livestream-player

Getting started

Install the package and render a live stream.

Install

pnpm add @grahamdigital/livestream-player react react-dom

react / 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

PropPurpose
srcLive HLS manifest URL (.m3u8). With ads set, this becomes the fail-open fallback.
adsDAI configuration ({ assetKey }). Omit for plain, ad-free playback.
prerollCSAI join pre-roll: { tagUrl, skipOffset? }. Fails open.
adConfigTargeting key-values, consent (GPP / US Privacy), and PPID — pass-through.
startModemuted-autoplay (default) or click-to-play (waits for a gesture, then plays with audio).
mutedInitial mute state for the first render (SSR/hydration agree); a persisted preference wins on the client. Default true.
autoPlayAttempt autoplay once the stream is ready. Default true.
onEventSubscribe to the normalized event contract.
onTelemetryMinimal error-telemetry sink (fatal errors, startup failures).
stickyDock as a sticky mini-player when scrolled out of view.
watermark / linkOverlayStation 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.

On this page