Skip to content

Player — Web Components

NPM:

Terminal window
npm install @livepeer-frameworks/player-wc
import "@livepeer-frameworks/player-wc/define";

CDN (no bundler):

<!-- unpkg -->
<script src="https://unpkg.com/@livepeer-frameworks/player-wc/dist/fw-player.iife.js"></script>
<!-- or jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/@livepeer-frameworks/player-wc/dist/fw-player.iife.js"></script>

Shadow DOM encapsulates all CSS — host page styles won’t break controls.

<fw-player content-type="live" content-id="<YOUR_PLAYBACK_ID>" autoplay muted></fw-player>

The element resolves through the official FrameWorks Gateway from the viewer’s browser, so Foghorn routes from that viewer’s IP. Set gateway-url only for a provider-managed private Gateway or local Gateway preview. For backend-generated playback URLs or custom players that do not use this element, use the dashboard playback DNS URL directly.

<fw-player
content-type="live"
content-id="<YOUR_PLAYBACK_ID>"
mist-url="https://edge-egress.eu.example.com"
autoplay
muted
></fw-player>
<fw-player content-type="dvr" content-id="a1b2c3d4e5f6g7h8"></fw-player>
<fw-player content-type="clip" content-id="a1b2c3d4e5f6g7h8"></fw-player>

Provide your own controls via the controls slot. Access the controller for programmatic control:

<fw-player id="player" content-type="live" content-id="a1b2c3d4e5f6g7h8" autoplay muted></fw-player>
<script>
const player = document.getElementById("player");
// Access the controller
player.controller.play();
player.controller.pause();
player.controller.seek(30000);
player.controller.setVolume(0.5);
// Listen for state changes
player.addEventListener("fw-state-change", (e) => {
console.log("State:", e.detail.state);
});
</script>

Provide custom controls via the controls slot and call the player element’s exposed controller:

<fw-player id="slot-player" content-id="a1b2c3d4e5f6g7h8" content-type="live">
<div slot="controls">
<button type="button" data-action="play">Play/Pause</button>
<button type="button" data-action="back">Back 10s</button>
<button type="button" data-action="forward">Forward 10s</button>
<button type="button" data-action="mute">Mute</button>
<button type="button" data-action="fullscreen">Fullscreen</button>
</div>
</fw-player>
<script>
const player = document.getElementById("slot-player");
player.addEventListener("click", (event) => {
const action = event.target?.dataset?.action;
if (action === "play") player.controller.togglePlay();
if (action === "back") player.controller.seekBy(-10000);
if (action === "forward") player.controller.seekBy(10000);
if (action === "mute") player.controller.toggleMute();
if (action === "fullscreen") player.controller.toggleFullscreen();
});
</script>

For bundled apps, import the package root to register the composable helper elements, then use them outside the player element with the for attribute:

import "@livepeer-frameworks/player-wc";
<fw-player id="my-player" content-id="a1b2c3d4e5f6g7h8" content-type="live"></fw-player>
<div class="external-controls">
<fw-play-button for="my-player"></fw-play-button>
<fw-volume-button for="my-player"></fw-volume-button>
<fw-time-display for="my-player"></fw-time-display>
<fw-live-badge for="my-player"></fw-live-badge>
<fw-fullscreen-button for="my-player"></fw-fullscreen-button>
</div>
ElementPurpose
<fw-play-button>Play/pause toggle
<fw-skip-button>Skip forward/back (direction="back" or "forward")
<fw-volume-button>Mute/unmute toggle
<fw-time-display>Current time / duration
<fw-live-badge>Live indicator + jump-to-live
<fw-fullscreen-button>Fullscreen toggle
AttributeTypeDefaultDescription
content-idstring—Playback ID
content-typestring—live, dvr, clip, or vod; auto-detected from Gateway or Mist metadata when omitted
gateway-urlstringOfficialGateway GraphQL endpoint override
mist-urlstring—Direct MistServer URL
auth-tokenstring—Bearer token for Gateway GraphQL resolution
playback-tokenstring—Viewer JWT for playback access control
playback-token-transport"query" | "header""query"Sends the viewer JWT as ?fwjwt= or as Authorization: Bearer where player transports can set headers
thumbnail-urlstring—Poster image before playback
autoplaybooleantrueAuto-start playback
mutedbooleanfalseStart muted
controlsbooleanfalseCompatibility no-op
no-controlsbooleanfalseHide the built-in controls
stock-controlsbooleanfalseUse browser-native video controls
native-controlsbooleanfalseAlias for stock-controls
animate-prerollbooleanfalseCycle thumbnail sprite tiles as a preroll animation before playback
themestring"default"Theme preset
localestring"en"Built-in UI locale
playback-modestring"auto"Protocol selection mode (see Playback Modes); changing only this attribute after the player has started does not re-run selection
dev-modebooleanfalseShow dev panel
debugbooleanfalseDebug logging

Use a preset with the theme attribute:

<fw-player theme="tokyo-night" ...></fw-player>

Or set individual tokens with the themeOverrides property:

document.querySelector("fw-player").themeOverrides = {
accent: "200 80% 60%",
surface: "230 15% 12%",
radius: "8px",
};

Setting --fw-* custom properties on the fw-player element from page CSS has no effect: the player redeclares every token on its surface element inside the shadow root.

<template>
<fw-player :content-id="contentId" content-type="live" autoplay muted />
</template>
<script setup>
import "@livepeer-frameworks/player-wc/define";
import { ref } from "vue";
const contentId = ref("a1b2c3d4e5f6g7h8");
</script>
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
import "@livepeer-frameworks/player-wc/define";
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
export class AppModule {}
<fw-player [attr.content-id]="contentId" content-type="live" autoplay muted></fw-player>