Media Library

Working with video

Learn how to handle video content in Sanity's Media Library.

Media Library's video streaming capabilities let you present high-quality, adaptive video content directly from your centralized asset storage. Videos uploaded to your Media Library are automatically processed and optimized for streaming through Mux, providing reliable video delivery with adaptive quality and global CDN distribution. You can also download the original file you uploaded and static renditions of it from the Media Library interface, separate from the playback stream.

This guide explains how to effectively present videos from your Media Library in your front-end applications. For information about uploading videos or configuring Media Library, see the Media Library documentation.

Prerequisites

This is a paid feature

This feature is available on certain Enterprise plans. Talk to sales to learn more.

  • A Sanity project with Media Library enabled and Studio v4.0.1 or later.
  • Video addon enabled for your project. Video is an addon feature of Media Library and is not enabled by default. Contact sales to learn more.
  • Video assets uploaded to your Media Library.

Understanding video representation in Media Library

Before implementing videos in your front-end, it's important to understand how Media Library handles videos:

  • Video fields are created using the defineVideoField helper from sanity/media-library
  • Videos are processed to generate playback IDs for streaming
  • Each video asset contains metadata, including aspect ratio, duration, and framerate

Note: Both public and private videos are supported. Private videos play through short-lived signed URLs rather than a public URL.

Supported formats and limitations

Media Library accepts most common video formats for upload.

Supported formats:

  • MP4 (recommended)
  • MOV
  • AVI
  • MKV
  • WebM
  • And most other standard video formats

Considerations:

  • Processing time varies based on video length and resolution.
  • Higher resolution videos (4K+) may take longer to process.

For best performance and compatibility, we recommend uploading videos in MP4 format with H.264 encoding. To minimize processing time, follow Mux's standard input specifications.

Video asset structure

Video assets in your Media Library have a nested structure:

{
  "_id": "2yg9Un9RMsQjuf3WDqEo70ggi8D",
  "_type": "sanity.asset",
  "assetType": "sanity.videoAsset",
  "title": "video-filename.mp4",
  "versions": [
    {
      "instance": {
        "_id": "2yg9UGEpG8H4xjgMj8YSstwpfVh",
        "_type": "sanity.videoAsset",
        "originalFilename": "video-filename.mp4",
        "metadata": {
          "_type": "sanity.videoMetadata",
          "aspectRatio": 0.5625,
          "duration": 8.86,
          "playbacks": [
            {
              "_id": "V5uFaHghtnzgV6lYlBkrbehGkvd5KNGHYU7w2Eo7HoQ", // Mux playback ID
              "_type": "sanity.videoMetadata.playback",
              "policy": "public" // Only public videos are currently supported
            }
          ]
        },
        "mimeType": "video/mp4",
        "originalFilename": "video-filename.mp4"
      }
    }
  ]
}

Setting up video fields in Studio

Use the defineVideoField helper to create video fields in your studio schemas:

Get the video data

There are two methods to fetch video data from your Media Library: using the Sanity client (recommended) or using GROQ queries.

Using the Sanity client (recommended)

The Sanity client provides a getPlaybackInfo() method that retrieves all necessary video information in a single call. This method requires API version v2025-03-25 or later.

First, configure your client to use Media Library:

import {createClient} from '@sanity/client'

const client = createClient({
  apiVersion: '2025-03-25',
  useCdn: false,
  token: 'your-token',
  '~experimental_resource': {
    type: 'media-library',
    id: 'your-media-library-id',
  },
})

Query for the document with your video field:

{
  "title": "My Video Document",
  "video": {
    "_type": "sanity.video",
    "asset": {
      "_ref": "media-library:mlZxz9rvqf76:video-30rh9U3GDEK3ToiId1Zje4uvalC-mp4",
      "_type": "reference"
    }
  }
}

Fetch playback information using the video asset reference:

const document = await client.fetch(
  `*[_type == 'videoDocument']{ title, video }`
)

const playbackInfo = await client.mediaLibrary.video.getPlaybackInfo(
  document.video.asset
)

The response contains URLs for stream and images like the thumbnail, as well as useful metadata like duration and aspect ratio.

{
  id: "30rh9U3GDEK3ToiId1Zje4uvalC", // Playback ID
  stream: { url: "https://stream.m.sanity-cdn.com/..." },
  thumbnail: { url: "https://image.m.sanity-cdn.com/..." },
  animated: { url: "https://image.m.sanity-cdn.com/..." },
  storyboard: { url: "https://image.m.sanity-cdn.com/..." },
  duration: 120.5,
  aspectRatio: 1.77
}

Alternative: Using GROQ queries

You can also fetch video data using GROQ queries. Use the documents::get() function to follow the Global Dataset Reference and access the video asset:

For more comprehensive video information, you can query additional metadata:

Display videos with Mux Player

To present videos from Media Library in your frontend, we'll use the Mux video player.

Install the Mux React player component:

