Vimeo Field
Retrieve Vimeo video data via the API with an access token and store it in Sanity.
By Marco Land
Install command
npm i sanity-plugin-vimeo-fieldSanity Plugin Vimeo Field
Syncs your Vimeo video library into Sanity as first-class documents and provides a reference field with a visual picker.
Installation
npm install sanity-plugin-vimeo-field
# or
pnpm add sanity-plugin-vimeo-fieldRequires Sanity Studio v5 and React 18+.
Setup
1. Register the plugin
// sanity.config.ts
import {defineConfig} from 'sanity'
import {vimeoField} from 'sanity-plugin-vimeo-field'
export default defineConfig({
// ...
plugins: [vimeoField()],
})2. Add a Vimeo field to a document
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',
}),
],
})3. Vimeo access token
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.
How it works
Videos are stored as hidden vimeoVideo documents in your dataset. The vimeo type is an object that contains a reference to these documents.
Vimeo Library tool
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.
Vimeo field
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.
The vimeoVideo document
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.
Querying in the frontend
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
}
}
}TypeScript type
Import the VimeoVideo type for use in your frontend code:
import type {VimeoVideo} from 'sanity-plugin-vimeo-field'Migrating from v2.x.x–3.1.0
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.
vimeoFieldPlugin renamed to vimeoField
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()],
})vimeoField type renamed to vimeo
The field type name has been shortened. Update your schemas:
defineField({
- type: 'vimeoField',
+ type: 'vimeo',
name: 'trailer',
title: 'Trailer',
})vimeoFieldType renamed to vimeoSchemaType
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.
License
MIT © Marco Land
Develop & test
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.