Getting started
Install the package and render a live stream.
Install
pnpm add @grahamdigital/livestream-player react react-domreact / react-dom (v19) are peer dependencies. shaka-player is a regular dependency
and is loaded lazily (dynamic import) the first time a player starts, so it never runs
during SSR.
Render a live stream
import { LivePlayer, type PlayerEvent } from "@grahamdigital/livestream-player";
function Watch() {
return (
<LivePlayer
src="https://example.com/live/master.m3u8"
muted // required for unattended autoplay
autoPlay
onEvent={(event: PlayerEvent) => {
// Bind analytics / page coordination to the normalized contract here.
if (event.type === "ready") console.log("live?", event.isLive);
}}
style={{ width: "100%", aspectRatio: "16 / 9" }}
/>
);
}adConfig, preroll, startMode, autoPlay, and the factory props
(engineFactory, adsFactory, prerollFactory) are captured when a playback
session starts. To apply a change to any of them, remount the player with a new
key (as the demo does).
Key props
| Prop | Purpose |
|---|---|
src | Live HLS manifest URL (.m3u8). With ads set, this becomes the fail-open fallback. |
ads | DAI configuration ({ assetKey }). Omit for plain, ad-free playback. |
preroll | CSAI join pre-roll: { tagUrl, skipOffset? }. Fails open. |
adConfig | Targeting key-values, consent (GPP / US Privacy), and PPID — pass-through. |
startMode | muted-autoplay (default) or click-to-play (waits for a gesture, then plays with audio). |
muted | Initial mute state for the first render (SSR/hydration agree); a persisted preference wins on the client. Default true. |
autoPlay | Attempt autoplay once the stream is ready. Default true. |
onEvent | Subscribe to the normalized event contract. |
onTelemetry | Minimal error-telemetry sink (fatal errors, startup failures). |
sticky | Dock as a sticky mini-player when scrolled out of view. |
watermark / linkOverlay | Station watermark and clickable link overlays, per-corner placement. |
The imperative handle
import { useRef } from "react";
import {
LivePlayer,
type LivePlayerHandle,
} from "@grahamdigital/livestream-player";
function Watch({ src }: { src: string }) {
const ref = useRef<LivePlayerHandle>(null);
// ref.current?.play() / .pause() / .mute(false) / .setVolume(0.5)
// ref.current?.seekToLive() / .skipAd() / .getEngine()
return <LivePlayer ref={ref} src={src} />;
}getEngine() is an escape hatch returning the underlying engine instance (a Shaka
Player by default) — it is not part of the stable contract.
Built-in UI
The player renders its own control bar: play/pause, mute + volume, a go to live edge control, a CC button (appears automatically once the stream exposes text tracks), and fullscreen. All UI state is driven by the normalized event contract, never by reading the engine directly.