Skip to content
FrameworkStyle

Google Cast

Cast playback to Chromecast devices with built-in Google Cast support, and configure the receiver and load request

Video.js streaming media elements (HLS and DASH) have Google Cast built in. Add a CastButton and users can move playback to a Chromecast device while the browser stays in control:

import { CastButton, createPlayer } from '@videojs/react';
import { HlsJsVideo } from '@videojs/react/media/hlsjs-video';
import { videoFeatures } from '@videojs/react/video';

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

export default function App() {
  return (
    <Player.Provider>
      <Player.Container>
        <HlsJsVideo
          src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
          autoPlay
          muted
          playsInline
          loop
        />
        <CastButton />
      </Player.Container>
    </Player.Provider>
  );
}

The pre-built skins include a Cast button already. It appears when a Chromecast device is on the network and stays hidden otherwise.

How Cast works

Cast uses a sender / receiver model:

  • Sender — the browser tab. It sends the receiver a load request with the source URL and metadata, then issues playback commands (play, pause, seek, volume).
  • Receiver — the Chromecast device running a receiver application: Google’s default media receiver, or a custom one you configure.

Session lifecycle

A Cast session moves through three states, exposed by the Remote Playback feature:

State Meaning
'disconnected' No active session
'connecting' Device picked; session starting
'connected' Session active; receiver has the media

While connected, the media element’s play, pause, currentTime, volume, muted, and playbackRate all proxy to the Cast receiver. Local playback is suspended.

The lazy-loaded SDK

Video.js injects the Cast SDK (cast_sender.js) as a <script> tag the first time a Cast-capable media element loads in a Chromium browser. Browsers that can’t cast never load the SDK.

Set disableRemotePlayback on the media element to opt out:

<HlsJsVideo disableRemotePlayback />

Configure Cast

Pass Cast options under the googleCast key of the media element’s config prop.

Custom receiver application ID

By default, Video.js casts to Google’s Default Media Receiver (CC1AD845). To use your own receiver app, set receiver:

<HlsJsVideo
  src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
  config={{ googleCast: { receiver: 'YOUR_APP_ID' } }}
/>

Custom data on load

Send extra data (auth tokens, user IDs) to the receiver with each load request via customData. The receiver app reads it from the load request’s customData field:

<HlsJsVideo
  src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
  config={{ googleCast: { customData: { token: 'abc123', userId: 'u_789' } } }}
/>

Cast a different source

By default the receiver loads the same URL the browser plays. Set src (and optionally contentType) to send the receiver a different one — for example, cast an HLS stream while the browser plays an MP4:

<HlsJsVideo
  src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4"
  config={{
    googleCast: {
      src: 'https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8',
      contentType: 'application/x-mpegURL',
    },
  }}
/>

HLS on the receiver

When the source (or config.googleCast.src) is an HLS playlist, Video.js inspects the playlist, detects the segment format (TS or fMP4), and sets hlsSegmentFormat / hlsVideoSegmentFormat on the Cast load request. The default media receiver plays HLS natively; no extra configuration needed.

Set streamType to tell the receiver whether the stream is 'on-demand' or 'live'. When unset, it falls back to the player’s streamType:

<HlsJsVideo
  src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
  config={{ googleCast: { streamType: 'live' } }}
/>

Read Cast state

Cast session state lives in the Remote Playback feature slice. Subscribe with selectRemotePlayback:

import { selectRemotePlayback, usePlayer } from '@videojs/react';

function CastStatus() {
  const remotePlayback = usePlayer(selectRemotePlayback);
  if (!remotePlayback) return null;

  return <span>{remotePlayback.remotePlaybackState}</span>;
}

Browser availability

The Remote Playback feature reports availability as 'available' (a device is on the network), 'unavailable' (no device found), or 'unsupported' (the browser can’t cast). The CastButton reflects it as a data-availability attribute. Use it to hide the button where casting never works:

CastButton renders a <button> element. Give it a className to target:

<CastButton className="cast-button" />
.cast-button[data-availability="unsupported"] {
  display: none;
}

See also