Skip to content

Player — React

Terminal window
npm install @livepeer-frameworks/player-react
import "@livepeer-frameworks/player-react/player.css";
import { Player } from "@livepeer-frameworks/player-react";
import "@livepeer-frameworks/player-react/player.css";
function LiveStream() {
return (
<Player
contentType="live"
contentId="<YOUR_PLAYBACK_ID>"
options={{
autoplay: true,
muted: true,
}}
/>
);
}

The player resolves through the official FrameWorks Gateway from the viewer’s browser, so Foghorn routes from that viewer’s IP. Set gatewayUrl only for a fully self-hosted control plane or local Gateway preview. For backend-generated playback URLs or custom players that do not use this component, use the dashboard playback DNS URL directly.

<Player
contentType="live"
contentId="<YOUR_PLAYBACK_ID>"
options={{ mistUrl: "https://edge-egress.eu.example.com" }}
/>
<Player contentType="dvr" contentId="pk_..." />
<Player contentType="clip" contentId="pk_..." />

Pass children to <Player> to replace the built-in controls with your own layout. Sub-components auto-connect to the parent via React context.

import {
Player,
PlayButton,
SkipButton,
VolumeControl,
TimeDisplay,
LiveBadge,
FullscreenButton,
ControlBar,
SettingsMenu,
} from "@livepeer-frameworks/player-react";
function CustomPlayer() {
return (
<Player contentId="pk_..." contentType="live">
<ControlBar>
<PlayButton />
<SkipButton direction="back" />
<SkipButton direction="forward" />
<TimeDisplay />
<LiveBadge />
<VolumeControl />
<SettingsMenu />
<FullscreenButton />
</ControlBar>
</Player>
);
}
ComponentPurpose
PlayButtonPlay/pause toggle
SkipButtonSkip forward/back (pass direction="back" or "forward")
VolumeControlVolume slider with mute toggle
TimeDisplayCurrent time / duration display
LiveBadgeLive indicator with jump-to-live
FullscreenButtonFullscreen toggle
SettingsMenuQuality, speed, and track selection
ControlBarHorizontal flex container for controls

All sub-components read state from the nearest <Player> parent via usePlayerContextOptional(). They render nothing if used outside a <Player>.

For complete UI control, use usePlayerController directly:

import { usePlayerController } from "@livepeer-frameworks/player-react";
function FullyCustomPlayer() {
const { containerRef, state, controller } = usePlayerController({
contentId: "pk_...",
contentType: "live",
autoplay: true,
muted: true,
});
return (
<div>
<div ref={containerRef} style={{ width: "100%", aspectRatio: "16/9" }} />
<p>State: {state.state}</p>
<p>
{state.isPlaying ? "Playing" : "Paused"} | Volume: {state.volume}
</p>
<button onClick={() => controller?.togglePlay()}>{state.isPlaying ? "Pause" : "Play"}</button>
<button onClick={() => controller?.toggleMute()}>{state.isMuted ? "Unmute" : "Mute"}</button>
</div>
);
}
PropertyTypeDescription
statePlayerControllerStateReactive state object (isPlaying, volume, currentTime, etc.)
controllerPlayerController | nullController instance for direct method calls
containerRefRefObject<HTMLElement>Attach to the container div
setDevModeOptionsfunctionRuntime player/source/protocol override helper
PropertyTypeDescription
state.statePlayerStateCurrent lifecycle state
state.isPlayingbooleanWhether playing
state.isPausedbooleanWhether paused
state.isMutedbooleanWhether muted
state.volumenumberVolume (0-1)
state.currentTimenumberCurrent position in milliseconds
state.durationnumberDuration in milliseconds (Infinity for live)
state.isBufferingbooleanWhether buffering
state.isFullscreenbooleanWhether in fullscreen
state.isEffectivelyLivebooleanWhether live content
state.errorstring | nullCurrent error message
PropTypeDescription
contentIdstringPlayback ID (live/clip/DVR/VOD)
contentType'live' | 'dvr' | 'clip' | 'vod'Content type (affects presets and UI)
endpointsContentEndpointsAdvanced: pass pre-resolved endpoints
thumbnailUrlstringPoster image (pre-playback overlay). Seek-bar sprites are auto-detected.
options.gatewayUrlstringGateway GraphQL endpoint override
options.mistUrlstringDirect MistServer base URL
options.authTokenstringBearer token for Gateway GraphQL resolution
options.playbackAuth{ token: string; transport?: "query" | "header" }Viewer JWT sent as ?jwt= by default, or Authorization: Bearer on player-controlled transports
options.autoplaybooleanAuto-start playback
options.mutedbooleanStart muted (required for autoplay)
options.stockControlsbooleanUse browser-native video controls
options.animatePrerollbooleanCycle thumbnail sprite tiles as a preroll animation before playback. Default false (static poster)
options.themestringTheme preset name
options.themeOverridesobjectPer-token theme overrides
options.localestringBuilt-in UI locale
options.playbackModestringInitial controls/dev-panel mode label; use setDevModeOptions for runtime protocol preference
options.debugbooleanDebug logging
onStateChangefunctionState transition callback
<Player
contentId="pk_..."
contentType="live"
onStateChange={(state, context) => {
// States: booting, gateway_loading, gateway_ready, gateway_error,
// no_endpoint, selecting_player, connecting, buffering,
// playing, paused, ended, error, destroyed
console.log("State:", state);
}}
/>

playbackMode controls protocol preference order:

ModePreferenceUse Case
low-latencyWebCodecs/WS → WHEP/WebRTC → MP4/WS → HLSReal-time interaction
qualityMP4/WS and WebCodecs/WS → HLS/MP4 → WebRTCStable, high quality
vodMP4/HLS/DASH → MP4/WS → WHEP/WebRTCPre-recorded content
autoBalanced score-basedDefault

LL-HLS and DASH are served from MistServer’s CMAF output (/play/{id}/cmaf/index.m3u8 and /play/{id}/cmaf/index.mpd) on every helmsman-managed edge.

<Player contentId="pk_..." contentType="live" options={{ playbackMode: "low-latency" }} />
const { setDevModeOptions } = usePlayerController({
contentId: "pk_...",
contentType: "live",
});
void setDevModeOptions({ forceType: "whep" });