Payload Plugins
Pluginspayload-mux

Using video

Relate to a video from any collection and stream it with adaptive HLS — playback URLs are ready on read, no extra calls.

For AI / LLMs: View Markdown

Relate to mux-video from any collection, then play the video back however you like. Every video exposes a playbackId and a virtual playbackUrl (an HLS .m3u8), which work with any Mux frontend or a custom HLS player.

The URLs compute on read from the stored playback id. Already-populated videos need no extra calls to play.

Relate and play

The example below uses @mux/mux-player-react. Install it first:

pnpm add @mux/mux-player-react

Then fetch the video and hand its playback fields to the player:

import config from '@payload-config'
import MuxPlayer from '@mux/mux-player-react'
import { getPayload } from 'payload'

async function Page() {
  const payload = await getPayload({ config })
  const video = await payload.findByID({ collection: 'mux-video', id: 'example' })

  const playback = video.playbackOptions?.[0]
  if (!playback) return null // still preparing — no playback ids yet

  return (
    <MuxPlayer
      playbackId={playback.playbackId} // by playback id
      src={playback.playbackUrl}        // …or the HLS URL
      poster={playback.posterUrl}
    />
  )
}

export default Page

playbackOptions is empty until the asset reaches ready. Read it with video.playbackOptions?.[0] and guard with an early return, as above. A non-null assertion (video.playbackOptions![0]) crashes on a video that is still preparing.

playbackOptions

playbackOptions is an array with one row per playback id. Most videos have a single row, so you read playbackOptions?.[0]. Each row carries:

Prop

Type

The three URL fields aren't stored — they compute from the playback id on every read. Under a signed policy each one arrives JWT-signed with the signedUrlOptions lifetime.

Signed playback

Under a signed policy each read signs all three URLs (playbackUrl / posterUrl / gifUrl), and JWT signing isn't free.

If you only render one URL (e.g. just the player), select it — alongside the playbackId / playbackPolicy it's built from — so the other two aren't signed:

payload.find({
  collection: 'mux-video',
  select: { playbackOptions: { playbackId: true, playbackPolicy: true, playbackUrl: true } },
})

Public playback does no signing, so this doesn't apply there.

Turn signed playback on with the plugin's options.playbackPolicy: 'signed' — see Quickstart and Plugin options.

Next

On this page