sanity-plugin-shopify-videos
v3.0.0
Published
A Sanity Studio video input that uploads videos to Shopify and stores Shopify video metadata.
Maintainers
Readme
sanity-plugin-shopify-videos
A Sanity Studio video input that uploads video files to Shopify, creates or updates a Shopify video metaobject, and stores a lightweight Shopify video asset document in Sanity for previews and reuse.
Shopify setup
Create the metaobject definition before using the plugin. For a merchant-owned video metaobject, use a file reference field named reference.
# shopify.app.toml
[metaobjects.video]
name = "Video"
display_name_field = "reference"
access.storefront = "public_read"
[metaobjects.video.fields.reference]
name = "Video"
type = "file_reference"
required = trueThe server token needs these Admin API scopes:
write_files
read_files
write_metaobjects
read_metaobjectsSanity Studio
import {defineConfig} from 'sanity'
import {shopifyVideoInput} from 'sanity-plugin-shopify-videos'
export default defineConfig({
// ...
plugins: [
shopifyVideoInput({
apiEndpoint: '/api/shopify-video',
acceptedMimeTypes: ['video/*'],
}),
],
})Use the field type in schemas:
{
name: 'video',
title: 'Video',
type: 'shopify.video',
}Server handler
Shopify Admin credentials must stay server-side. Export an endpoint from your host runtime and pass environment variables into the agnostic handler.
For Dev Dashboard apps, pass the Client ID and Client secret. The handler exchanges them for an Admin API access token and refreshes the token in memory before it expires.
import {createShopifyVideoHandler} from 'sanity-plugin-shopify-videos/server'
const handler = createShopifyVideoHandler({
shopDomain: process.env.SHOPIFY_SHOP_DOMAIN!,
clientId: process.env.SHOPIFY_CLIENT_ID!,
clientSecret: process.env.SHOPIFY_CLIENT_SECRET!,
apiVersion: process.env.SHOPIFY_API_VERSION || '2026-04',
metaobjectType: process.env.SHOPIFY_VIDEO_METAOBJECT_TYPE || 'video',
metaobjectVideoFieldKey: process.env.SHOPIFY_VIDEO_METAOBJECT_FIELD_KEY || 'reference',
})Next.js app route:
export async function POST(request: Request) {
return handler(request)
}Cloudflare Worker:
export default {
fetch(request: Request, env: Env) {
return createShopifyVideoHandler({
shopDomain: env.SHOPIFY_SHOP_DOMAIN,
clientId: env.SHOPIFY_CLIENT_ID,
clientSecret: env.SHOPIFY_CLIENT_SECRET,
apiVersion: env.SHOPIFY_API_VERSION || '2026-04',
metaobjectType: env.SHOPIFY_VIDEO_METAOBJECT_TYPE || 'video',
metaobjectVideoFieldKey: env.SHOPIFY_VIDEO_METAOBJECT_FIELD_KEY || 'reference',
})(request)
},
}For quick local tests, you can also pass a short-lived token directly:
createShopifyVideoHandler({
shopDomain: process.env.SHOPIFY_SHOP_DOMAIN!,
adminAccessToken: process.env.SHOPIFY_ADMIN_ACCESS_TOKEN!,
metaobjectVideoFieldKey: process.env.SHOPIFY_VIDEO_METAOBJECT_FIELD_KEY || 'reference',
})API
The Studio plugin sends a single POST action API to apiEndpoint:
stagedUpload: creates a Shopify staged upload target for a video file.completeUpload: creates the Shopify video file, waits briefly for video metadata, upserts thevideometaobject, and returns normalized asset data.syncAsset: reloads cached Sanity metadata from the Shopify video file.
Shopify remains the source of truth for the video file and metaobject. Sanity stores shopify.videoAsset documents for Studio previews, search, and field references.
Real app testing
See docs/nextjs-real-app-setup.md for installing the packed tarball, configuring Shopify custom data, and adding a Next.js App Router API route.
