Skip to content

ReferenceMedia

playerjs-video

Video component that plays any embed implementing the player.js protocol, such as Mux Player, Gumlet, FrameRate, Livid, Bunny Stream, and Streamable

player.js is a postMessage protocol for controlling embedded players, not a video host. Any embed that implements its receiver side plays through this one component: Mux Player’s iframe embed, Gumlet, FrameRate, Livid, Bunny Stream, Streamable, and others. Commands are posted to the embed directly, so no third-party script loads.

Import

pnpm add @videojs/playerjs-video
import '@videojs/html/media/playerjs-video';

Or load it from the CDN:

<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.0.1/media/playerjs-video.js"></script>

Load a source

src takes the embed URL of any player.js receiver: an absolute http or https URL, with protocol-relative URLs (//host/…) read as https. Nothing inspects the URL to decide whether it speaks player.js; choosing this component is the opt-in. A src that isn’t an http(s) URL fails with MEDIA_ERR_SRC_NOT_SUPPORTED, and an embed that doesn’t implement the protocol never reports ready, so the element stays at readyState 0.

<playerjs-video src="https://play.gumlet.io/embed/64bfb0913ed6e5096d66dc1e"></playerjs-video>

Feature detection

Embeds implement the spec to different degrees. Each one lists the methods and events it supports in its ready message, and every command is checked against that list:

  • A missing getter leaves its value at the default, such as a duration of NaN. Some embeds implement a getter but can’t answer it yet: Streamable reports no duration until playback starts.
  • A missing setter is a no-op; the value stays wherever the embed has it.

supports(type, name) reports whether the embed advertised a method or event. type is 'method' or 'event', and name is one player.js name or an array of names that must all be supported. It returns false until the embed reports ready.

The loadcomplete event marks the point where the answer is meaningful:

const video = document.querySelector('playerjs-video');

video.addEventListener('loadcomplete', () => {
  const canSeek = video.supports('method', 'setCurrentTime');
});

Controls

Without controls, the element ignores pointer events, so a player skin above it receives every click. With controls, the embed’s own chrome takes pointer input.

player.js itself can’t hide an embed’s chrome, but for the services it recognizes, the element does it through the embed URL, as far as each service allows:

Service Without controls
Mux Player (player.mux.com) Nothing: its controls are hidden with the --controls CSS property, which the iframe doesn’t expose. Under a skin its control bar still stays out of sight, since the frame never gets the hover that reveals it, but its center play button shows while paused
Gumlet disable_player_controls=true: only the large center play button stays
FrameRate show_controls=0 and initial_play_btn=0: no control bar and no large start button
Livid controls=0: no chrome at all, the play button included. Livid applies it to videos on Pro and Premium accounts only
Bunny Stream No parameter hides the control bar, so it’s shrunk instead: compactControls=true, showSpeed=false, showHeatmap=false, chromecast=false, disableAirPlay=true
Streamable nocontrols=1: no chrome at all

Other services get their URL untouched; pass whatever they offer under source.engine.playerJs.

URL parameters

For the recognized services, autoplay, muted (either muted or defaultMuted), loop, and preload are written onto the embed URL in the service’s own spelling, and turned off explicitly where the service defaults to on: Gumlet and Streamable loop, and Bunny Stream autoplays. Livid and Mux Player also take preload as the element’s own value. The embed reads its URL once, so changing these later reaches the embed over the protocol (autoplay, muted, loop) or not until the next source (controls, preload); rebuilding the frame for them would restart the video.

Every other parameter a service documents works too, in either of two places. Written into src, a parameter is kept as written, even over one the element would derive. Under source.engine.playerJs, it overrides both. A parameter a service reads from the URL hash, like Livid’s start time #t=25, goes in src.

<playerjs-video src="https://player.mediadelivery.net/embed/759/eb1c4f77-0cda-46be-b47d-1118ad7c2ffe?t=30s&captions=en"></playerjs-video>

Behavior

  • autoplay, muted (seeded by defaultMuted), and loop are also applied over the protocol once the embed reports ready, which is how they reach services the element doesn’t recognize. An embed without setLoop is looped by replaying it on ended.
  • volume (0 to 1, sent as the spec’s 0 to 100), muted, and seeking through currentTime use the spec’s methods.
  • playbackRate reaches only embeds that advertise setPlaybackRate, an extension to the spec that Gumlet implements.
  • player.js reports no buffering, so a started embed counts as playing.
  • No text tracks: textTracks stays empty.
  • The protocol has no fullscreen command, so the element’s own requestFullscreen() fullscreens the iframe.
  • poster and playsInline are stored but have no effect on the embed. preload reaches Livid and Mux Player as is and Bunny Stream as preload=false when it’s "none", and no other service.
  • An embed error with code 1 surfaces as MEDIA_ERR_SRC_NOT_SUPPORTED. Codes 2 and 3 mean a command wasn’t supported; they’re ignored, with a warning in development. Any other code is a fatal error carrying the embed’s message.

Examples

Basic Usage

<playerjs-video class="playerjs-video" src="https://play.gumlet.io/embed/64bfb0913ed6e5096d66dc1e" controls></playerjs-video>

API Reference

Attributes

These attributes configure the embedded media adapter:

AttributeTypeDefault
autoplaybooleanfalse
controlsbooleanfalse
loopbooleanfalse
mutedbooleanfalse
playsinlinebooleantrue
posterstring''
preloadMediaPreloadType'metadata'
srcstring''

Properties

PropertyTypeDefaultDetails
autoplaybooleanfalse
bufferedTimeRangeLike—
controlsbooleanfalse
currentSrcstring—
currentTimenumber—
defaultMutedbooleanfalse
durationnumber—
endedboolean—
engineWindow | null—
errorMediaError | null—
isFullscreenboolean—
loopbooleanfalse
mutedbooleanfalse
pausedboolean—
playbackRatenumber—
playedobject—
playsInlinebooleantrue
posterstring''
preloadMediaPreloadType'metadata'
readyStatenumber—
seekableTimeRangeLike—
seekingboolean—
sourceobjectnull
srcstring''
textTracksTextTrackListLike—
volumenumber—

Engine options

source.engine.playerJs

player.js standardizes the messages an embed answers, not its URL, so there are no shared parameters. Every key under source.engine.playerJs is written onto the embed URL’s query as given, for whichever service serves it — anything in Gumlet’s, Bunny Stream’s, or Livid’s parameter lists, for example. Values are stringified (true becomes 'true'), an array repeats the parameter once per value, and null removes a parameter the URL would otherwise carry. These override both src and the parameters the element derives from its props. Changing them reloads the embed. Media Sources covers how engine options fit into a structured source.

referrerPolicy never reaches the URL, and <playerjs-video> doesn’t apply it to its iframe either; it takes effect only in the React component.

Prefer the autoplay, loop, muted, controls, and preload props over their URL spellings: the props also reach the embed over the protocol and keep the element’s state in step with it.

const video = document.querySelector('playerjs-video');
video.controls = true;
video.source = {
  src: 'https://play.gumlet.io/embed/64bfb0913ed6e5096d66dc1e',
  engine: { playerJs: { player_color: '#ff0000', disabled_player_control: ['cast', 'pip'] } },
};
OptionTypeDetails
referrerPolicyReferrerPolicy | undefined

Methods

Supports these media methods: exitFullscreenloadpauseplayrequestFullscreensupports

Events

Implements these standard media events through the embedded player: durationchangeemptiedendederrorloadedmetadataloadstartpauseplayplayingprogressratechangeseekedseekingtimeupdatevolumechange

Also emits these Video.js-specific events:

EventDescription
loadcomplete
sourcechangeFired when source changes, either directly or by resolving a new src. Read source for the new value.