Skip to content

Reference: Events

BaseEventMap is the complete event map every player built on the kit emits. Subscribe with player.on(name, handler), the payload type is inferred from the name. Library-specific maps (VideoEventMap, MusicEventMap) extend this with domain-only events on top.

Every before* row below carries a BeforeEvent<TData> payload: data (mutable), preventDefault(), isDefaultPrevented(), stopImmediatePropagation(), isPropagationStopped(), delay(promise), isDelayed(). See Transport Contract for the full cancel/mutate/delay walkthrough.

Setup lifecycle

Fires once, in order, during setup(). Each stage has a paired <stage>Error event.

EventPayload
beforeSetupvoid
setupStart{ container: HTMLElement }
configResolved{ config: BasePlayerConfig }
pluginsRegistering / pluginsRegisteredvoid
streamsReadyvoid
authReadyvoid
playlistResolving{ url: string }
playlistReady{ length: number }
playlistError{ url, error, code }
mediaReadyvoid
readyvoid
setupStartError / configResolvedError / pluginsRegisteringError / pluginsRegisteredError / streamsReadyError / authReadyError / playlistResolveError / mediaReadyErrorPlayerErrorEvent

Play-path lifecycle

EventPayload
beforePlay / beforePause / beforeStop / beforeNext / beforePreviousBeforeEvent<ActionOptions>
playPrevented / pausePrevented / stopPrevented / nextPrevented / previousPrevented / loadPrevented{ reason: PreventedReason; cause?: unknown }
firstFramevoid
playingvoid — fires when the backend confirms active rendering, after buffering resolves.
beforeSeekBeforeEvent<{ time: number; source?: ActionSource }>
seekPrevented{ reason, cause? }
beforeLoadBeforeEvent<{ item: I; source?: ActionSource }>

Mutation contract & phase

EventPayload
beforeMutationBeforeEvent<{ method: string; args: ReadonlyArray<unknown>; phase: PlayerPhase; dispatchStack: ReadonlyArray<string> }>
mutationPrevented{ method, reason, cause? }
phase{ from: PlayerPhase; to: PlayerPhase }

Standard transport

EventPayload
play / pause / stop / next / previousActionOptions
endedvoid
seek{ time: number; source?: ActionSource } — fires at dispatch time, before the backend moves.
seeked{ time: number } — fires after the backend confirms.
progress{ time, duration, percentage } — throttled by progressIntervalMs, prefer over time for watch-position saves.
timeTimeState{ time, position, duration, buffered, remaining, percentage }, the same snapshot timeData() returns. Unthrottled, per-frame.
disposevoid
beforeDisposeBeforeEvent<void>
disposePrevented{ reason, cause? }

Language, volume, mode state

EventPayload
language{ lang: string }
beforeLanguage / languagePreventedBeforeEvent<{ lang }> / { reason, cause? }
volume{ level: number }
beforeVolume / volumePreventedBeforeEvent<{ level }> / { reason, cause? } — fires unconditionally, independent of mutationGuards.
mute{ muted: boolean }
beforeMute / mutePreventedBeforeEvent<{ muted }> / { reason, cause? }
repeat{ state: RepeatState }
beforeRepeat / repeatPreventedBeforeEvent<{ state }> / { reason, cause? }
shuffle{ state: ShuffleState }
beforeShuffle / shufflePreventedBeforeEvent<{ state }> / { reason, cause? }
playbackRate{ rate: number }
beforePlaybackRate / playbackRatePreventedBeforeEvent<{ rate }> (already clamped [0.25, 2]) / { reason, cause? } — fires unconditionally.

Error severity tiers

EventPayload
fatal / error / warning / infoPlayerErrorEvent — see Reference: Errors.

Queue, backlog, item

EventPayload
item{ item: I | undefined; index: number }
queueI[]
queue:append{ items: I[]; from: number }
queue:prepend{ items: I[] }
queue:insert{ items: I[]; index: number }
queue:remove{ id, index, item }
queue:move{ from: number; to: number }
queue:clear{ previousLength: number }
queue:shuffle / queue:sortvoid
queue:exhaustedvoid — last item of a non-repeating queue ended naturally.
backlogI[]
backlog:append{ items: I[] }
backlog:remove{ id, index, item }
backlog:clear{ previousLength: number }
itemEndingSoon{ remaining: number; item: I } — fires once per item at itemEndingSoonThreshold.
duration{ duration: number }

Backend, auth, stream

EventPayload
backend:changed{ kind: string }
backend:loading{ url, kind }
backend:loaded{ url, kind, duration }
backend:error{ error, kind }
backend:stalled{ time: number }
backend:ratechange{ rate: number }
backend:waitingvoid
auth:refreshed{ tokenAcquiredAt: number }
auth:failed{ error }
stream:manifest-loaded{ url: string }
stream:level-switched{ level, label }
stream:fragment-loaded{ url, durationMs }
stream:level-considered{ candidate, decided, reason }
stream:error{ details, fatal }
stream:encrypted{ initData, initDataType }

Cues, audio track, chapters, cast

Subtitle-specific rows (subtitleCue, subtitleStyle, subtitle, beforeSubtitle / subtitlePrevented, subtitles) are typed in BaseEventMap at the core level for shared-implementation reasons, even though subtitles are a video-only concern in practice, see Reference: Events on the video player for the full walkthrough.

EventPayload
cue:enter / cue:exitCueEventPayload
subtitleCueSubtitleCueChange — unified cue-change stream across sidecar VTT and native text tracks.
subtitleStyleSubtitleStyle — written by subtitleStyle({...}).
subtitle{ track: number | null }
beforeSubtitle / subtitlePreventedBeforeEvent<{ track: number | null }> / { reason, cause? }
subtitles{ tracks: ReadonlyArray<SubtitleTrack> } — fires when addSubtitleTrack() / removeSubtitleTrack() changes the sidecar set.
audioTrack{ id: number | null }
beforeAudioTrack / audioTrackPreventedBeforeEvent<{ id }> / { reason, cause? }
chapter{ index: number; title: string }
chapters{ chapters: ReadonlyArray<Chapter> }
castState{ state: CastState }
beforeTransfer / transferPreventedBeforeEvent<{ target: CastTarget }> / { reason, cause? }
qualityState{ state: 'auto' | 'manual' }
audioTrackState{ state: 'default' | 'manual' }
level-switched{ level: number } — HLS adaptive level switch.

Plugins, network, metrics, activity

EventPayload
plugin:installed{ id, version }
plugin:enabled{ id }
plugin:disabled{ id, reason? }
plugin:opts:changed{ id, opts }
plugin:disposed{ id }
plugin:failed{ id, error }
plugin:error / plugin:warningPlayerErrorEvent
network:online / network:offlinevoid
network:slow{ rttMs: number | undefined } — only fires on the not-slow → slow transition.
visibility:visible / visibility:hiddenvoid
playback:metricsPlaybackMetrics
fetch:start{ url, pluginId? }
fetch:retry{ url, attempt, reason, delayMs, pluginId? }
fetch:complete{ url, ok, status?, durationMs, pluginId? }
activity{ active: boolean }
listeners-changed{ name: string; count: number }

Preload & transition

EventPayload
preloadStart{ item, assets }
preloadProgress{ item, loaded, total }
preloadComplete{ item }
preloadError{ item, error }
transitionStart{ outgoing, incoming }
transitionProgress{ outgoing, incoming, fraction }fraction is [0, 1].
transitionComplete{ from, to }
transitionCancelled{ reason: string }

Next steps

  • Reference: Types: the domain types and enums referenced throughout the tables above.