Video Tracking
Track video playback with per-minute active time, engagement, and performance metrics.
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']
});
| Parameter | Type | Description |
|---|---|---|
autoDetectVideoPlayers | string[]optional | List 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();
| Parameter | Type | Description |
|---|---|---|
playerAdapter | VideoPlayerAdapterrequired | An adapter object implementing the player interface (see below) |
Return value: an object with two methods:
| Method | Description |
|---|---|
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);
| Parameter | Type | Description |
|---|---|---|
getName() | function → stringrequired | Returns the video title displayed in reports |
getDuration() | function → numberrequired | Returns total duration in seconds (`0` if unknown) |
getCurrentTime() | function → numberrequired | Returns current playback position in seconds |
getVideoUrl() | function → stringrequired | Returns the asset URL (e.g., `.mp4`, HLS manifest) |
getVideoType() | function → stringrequired | Returns `'ondemand'`, `'linear'`, or `null` |
onPlay(callback) | functionrequired | Registers a callback for play/resume events |
onPause(callback) | functionrequired | Registers a callback for pause events |
onComplete(callback) | functionrequired | Registers a callback for natural video completion |
onBuffer(callback) | functionrequired | Registers a callback for buffering/stall events |
onError(callback) | functionrequired | Registers a callback for fatal playback errors |
onFirstFrame(callback) | functionrequired | Registers a callback for the first frame rendered. The callback receives `{ loadTime: number|null }` where `loadTime` is the startup time in milliseconds. |
destroy() | functionrequired | Removes 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
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.| Parameter | Type | Description |
|---|---|---|
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) | numberoptional | Startup 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.
trackVideo() call creates an independent session with its own active time and sequence number. You can track multiple simultaneous players on the same page.