Skip to content

Configuration

All options are passed to init(config). Every key is optional, but you must supply either endpoint or handler — with neither, init() emits a console.warn and no events are delivered.

Option Type Default Description
endpoint string | null null URL that events are POSTed to as JSON. Required unless handler is set.
handler function | null null Custom delivery callback handler(payload). When set it fully replaces network delivery — endpoint is never called. Thrown errors are caught and logged, not propagated.
events object { listen: 30 } Which events fire and their thresholds. Keys: play, listen (seconds of media-time), complete (percent 0–100). Any subset; omit a key (or pass null / false) to disable that event. 0 is a real threshold (1.1.0+).
headers object<string,string> {} Extra headers merged into the fetch POST (e.g. Authorization). Any custom header rules out sendBeacon (beacon can’t set headers), so terminal events always go by fetch + keepalive. For a cross-origin endpoint, list each header in the preflight’s Access-Control-Allow-Headers — see Delivery semantics.
metadata object {} Key/value pairs spread into every payload (e.g. user_id, post_id).
session boolean true When true, a random anonymous session id is generated on init() and added to every payload as session (a later init() keeps it, 1.1.0+). Pass false to omit it entirely.
debug boolean false When true, emits verbose console.log('[WaveformTracker]', …) tracing (ready/destroy, play/pause, sent payloads, beacon fallbacks). Does not suppress sending.
WaveformTracker.init({
endpoint: '/api/track',
events: {
play: 3, // fire 'play' once 3s of media-time accumulates
listen: 30, // fire 'listen' once 30s of media-time accumulates
complete: 90 // fire 'complete' once playback reaches 90% of duration
}
});
  • play and listen are seconds of accumulated media-time.
  • complete is a percent (0–100) of duration. It fires when (currentTime / duration) * 100 crosses the threshold during playback, or on the player’s ended event — only for a finite duration above 0, so never for a live stream.
  • complete also needs real listening (1.1.0+): at least half the audio up to the threshold must have been heard, in media-time (COMPLETE_ENGAGEMENT = 0.5). With complete: 90 on a 4-minute track that’s 108s, so scrubbing to 95% — or to the end — no longer counts as a completion. Expect fewer complete events than 1.0.x reported.
  • A threshold of 0 fires on the first check after playback starts (1.1.0+; it used to disable the event). Omit the key, or pass null / false, to turn an event off.
  • Each event fires at most once per track, tracked per player. The set re-arms on ended, so a replay can fire them all again, and when the player switches to a different URL (loadTrack() or load()), so the new track gets its own events (1.0.2+).
  • The default config — when you pass no events — fires only listen at 30 seconds.

metadata is spread into the payload before the fixed session and title keys. That ordering matters:

  • metadata can override the five core fields — event, url, time, duration, page.
  • metadata cannot override session or title (they’re added afterward).
WaveformTracker.init({
endpoint: '/api/track',
metadata: { user_id: 42, post_id: 456 },
session: true // default; set false to drop the session id
});

The session id is anonymous and in-memory only — a fresh random string (Math.random().toString(36).slice(2) + Date.now().toString(36)) generated by the first init() (and again after reset()) and regenerated on every reload. It correlates events within a single page session; it is not a persistent identifier.