# MuxVideo

Video element for Mux-hosted HLS streams

Video element for playing Mux-hosted HLS streams. Built on hls.js with Mux-specific optimizations.

## Import

```bash
pnpm add @videojs/mux-video
```

```tsx
import { MuxVideo } from '@videojs/react/media/mux-video';
```

## Load a source

The `source` param builds the URL for you from a playback ID, an optional custom domain, and `playback` params. Playback params are just camelCased [Mux playback query params](https://www.mux.com/docs/api-reference/stream/streaming/get-hls-manifest); for example, `max_resolution` becomes `maxResolution`.

```tsx
<MuxVideo
  source={{ 
    playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM',
    customDomain: 'media.example.com',
    playback: { maxResolution: '1080p' }
  }} 
/>
```

If for some reason you need a bit more control, you can use the `src` param with a plain ’ol URL, too:

```tsx
<MuxVideo
  src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
/>
```

MuxVideo ignores the same source object when it is assigned again. A new object fires `sourcechange` even when its values are equal, although an equivalent playback source does not reload.

## Posters and storyboards

The Mux video component derives a poster image and a storyboard from the playback ID. `source.poster` and `source.storyboard` configure the generated URLs.

When the Mux video component is inside a player, it supplies the poster for the skin to display. Set `poster` on the player when you want to use your own image instead.

A generated poster becomes available after MuxVideo mounts. Pass `poster` to the player when the image must appear in server-rendered HTML.

The Mux video component injects the derived storyboard `<track>` automatically and removes it when the media detects a live stream. Configure the derived URLs through the source object:

```tsx
<MuxVideo
  source={{
    playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM',
    poster: { time: 2, width: 1280 },
    storyboard: { format: 'webp' },
  }}
/>
```

The storyboard lives on a Mux domain, so the Mux video component has to be CORS-enabled for that cross-origin `<track>` to load at all. The [thumbnail component](https://videojs.org/docs/framework/react/reference/components/thumbnail) then fetches the sprite sheets its cues point at the same way:

```tsx
<MuxVideo
  source={{ playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM' }}
  crossOrigin="anonymous"
/>
```

## Signed playback

For [signed playback](https://www.mux.com/docs/guides/secure-video-playback), put the playback token on `source.playback.token`. The token replaces every other playback param, so bake modifiers like resolution and time bounds into the token when you sign it.

Signed playback needs a separate token for each image URL. Put the thumbnail token (`aud: 't'`) at `source.poster.token` and the storyboard token (`aud: 's'`) at `source.storyboard.token`. If either token is missing or has the wrong audience, the Mux video component does not generate the corresponding URL.

```tsx
<MuxVideo
  source={{
    playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM',
    playback: { token: playbackToken },
    poster: { token: posterToken },
    storyboard: { token: storyboardToken },
  }}
/>
```

## Analytics and casting

The Mux video component plays Mux streams. It doesn’t monitor them or cast them — [Mux Data](https://videojs.org/docs/framework/react/guides/mux-data) and [Google Cast](https://videojs.org/docs/framework/react/guides/casting) are separate extensions you add to the player alongside it. Mux Data needs no environment key here, since Mux attributes the views to the environment that owns the playback ID:

Install both extensions before using the example below:

```bash
pnpm add @videojs/mux-data @videojs/google-cast
```

```tsx
import { createPlayer } from '@videojs/react';
import { GoogleCast } from '@videojs/react/extensions/google-cast';
import { MuxData } from '@videojs/react/extensions/mux-data';
import { MuxVideo } from '@videojs/react/media/mux-video';
import { videoFeatures } from '@videojs/react/video';

const { Player } = createPlayer({ features: videoFeatures });

export function MuxPlayer() {
  return (
    <Player>
      <MuxVideo source={{ playbackId: 'BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM' }} playsInline />
      <MuxData playerSoftwareName="mux-video" />
      <GoogleCast />
    </Player>
  );
}
```

- [Mux Data](https://videojs.org/docs/framework/react/guides/mux-data): Metadata, options, and configuration
- [Cast to AirPlay and Chromecast](https://videojs.org/docs/framework/react/guides/casting): Receivers, load requests, and session state

## Examples

### Basic Usage

**App.tsx**

```tsx
import { MuxVideo } from '@videojs/react/media/mux-video';

export default function BasicUsage() {
  return (
    <MuxVideo
      className="mux-video"
      src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
      autoPlay
      muted
      playsInline
      loop
      crossOrigin="anonymous"
    />
  );
}
```

**App.css**

```css
.mux-video {
  width: 100%;
  aspect-ratio: 16 / 9;
}
```

## API Reference

### Props

Accepts the standard React props for a native `<video>`, plus these Video.js-specific props:

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disableRemotePlayback` | `unknown` | `false` | Whether remote playback (AirPlay, Google Cast) is disabled for this media. |
| `preload` | `MediaPreloadType` | `'metadata'` | Preload type (`'none'` / `'metadata'` / `'auto'`). |
| `source` | `{ type?: 'application/vnd.apple.mpegurl' \| 'video/mp4'; preferPlayback?: 'mse' \| 'native'; maxAutoResolution?: '270p' \| '360p' \| '480p' \| '540p' \| '720p' \| '1080p' \| '1440p' \| '2160p'; capRenditionToPlayerSize?: boolean; minAutoResolution?: '270p' \| '360p' \| '480p' \| '540p' \| '720p' \| '1080p' \| '1440p' \| '2160p'; engine?: HlsEngineConfig; src?: string; playbackId?: string; customDomain?: string; playback?: MuxPlaybackParams; poster?: MuxPosterParams; storyboard?: MuxStoryboardParams; drm?: MuxDrmParams } \| null` | `null` | Structured Mux source. Setting it derives `src` from the playback ID, custom domain, and `playback` params (appended as `snake_case` query params). A `playback.token` replaces all other params — signed URLs bake them into the token. Engine options live under `engine`. A `drm.token` fills in `drm` itself: Mux's FairPlay, Widevine, and PlayReady license servers for this playback ID, so protected media plays whichever path the browser takes. License servers named alongside the token win, key by key, for content Mux does not license. `playback.maxResolution` and `playback.minResolution` are server-side: they decide which renditions Mux puts in the manifest at all. The inherited `maxAutoResolution` and `minAutoResolution` only look like their pair — those are client-side and bound which of the renditions that *do* arrive adaptive selection reaches for. The two halves are independent. |
| `src` | `string` | `''` | Media source URL. Setting a Mux stream URL (`https://stream.mux.com/<playback-id>.m3u8?...`) extracts the playback ID and query params into `source`; other URLs are kept as a plain `source.src`. Only playback options carry over. Mux identity comes from the URL, and the signed `poster`, `storyboard`, and `drm` tokens are scoped to a playback ID, so carrying them onto a different source would build rejected URLs. |
| `streamType` | `'on-demand' \| 'live' \| 'unknown'` | `'unknown'` | Current stream type (`'on-demand'` / `'live'` / `'unknown'`). |

### Engine options

#### `source.engine.nativeHls`

Options passed under `source.engine.nativeHls`.

| Option | Type | Description |
| --- | --- | --- |
| `drmSystems` | `Partial<Record<KeySystem, DrmSystemConfig>> \| undefined` | License servers for protected content, keyed by EME key system id. An escape hatch for licensing native playback differently from every other path: naming it replaces `source.drm` here, and nowhere else. |

### Ref

Forwards its ref to the rendered `<video>`. The ref is an [HTMLVideoElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement) and exposes its complete native property and method API.

### Events

Handle standard media events with React event props such as `onPlay` and `onTimeUpdate`. For native events without a React prop, attach a listener through the ref with `addEventListener`.

---

React documentation: https://videojs.org/docs/framework/react/llms.txt
All documentation: https://videojs.org/llms.txt
