Skip to content
FrameworkStyle

Play live streams

Play live streams with live-edge tracking, DVR windows, and stream-type detection.

Play live streams: show a live badge, jump to the live edge, and support DVR windows when the stream allows scrubbing back.

Use the live feature bundle with a streaming media element, and give users a LiveButton: it shows whether playback is at the live edge and seeks back to it when activated.

<live-video-player>
  <media-container>
    <hlsjs-video src="https://your-stream.example.com/live.m3u8" autoplay muted playsinline></hlsjs-video>
    <media-live-button></media-live-button>
  </media-container>
</live-video-player>
<script type="module">
  import '@videojs/html/live-video/player';
  import '@videojs/html/media/hlsjs-video';
  import '@videojs/html/live-video/ui';
</script>

The liveVideoFeatures bundle mirrors videoFeatures but adds the live feature and drops playback rate (not meaningful for live), quality selection, and audio-track selection. The live presets also ship skins without duration and current-time displays.

Both bundles are plain arrays, so extending one is a spread:

import { createPlayer, streamTypeFeature } from '@videojs/html';
import { liveVideoFeatures } from '@videojs/html/live-video';

const { ProviderMixin } = createPlayer({ features: [...liveVideoFeatures, streamTypeFeature] });

How it works

Two features describe liveness:

  • The stream type feature reports streamType: 'live', 'on-demand', or 'unknown'. Streaming media derives it from manifest metadata; plain media elements fall back to duration-based detection. liveVideoFeatures does not include it; add streamTypeFeature to the player’s features when you need streamType.
  • The live feature reports two values:
    • liveEdgeStart is where “live” begins on the timeline. When the playhead is at or past this time, the viewer is watching live; behind it, they’re watching earlier moments of the stream.
    • targetLiveWindow is how far back the stream lets viewers rewind. 0 means a plain live stream that stays at the edge. Infinity means full DVR: rewind as far as the recording goes. NaN means the stream isn’t live, or the player doesn’t know yet.

The time feature adjusts for live playback: duration reports the live edge (the end of the seekable range) and keeps growing as the stream continues.

LiveButton reads this state: it renders as an active “go to live” control while playback is behind the edge, seeks to the edge on activation, and goes inactive at the edge.

Availability and constraints

  • liveEdgeStart and targetLiveWindow come from media that implements the live capability — the hls.js-based media elements. With plain media elements, stream type falls back to duration-based detection and liveEdgeStart stays NaN.
  • Live playback drifts behind the edge when the network stalls or the tab is backgrounded. Always give users a path back to the edge.
  • Seeking makes sense only for DVR streams (targetLiveWindow of Infinity). For standard-latency streams, omit the time slider.
  • Playback rate control isn’t meaningful for live; liveVideoFeatures omits it.

Common variations

DVR: let users scrub back

For streams with a DVR window, keep a TimeSlider in the UI. The slider tracks the sliding window automatically because duration follows the live edge.

Switch UI by stream type

Render live or on-demand controls from streamType when one player handles both kinds of content. Add streamTypeFeature to the player’s features; liveVideoFeatures does not include it:

<media-live-button> selects from the live, time, and buffer features and reflects live state. To swap larger parts of the UI on streamType, build a provider with createPlayer and add streamTypeFeature to its features (<live-video-player> uses liveVideoFeatures, which does not include it), then read streamType from the player store through the player controller.

Troubleshooting

The live badge never activates

streamType isn’t 'live'. Confirm the player’s features include streamTypeFeature (liveVideoFeatures does not include it, so streamType reads as undefined), the source is a live manifest, and it plays through a live-capable media element such as HlsJsVideo.

Playback keeps falling behind the edge

Network throughput can’t sustain the stream, or the tab was backgrounded. LiveButton returns users to the edge; for lower drift, review the stream’s latency configuration on the encoder side.

The time slider behaves oddly on a live stream

Standard-latency live streams have no meaningful seek range. Show the slider only for DVR streams (targetLiveWindow of Infinity).