Basic implementation

Here's the simplest way to display a video from your Media Library:

Using with queried data

Integrate with your GROQ query results:

Displaying thumbnails

Thumbnail images are automatically generated for your videos. You can use these as poster images:


You can also customize the poster image size and format:

Understanding streaming and thumbnail URLs

Media Library provides video streaming and thumbnail generation through Mux. Understanding the URL structure helps you optimize video delivery:

Streaming URLs

Videos are delivered via HLS (HTTP Live Streaming) using this URL pattern:

https://stream.m.sanity-cdn.com/{playbackId}.m3u8

The Mux Player handles this automatically, but you can access the raw streaming URL if needed:

Thumbnail URLs

Thumbnails are automatically generated using this URL pattern:

https://image.m.sanity-cdn.com/{playbackId}/thumbnail.{format}

You can customize thumbnails with query parameters, similar to Sanity's image pipeline:

Available thumbnail parameters:

  • width and height - Resize the thumbnail
  • fit_mode - How to fit within dimensions (crop, preserve, stretch, pad)
  • time - Extract thumbnail from specific video timestamp (in seconds)
  • Format options: .jpg, .png, .webp

For the complete list of thumbnail transformation options, see the Mux thumbnail documentation.

Downloading video files

From an asset's actions in the Media Library interface you can download the original file you uploaded and static renditions generated from it. The original is the exact source file; renditions are transcoded versions of the video.

Advanced player configuration

Configure additional player features:

Customizing player appearance

For styling and theming options, see the Mux Player customization guide. The player supports:

  • Custom accent colors
  • CSS custom properties for extensive styling
  • Multiple built-in themes
  • Custom CSS for complete control over appearance

Background video

For looping, muted, autoplay videos use the dedicated @mux/mux-background-video React component rather than Mux Player. It is lightweight, uses HLS adaptive streaming, and is optimized for this use case.

Background video vs. Mux Player

Choose the right component based on how the video is used:

  • Background video: short, looping, muted clips that autoplay silently. No playback controls. Use MuxBackgroundVideo.
  • Interactive video: product demos, explainers, or any video the user actively watches with play/pause/seek controls. Use MuxPlayer.

Installation

Basic implementation

Pass the playback ID from your Media Library asset to the component. Include an <img> element as a poster — it displays while the video loads and is important for LCP performance.

Controlling resolution

Use the maxResolution prop to cap the quality served. This reduces bandwidth usage when the video is displayed at a smaller size — for example, a full-bleed hero rarely needs more than 1080p.

Available values: 270p, 360p, 480p, 540p, 720p, 1080p, 1440p, 2160p.

Pause when the tab is hidden

Background videos continue playing when users switch tabs, consuming CPU and battery. Pause playback when the page is hidden using the Page Visibility API:

Performance considerations

To maximize performance when displaying videos:

Preload settings

Use appropriate preload settings based on your use case:

  • preload="none" - Don't preload anything. Best for pages with many videos.
  • preload="metadata" - Preload video metadata only. Default setting.
  • preload="auto" - Preload the entire video. Use sparingly, and avoid when loading multiple videos.

Loading strategies

Lazy load videos below the fold as users scroll to reduce initial page load time.

Resolution control

Set maxResolution on the player to cap the maximum video quality and reduce bandwidth usage. Available options are "720p", "1080p", "1440p", and "2160p".

Image optimization

Use appropriately sized thumbnails instead of full-resolution images by utilizing the transformation options.

User interaction

Consider implementing click-to-play for videos that aren't essential to the user experience to save bandwidth.

Poster images and LCP

For above-the-fold videos, always provide a poster image. The <img> element inside MuxBackgroundVideo (or the poster prop on MuxPlayer) is treated as a Largest Contentful Paint candidate. Use an appropriately sized .webp thumbnail from the Mux image CDN to keep LCP fast.

min-resolution

Use minResolution alongside maxResolution to define a quality range. This is useful when your video contains text or fine detail that must remain legible — for example, a screen recording or product demo where 480p would be unacceptable.

Common issues

Video not loading

  • Check that the playback ID exists in your query: video.asset->metadata.playbacks[policy == "public"][0]._id
  • Ensure your Media Library integration is properly configured
  • Verify the GROQ query is returning the expected data structure

Player not displaying

  • Confirm @mux/mux-player-react is properly installed
  • Check browser console for JavaScript errors
  • Verify the container element has appropriate dimensions

Aspect ratio issues

  • Ensure you're using the correct aspect ratio from video.asset->metadata.aspectRatio
  • Note that aspect ratio is width/height (e.g., 0.5625 for 9:16 vertical video)
  • Set proper container styles to maintain aspect ratio

Additional resources

Mux Player documentation

Complete guide to Mux Player features and customization options.

Media Library documentation

Learn more about configuring and using Media Library.

Creating custom aspects

Add custom metadata fields to your video assets.

Was this page helpful?