Syncs your Vimeo video library into Sanity as first-class documents and provides a reference field with a visual picker.
npm install sanity-plugin-vimeo-field
# or
pnpm add sanity-plugin-vimeo-fieldRequires Sanity Studio v5 and React 18+.
// sanity.config.ts
import {defineConfig} from 'sanity'
import {vimeoField} from 'sanity-plugin-vimeo-field'
export default defineConfig({
// ...
plugins: [vimeoField()],
})Use the vimeo type in any document's fields array. All standard field options (hidden, readOnly, group, validation, etc.) work as expected.
// schemas/movie.ts
import {defineField, defineType} from 'sanity'
export default defineType({
name: 'movie',
title: 'Movie',
type: 'document',
fields: [
defineField({
type: 'vimeo',
name: 'trailer',
title: 'Trailer',
}),
// With standard field options
defineField({
type: 'vimeo',
name: 'behindTheScenes',
title: 'Behind the Scenes',
hidden: ({document}) => !document?.title,
readOnly: true,
group: 'media',
}),
],
})The first time you use the field, you will be prompted to enter your Vimeo API access token. The token is stored securely in the Sanity dataset using @sanity/studio-secrets.
To create a token, go to developer.vimeo.com/apps, select your app (or create one), and generate a personal access token with the following scopes:
- Public — access public videos
- Private — access private and unlisted videos
- Video Files — access direct video file links (progressive/HLS/DASH)
The Video Files scope requires a Vimeo Pro plan or above. Without it the
playfield will be empty.
Videos are stored as hidden vimeoVideo documents in your dataset. The vimeo type is an object that contains a reference to these documents.
The plugin adds a Vimeo Library tool to the Studio sidebar. It provides a searchable, browsable grid of all synced videos with inline video playback. From here you can:
- Search videos by name or Vimeo ID.
- Sync from Vimeo to fetch your full Vimeo library and upsert documents.
- Configure Access Token to update your Vimeo API credentials.
When using the vimeo type in a document:
- Select Video opens a picker dialog showing all synced videos.
- Sync from Vimeo (in the picker) fetches your full Vimeo library and upserts documents.
- Refresh (on the populated field) re-syncs just the selected video from the Vimeo API.
Each synced video is stored as a document with this shape:
| Field | Type | Description |
|---|---|---|
vimeoId |
string |
Numeric Vimeo video ID |
name |
string |
Video title |
duration |
number |
Duration in seconds |
width |
number |
Video width in pixels |
height |
number |
Video height in pixels |
privacy |
string |
Privacy setting — anybody, nobody, unlisted, etc. |
lastSynced |
datetime |
When this document was last synced |
pictures |
object |
Thumbnail sizes (array of {width, height, link}) |
files |
array |
Video file downloads — {quality, type, width, height, link, size} |
play |
object |
Playback links — progressive[], dash, hls |
Documents use the ID format vimeoVideo-{vimeoId} and have liveEdit: true (no draft/publish workflow).
Note: The
filesandplayfields require a Vimeo account with API access to direct video file links (Pro plan or above). On free/basic accounts these fields will be empty.
Important: The
playlinks (progressive/HLS/DASH) are short-lived and will expire after a few hours. They are not suitable for use in production frontends. Use thefilesfield instead — it contains persistent direct MP4 download URLs that do not expire.
The field stores a reference inside an object, so you need to dereference the nested asset field in your GROQ query:
*[_type == "movie"][0] {
title,
trailer {
asset-> {
vimeoId,
name,
duration,
width,
height,
privacy,
"thumbnail": pictures.sizes[0].link,
"mp4": files[quality == "hd"][0].link,
files
}
}
}
Import the VimeoVideo type for use in your frontend code:
import type {VimeoVideo} from 'sanity-plugin-vimeo-field'Note: In versions 2.x.x–3.1.0 the plugin was exported as
vimeoFieldPluginand the field type was namedvimeoField. Both have been renamed in the current version.
The plugin export has been renamed. Update your config:
- import {vimeoFieldPlugin} from 'sanity-plugin-vimeo-field'
+ import {vimeoField} from 'sanity-plugin-vimeo-field'
export default defineConfig({
- plugins: [vimeoFieldPlugin()],
+ plugins: [vimeoField()],
})The field type name has been shortened. Update your schemas:
defineField({
- type: 'vimeoField',
+ type: 'vimeo',
name: 'trailer',
title: 'Trailer',
})If you import the raw schema type definition, update the import:
- import {vimeoFieldType} from 'sanity-plugin-vimeo-field'
+ import {vimeoSchemaType} from 'sanity-plugin-vimeo-field'No data migration is needed — only code references change.
MIT © Marco Land
This plugin uses @sanity/plugin-kit with default configuration for build & watch scripts.
# Install dependencies
pnpm install
# Build the plugin
pnpm build
# Watch for changes during development
pnpm watch
# Link into a Sanity Studio for live development
pnpm link-watch
# Lint
pnpm lintSee Testing a plugin in Sanity Studio on how to run this plugin with hotreload in the studio.