Player Events & Liveness
The player event catalog, the manifest liveness signal, and how to tell when a stream is live.
The Native Frame web player is an event emitter. This page is the reference for the events it fires — including the manifest event, the player's live/offline signal — plus the polling behavior behind it and how to detect liveness from your backend.
Subscribing to player events
videoClient.requestPlayer(manifestUrl, options) returns a player you can subscribe to with player.on(event, handler):
import { VideoClient, types } from "@video/video-client-core";
const vc = new VideoClient(vcOptions);
const player = vc.requestPlayer(manifestUrl, playerOptions);
player.on("driverFailover", (failedOver) => {
console.log("driver failover:", failedOver);
});
manifest eventrequestPlayer is typed to return PlayerAPI, but the object it returns is a manifest player, which emits the additional manifest event. To subscribe with full typing, cast to types.ManifestPlayer:
const player = vc.requestPlayer(manifestUrl, playerOptions) as types.ManifestPlayer;
player.on("manifest", ({ state, formats, viewCount }) => {
console.log("stream is", state, "with", viewCount, "viewers");
});
The manifest event — the live/offline signal
The player fetches and re-polls the stream's manifest, and emits manifest with the result. This is the signal to build live/offline UI on:
player.on("manifest", (m) => {
// m: { state: "online" | "offline" | "forbidden"; code?: number;
// formats: ManifestFormats; viewCount?: number }
});
state | Meaning |
|---|---|
online | The stream is live — the manifest returned playable formats. |
offline | The stream is not live (the manifest returned 404 or no formats). The player keeps polling and transitions back to online when the stream starts. |
forbidden | Access was denied (401/403) and did not recover within the recovery window. This is terminal: the player disposes and raises an error. |
codeis the HTTP status of the manifest request.formatslists the available delivery formats (mp4-hls,webrtc,jpeg, …).viewCountis the stream's current viewer count — see Viewer presence.
Polling cadence
The player re-polls the manifest on an interval that depends on the last result. All four are configurable via requestPlayer options:
| Option | Default | Applies when |
|---|---|---|
pollingInterval | 5000 ms | Stream online |
notFoundPollingInterval | 10000 ms | Stream offline (last poll was 404) |
unauthorizedPollingInterval | 2000 ms | Last poll was 401/403, still inside the recovery window |
unauthorizedRecoveryDuration | 10000 ms | How long 401/403 is retried before the player gives up with forbidden |
So an offline stream is noticed within ~10 seconds of going live, and recorded (VOD) manifests are not polled at all.
Event catalog
Events on every player:
| Event | Payload | Fires when |
|---|---|---|
manifest | { state, code?, formats, viewCount? } | Each manifest poll result — see above. (Manifest players only.) |
driver | string | The active playback driver changed (e.g. "webrtc", "hlsjs"). |
driverFailover | boolean | The active driver stalled and the player failed over to a backup driver. |
restartDriver | { timeout: number } | The player is restarting its driver. |
availableQualities | Quality[] | The set of selectable quality levels changed. |
currentQuality | Quality | null | The active quality level changed. |
localVideoPaused | boolean | Playback was paused/resumed locally. |
localAudioMuted | boolean | Audio was muted/unmuted locally. |
localAudioVolume | number | Local volume changed. |
forcedMute | boolean | The browser's autoplay policy forced the player to mute. |
hostElementAttached | { el } | The player attached to its <video> element. |
videoFirstPlay | — | First frame of playback. |
timeupdate, progress | — | Standard playback progress ticks. |
consumerAudioEnabled | boolean | The remote peer's audio track became active/inactive (WebRTC). |
consumerVideoEnabled | boolean | The remote peer's video track became active/inactive (WebRTC). |
playerAccessDenied | { message: string } | The access token was rejected — most commonly because a webhook token was reused (tokens must be unique per viewer). |
peerAtCapacity | boolean | A private stream is at its producer/peer capacity. |
noPlayers | boolean | No compatible playback driver is available in this browser — see codec support. |
error | Error | A player error. Always subscribe to this. |
disposed | — | The player was disposed. |
playerAccessDenied typically means an access token was used more than once. Webhook-validated viewer tokens are single-use — issuing the same token to two viewers kicks the first one. See Webhook Authentication.
Detecting liveness from your backend
If you need liveness server-side (not in the player), poll the stream detail endpoint — but read its liveness fields carefully:
activeis only present — astrue— while the stream is live. When the stream is offline, the field is omitted entirely; the API never returnsactive: false. Check for the presence of the field (data.active === true), and treat a missing field as offline. Code that waits foractive === falsewill wait forever.lastLiveAt(most recent time the stream was live) andcurrentLiveSince(start of the current broadcast) are likewise omitted when not applicable, and are only populated for v2-mode streams.- Alternatively, poll the stream's manifest URL with
GET—200with formats means live,404means offline. (UseGET, notHEAD: the manifest endpoint returns404toHEADrequests even when the stream is live.) - For push-based liveness, the
starting/closedevents on the program-states webhook fire when a broadcast starts and ends.
Viewer presence
There is no push-based viewer roster. Your options:
- Pull: the manifest document and the
manifestplayer event both carryviewCount; there are also dedicated viewer count and stream state endpoints. - Push: derive joins and leaves from the
joining/closedevents on consuming tokens in the program-states webhook — see the presence recipe in the webhook stream-state guide.
See also
- View a Stream — the manifest player, codec support, and the snapshot poster fallback
- Private Stream Viewer Auth — why an unauthorized viewer of a private stream gets a blurred picture instead of an error, and the two ways to authorize one
- Customize your Player — UI components and controls
- Manifests — what the manifest document contains
- Webhooks API reference — the server-side event catalog