Google Cast
Cast playback to Chromecast devices with the Google Cast component, and configure the receiver and load request
Add Google Cast to any Video.js streaming media element (HLS and DASH) by placing the Google Cast component next to it. Pair it with a CastButton and users can move playback to a Chromecast device while the browser stays in control:
import { CastButton, createPlayer } from '@videojs/react';
import { GoogleCast } from '@videojs/react/media/google-cast';
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
/>
<GoogleCast />
<CastButton />
</Player.Container>
</Player.Provider>
);
}<video-player>
<media-container>
<hlsjs-video
src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
autoplay
muted
playsinline
loop
></hlsjs-video>
<google-cast></google-cast>
<media-cast-button></media-cast-button>
</media-container>
</video-player>Register the <google-cast> element by importing @videojs/html/media/google-cast.
The component registers Google Cast with whichever media the player is using, so it works with any of the streaming media elements. 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 Google Cast component is added in a Chromium browser. Browsers that can’t cast — and players without the component — never load the SDK.
Set disableRemotePlayback on the media element to opt out of remote playback entirely:
<HlsJsVideo disableRemotePlayback /><hlsjs-video disableremoteplayback></hlsjs-video>Configure Cast
Pass Cast options as props of the GoogleCast component.
Set Cast options as attributes on the <google-cast> element. Object-valued options (like customData) are properties only.
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" />
<GoogleCast receiver="YOUR_APP_ID" /><hlsjs-video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"></hlsjs-video>
<google-cast receiver="YOUR_APP_ID"></google-cast>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" />
<GoogleCast customData={{ token: 'abc123', userId: 'u_789' }} />const googleCast = document.querySelector('google-cast');
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" />
<GoogleCast
src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
contentType="application/x-mpegURL"
/><hlsjs-video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4"></hlsjs-video>
<google-cast
src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"
content-type="application/x-mpegURL"
></google-cast>HLS on the receiver
When the Cast source 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" />
<GoogleCast streamType="live" /><hlsjs-video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8"></hlsjs-video>
<google-cast stream-type="live"></google-cast>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>;
}import { PlayerController, playerContext, selectRemotePlayback } from '@videojs/html';
class CastStatus extends HTMLElement {
readonly #remotePlayback = new PlayerController(this, playerContext, selectRemotePlayback);
}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 keeps this raw value in data-availability, but handles presentation for you:
- When Cast is unsupported, the HTML custom element receives the native
hiddenattribute and the React component returnsnull. - When Cast is supported but no device is reachable, the button remains visible with
aria-disabled="true"anddata-disabled.
Use data-disabled to style the visible, non-interactive state:
media-cast-button[data-disabled] {
cursor: not-allowed;
opacity: 0.5;
}CastButton renders a <button> element. Give it a className to target:
<CastButton className="cast-button" />.cast-button[data-disabled] {
cursor: not-allowed;
opacity: 0.5;
}Unsupported buttons hide automatically, so no availability selector or extra hiding CSS is required.