Skip to content

Player — Vanilla JS

Terminal window
npm install @livepeer-frameworks/player-core
import "@livepeer-frameworks/player-core/player.css";

The primary API for vanilla and headless usage. Returns a property-based facade with queries, mutations, and subscriptions.

import { createPlayer } from "@livepeer-frameworks/player-core";
import "@livepeer-frameworks/player-core/player.css";
const player = createPlayer({
target: "#player",
contentId: "my-stream",
contentType: "live",
theme: "dracula",
autoplay: true,
muted: true,
});
// Read state (queries)
player.state; // "playing"
player.volume; // 0.75
player.currentTime; // 12500 (ms)
player.live; // true
player.paused; // false
// Change state (mutations)
player.volume = 0.5;
player.play();
player.pause();
player.seek(30000);
player.theme = "tokyo-night";
// React to changes (subscriptions)
const unsub = player.subscribe.on("volume", (v) => console.log("Volume:", v));
// Cleanup
player.destroy();

By default, resolution runs through the official FrameWorks Gateway from the viewer’s browser or playback device. Set gatewayUrl only for a fully self-hosted control plane or local Gateway preview. If you are generating URLs on a backend or building a player that will not call Gateway from the viewer, use the dashboard playback DNS URL directly.

PropertyTypeDescription
statePlayerStateCurrent lifecycle state
streamStateStreamState | nullUpstream stream status
endpointsContentEndpoints | nullResolved playback endpoints
metadataobjectStream metadata from gateway
videoElementHTMLVideoElement | nullUnderlying video element
readybooleanPlayer initialized and ready
currentTimenumberCurrent position (milliseconds)
durationnumberTotal duration in milliseconds (Infinity for live)
volumenumberVolume level (0-1)
mutedbooleanWhether muted
pausedbooleanWhether paused
playingbooleanWhether actively playing
bufferingbooleanWhether buffering
startedbooleanWhether playback started at least once
playbackRatenumberCurrent speed
loopbooleanLooping enabled
livebooleanWhether live stream
nearLivebooleanWhether near the live edge
fullscreenbooleanWhether in fullscreen
pipbooleanWhether in picture-in-picture
errorstring | nullCurrent error message
qualityPlaybackQuality | nullActive quality level
abrMode'auto' | 'resize' | 'bitrate' | 'manual'ABR mode
themestringCurrent theme
size{ width, height }Container dimensions
capabilitiesCapabilitiesRuntime feature detection
MutationSignatureDescription
volumeset volume(n)Set volume (0-1)
mutedset muted(b)Set mute state
playbackRateset playbackRate(n)Set playback speed
loopset loop(b)Enable/disable looping
abrModeset abrMode(m)Switch ABR mode
themeset theme(t)Switch theme preset
play()() => Promise<void>Start playback
pause()() => voidPause playback
seek(t)(milliseconds) => voidSeek to time
seekBy(d)(deltaMs) => voidSeek relative
jumpToLive()() => voidJump to live edge
skipForward(ms?)(milliseconds?) => voidSkip forward (default 10000ms)
skipBack(ms?)(milliseconds?) => voidSkip backward (default 10000ms)
togglePlay()() => voidToggle play/pause
toggleMute()() => voidToggle mute
toggleFullscreen()() => Promise<void>Toggle fullscreen
togglePiP()() => Promise<void>Toggle picture-in-picture
getQualities()() => Quality[]List available qualities
selectQuality(id)(id) => voidLock to specific quality
retry()() => Promise<void>Retry current connection
retryWithFallback()() => Promise<boolean>Retry with next endpoint
reload()() => Promise<void>Full reload
clearError()() => voidDismiss error
getStats()() => Promise<unknown>Playback statistics snapshot
setThemeOverrides(o)(overrides) => voidApply theme overrides
clearTheme()() => voidReset to default theme
destroy()() => voidTear down the player
const unsub = player.on("stateChange", ({ state }) => {
console.log("State:", state);
});
unsub();
EventPayloadDescription
stateChange{ state, context? }State transition
timeUpdate{ currentTime, duration }Position changed
volumeChange{ volume, muted }Volume/mute changed
qualityChanged{ fromLevel?, toLevel }Quality level changed
fullscreenChange{ isFullscreen }Fullscreen state changed
pipChange{ isPiP }PiP state changed
error{ error, code? }Playback error
streamStateChange{ state }Upstream status changed
metadataUpdate{ currentTime, duration, bufferedAhead, ... }Metadata updated

Per-property subscriptions with immediate invocation via player.subscribe:

const unsub = player.subscribe.on("volume", (v) => {
volumeSlider.value = v;
});
const unsub2 = player.subscribe.on("playing", (isPlaying) => {
playBtn.textContent = isPlaying ? "Pause" : "Play";
});
// Synchronous read
const vol = player.subscribe.get("volume");

Available reactive properties: paused, playing, currentTime, duration, volume, muted, playbackRate, loop, buffering, fullscreen, pip, tracks, streamState, error, loading, ended, seeking.

Constructor-based alternative for class-oriented code:

import { FrameWorksPlayer } from "@livepeer-frameworks/player-core/vanilla";
import "@livepeer-frameworks/player-core/player.css";
const player = new FrameWorksPlayer("#player", {
contentId: "<YOUR_PLAYBACK_ID>",
contentType: "live",
autoplay: true,
muted: true,
onStateChange: (state) => console.log("State:", state),
onReady: (videoElement) => console.log("Ready!"),
});
player.play();
player.pause();
player.seek(30000);
player.setVolume(0.5);
player.jumpToLive();
player.destroy();
<template>
<div ref="container" style="width: 100%; aspect-ratio: 16/9;" />
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import type { FrameWorksPlayer as FWP } from "@livepeer-frameworks/player-core/vanilla";
const container = ref<HTMLDivElement>();
let player: FWP | null = null;
onMounted(async () => {
const { FrameWorksPlayer } = await import("@livepeer-frameworks/player-core/vanilla");
await import("@livepeer-frameworks/player-core/player.css");
if (container.value) {
player = new FrameWorksPlayer(container.value, {
contentId: "<YOUR_PLAYBACK_ID>",
contentType: "live",
autoplay: true,
muted: true,
});
}
});
onUnmounted(() => player?.destroy());
</script>

The capabilities object reports runtime feature support:

if (player.capabilities.pip) player.togglePiP();
if (player.capabilities.qualitySelection) player.selectQuality("720p");
PropertyTypeDescription
fullscreenbooleanFullscreen API available
pipbooleanPicture-in-picture available
seekingbooleanArbitrary seeking supported
playbackRatebooleanSpeed control supported
audiobooleanAudio track selection
qualitySelectionbooleanManual quality selection
textTracksbooleanSubtitle/caption support
OptionTypeDefaultDescription
targetstring | HTMLElementContainer
contentIdstringPlayback ID
contentTypestring"live"Content type
gatewayUrlstringOfficialGateway GraphQL endpoint override
mistUrlstringDirect MistServer URL
endpointsContentEndpointsPre-resolved endpoints
autoplaybooleantrueAuto-start
mutedbooleanfalseStart muted
controlsbooleantrueShow built-in controls
posterstringPoster image before playback
animatePrerollbooleanfalseCycle thumbnail sprite tiles as a preroll animation before playback
themestring"default"Theme preset
themeOverridesobjectPer-token theme overrides
localestring"en"UI language
playbackModestring"auto"Protocol preference
skinstring | SkinDefinition | false"default"Skin for blueprint rendering (see Advanced)
debugbooleanfalseDebug logging