# CloudflareVideo

Video component that plays Cloudflare Stream videos through the Stream player

[Cloudflare Stream](https://developers.cloudflare.com/stream/) runs in an embedded player. Its own chrome stays hidden by default, so it drops into a [player skin](https://videojs.org/docs/framework/react/guides/skins) like any other media component; set `controls` to use Cloudflare’s UI instead.

## Import

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

```tsx
import { CloudflareVideo } from '@videojs/react/media/cloudflare-video';
```

## Load a source

`src` takes a raw 32-character video UID, any `cloudflarestream.com` or `videodelivery.net` URL, or a signed token. Watch, embed, iframe, manifest, and thumbnail URLs all carry the UID in the same position, and a signed token stands in for the UID wherever one appears.

```tsx
<CloudflareVideo src="https://watch.videodelivery.net/bfbd585059e33391d67b0f1d15fe6ea4" />
```

## Signed playback

For [signed URLs](https://developers.cloudflare.com/stream/viewing-videos/securing-your-stream/), pass the signed token wherever the UID would go: as the whole `src`, or inside a Stream URL. Keep your customer subdomain when your URLs name one. Cloudflare serves signed and access-controlled videos only from `customer-<code>.cloudflarestream.com`, so the element preserves that origin instead of collapsing it onto the shared host.

## Behavior

A few things work differently from a native `<video>` element, because the Stream embed doesn’t expose them:

- The embed owns text tracks: `textTracks` stays empty, and `engine.cloudflare.defaultTextTrack` picks the track to show.
- Picture-in-picture is unavailable, and the player reports it as unsupported.
- Fullscreen targets the iframe, so Cloudflare’s own chrome shows in fullscreen.
- `playsInline` has no effect: the Stream embed always plays inline.

## Examples

### Basic Usage

**App.tsx**

```tsx
import { CloudflareVideo } from '@videojs/react/media/cloudflare-video';

export default function BasicUsage() {
  return (
    <div className="cloudflare-video">
      <CloudflareVideo src="https://watch.videodelivery.net/bfbd585059e33391d67b0f1d15fe6ea4" controls />
    </div>
  );
}
```

**App.css**

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

## API Reference

### Props

Accepts these Video.js-specific props:

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `autoplay` | `boolean` | `false` | |
| `controls` | `boolean` | `false` | |
| `defaultMuted` | `boolean` | `false` | |
| `loop` | `boolean` | `false` | |
| `muted` | `boolean` | `false` | |
| `playsInline` | `boolean` | `true` | |
| `poster` | `string` | `''` | |
| `preload` | `MediaPreloadType` | `'metadata'` | |
| `source` | `{ src?: string; engine?: CloudflareSourceEngineConfig } \| null` | `null` | Structured source: `src` plus embed parameters under `engine.cloudflare`. Replacing it re-derives `src`. |
| `src` | `string` | `''` | |

### Engine options

#### `source.engine.cloudflare`

Pass [Stream player parameters](https://developers.cloudflare.com/stream/viewing-videos/using-the-stream-player/) under `source.engine.cloudflare`, spelled exactly as Cloudflare spells them, plus anything Cloudflare adds next. They’re serialized onto the embed URL untouched, and the embed reads them once, when its URL is built. [Media Sources](https://videojs.org/docs/framework/react/guides/media-sources) covers how engine options fit into a structured source.

`controls`, `autoplay`, `loop`, `muted`, `preload`, and `poster` come from the props of the same name, so they have no `engine.cloudflare` spelling.

```tsx
<CloudflareVideo
  source={{
    src: 'bfbd585059e33391d67b0f1d15fe6ea4',
    engine: { cloudflare: { primaryColor: '#f03e3e', startTime: '5m30s' } },
  }}
/>
```

| Option | Type | Description |
| --- | --- | --- |
| `ad-url` | `string \| undefined` | VAST tag to play as a pre-roll ad. Reported through the `stream-ad*` events. |
| `defaultTextTrack` | `string \| undefined` | BCP 47 language of the text track to show by default (`'en'`, `'de'`). |
| `letterboxColor` | `string \| undefined` | Any CSS color for the letterbox bars around a video that does not fill the player. |
| `primaryColor` | `string \| undefined` | Any CSS color for the progress bar and other player accents. |
| `referrerPolicy` | `ReferrerPolicy \| undefined` | `referrerpolicy` for the embed iframe. Not a Cloudflare player parameter. |
| `startTime` | `number \| string \| undefined` | Where playback starts, in seconds or as a time string (`'5m30s'`). |

### Ref

Forwards its ref to the rendered `<iframe>`. The ref is an [HTMLIFrameElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement). Control playback with the component props and player APIs rather than the iframe ref.

### 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
