Video Tracking

Track video playback with per-minute active time, engagement, and performance metrics.

Web only
Video tracking via player adapters is currently available for the JavaScript web collector only.

Overview

Video tracking creates dedicated videoplay events, independent from pageviews. Each tracked video gets its own session with:

  • Active time — per-minute breakdown of actual play time (only counted when the page is visible and focused)
  • Engagement percent — percentage of the video watched (currentTime / duration)
  • Performance metrics — startup time, rebuffering, load errors
  • Heartbeat — periodic updates every 30 seconds so partial views are never lost

Auto-detection

The simplest way to track JWPlayer instances. Add autoDetectVideoPlayers to your setConfig() call and the SDK automatically finds and tracks all players on the page, including those added dynamically.

alkeAnalytics.setConfig({
    propertyId: 'your-property-uuid',
    autoDetectVideoPlayers: ['jwplayer']
});
ParameterTypeDescription
autoDetectVideoPlayersstring[]optionalList of player names to auto-detect. Currently supported: `'jwplayer'`

Auto-detection scans the page for player instances every 500ms for 30 seconds after initialization, then stops. Players added after this window can be tracked manually.

Manual Tracking

Use trackVideo() when you need direct control — for example, after a dynamic player load or to track a custom player.

import JWPlayerAdapter from 'alke-collector/players/jwplayer';

// Create an adapter for your player instance
const adapter = new JWPlayerAdapter(jwplayer('my-player'));

// Start tracking — returns a handle
const handle = alkeAnalytics.trackVideo(adapter);

// Stop tracking early (sends a final event and cleans up)
handle.destroy();

// Access the unique ID generated for this video session
const videoId = handle.getVideoId();
ParameterTypeDescription
playerAdapterVideoPlayerAdapterrequiredAn adapter object implementing the player interface (see below)

Return value: an object with two methods:

MethodDescription
destroy()Sends a final event and stops all tracking for this video
getVideoId()Returns the unique ID (string) generated for this video session

JWPlayer Adapter

The built-in JWPlayerAdapter wraps a JWPlayer instance and implements the full player interface automatically, including startup time measurement from firstFrame and playlist change handling.

import JWPlayerAdapter from 'alke-collector/players/jwplayer';

jwplayer('my-player').setup({ file: 'video.mp4' });

// Pass the JWPlayer instance to the adapter
const adapter = new JWPlayerAdapter(jwplayer('my-player'));
const handle = alkeAnalytics.trackVideo(adapter);

When using autoDetectVideoPlayers: ['jwplayer'], this adapter is created automatically for each detected player — no manual instantiation needed.

Custom Player Adapter

To track any other player, implement the VideoPlayerAdapter interface:

const myAdapter = {
    // Video metadata
    getName()        { return player.getTitle(); },
    getDuration()    { return player.totalDuration; },
    getCurrentTime() { return player.currentPosition; },
    getVideoUrl()    { return player.sourceUrl; },
    getVideoType()   { return 'ondemand'; }, // 'ondemand' | 'linear' | null

    // Event registration
    onPlay(callback)       { player.on('play', callback); },
    onPause(callback)      { player.on('pause', callback); },
    onComplete(callback)   { player.on('ended', callback); },
    onBuffer(callback)     { player.on('waiting', callback); },
    onError(callback)      { player.on('error', callback); },
    onFirstFrame(callback) { player.on('playing', () => callback({ loadTime: null })); },

    // Cleanup
    destroy() {
        player.off('play'); player.off('pause'); player.off('ended');
        player.off('waiting'); player.off('error'); player.off('playing');
    }
};

alkeAnalytics.trackVideo(myAdapter);
ParameterTypeDescription
getName()function → stringrequiredReturns the video title displayed in reports
getDuration()function → numberrequiredReturns total duration in seconds (`0` if unknown)
getCurrentTime()function → numberrequiredReturns current playback position in seconds
getVideoUrl()function → stringrequiredReturns the asset URL (e.g., `.mp4`, HLS manifest)
getVideoType()function → stringrequiredReturns `'ondemand'`, `'linear'`, or `null`
onPlay(callback)functionrequiredRegisters a callback for play/resume events
onPause(callback)functionrequiredRegisters a callback for pause events
onComplete(callback)functionrequiredRegisters a callback for natural video completion
onBuffer(callback)functionrequiredRegisters a callback for buffering/stall events
onError(callback)functionrequiredRegisters a callback for fatal playback errors
onFirstFrame(callback)functionrequiredRegisters a callback for the first frame rendered. The callback receives `{ loadTime: number|null }` where `loadTime` is the startup time in milliseconds.
destroy()functionrequiredRemoves all event listeners registered by this adapter

Page-level Video Metadata

For simple use cases where video metrics should be attached to the current pageview rather than tracked as a dedicated videoplay event, use these setters before the pageview is finalized:

alkeAnalytics.setVideoType('ondemand');       // 'ondemand' | 'linear'
alkeAnalytics.setVideoRebuffer(true);         // rebuffering occurred
alkeAnalytics.setVideoLoadError(false);       // no load error
alkeAnalytics.setVideoStartupTime(850);       // 850ms startup
When to use page-level metadata vs. trackVideo()
Use setVideoType() and related methods when you want to annotate a pageview with video context (e.g., a video page where startup time matters). Use trackVideo() when you need a full independent video tracking session with active time, heartbeat, and engagement.
ParameterTypeDescription
setVideoType(type)string|nulloptional`'ondemand'`, `'linear'`, or `null` to clear
setVideoRebuffer(value)boolean|nulloptional`true` if rebuffering occurred, `null` to clear
setVideoLoadError(value)boolean|nulloptional`true` if a fatal load error occurred, `null` to clear
setVideoStartupTime(ms)numberoptionalStartup time in milliseconds (positive integer)

Event Lifecycle

Each trackVideo() call produces the following sequence of events:

trackVideo() called
     initial event sent immediately (final=0)
     heartbeat every 30s (final=0)
     on play/pause: active time updated in memory

video ends naturally / handle.destroy() / page unloads
     final event sent (final=1) with complete active time

If the video encounters a fatal error (onError), a final event is sent and tracking stops automatically.

Multiple videos
Each trackVideo() call creates an independent session with its own active time and sequence number. You can track multiple simultaneous players on the same page.