Media & Streaming Event Spec
This page defines standard events for video and audio platforms — including on-demand streaming, live video, and podcast players. The spec is inspired by Segment’s video tracking spec and extended for modern streaming use cases.
All events are sent via _df.track(). Properties listed here are sent inside the properties object.
Playback vs Content Events
This spec distinguishes between two categories of video event:
Playback events (video_playback_*) describe the state of the media player — play, pause, buffer, seek. They are fired regardless of what content is loaded.
Content events (video_content_*) describe the specific piece of content being watched — the show, film, or clip. A single playback session may contain multiple content items (e.g. a playlist or episode queue).
Use session_id to correlate all events within the same viewing session.
Session Identification
Every video event must include a session_id — a unique identifier you generate when the player initialises. All playback, content, and ad events within a single viewing session share the same session_id, making it possible to reconstruct the full session timeline from raw event data.
Generate a new session_id each time the player loads, not each time a new video starts.
Video Playback Events
These events describe the state of the media player.
video_playback_started
Fired when a user presses play and playback begins (or auto-play initiates). This is the first event in any playback session.
_df.track('video_playback_started', {
session_id: 'vps-f3a9c2b1',
content_asset_id: 'ep-s2e4-breaking-ground',
position: 0,
total_length: 2740,
bitrate: 4500,
quality: '1080p',
fullscreen: false,
sound: 80,
livestream: false
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Unique identifier for this playback session |
content_asset_id | string | Optional | ID of the content item currently loaded |
content_pod_id | string | Optional | ID of the content playlist or pod |
ad_asset_id | string | Optional | ID of an ad playing at session start (pre-roll) |
position | number | Optional | Playback position in seconds at start |
total_length | number | Optional | Total duration of the content in seconds |
bitrate | number | Optional | Current stream bitrate in kbps |
quality | string | Optional | Video quality label (e.g. 1080p, 720p, 480p, auto) |
fullscreen | boolean | Optional | Whether the player is in fullscreen mode |
sound | number | Optional | Volume level at start, expressed as 0–100 |
livestream | boolean | Optional | Whether this is a live stream |
video_playback_paused
Fired when playback is paused by the user.
_df.track('video_playback_paused', {
session_id: 'vps-f3a9c2b1',
position: 483,
total_length: 2740
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
position | number | Optional | Playback position in seconds when paused |
total_length | number | Optional | Total duration of the content in seconds |
video_playback_resumed
Fired when playback resumes after a pause.
_df.track('video_playback_resumed', {
session_id: 'vps-f3a9c2b1',
position: 483,
total_length: 2740
})Accepts the same properties as video_playback_paused.
video_playback_completed
Fired when the player reaches the end of the content and playback stops naturally.
_df.track('video_playback_completed', {
session_id: 'vps-f3a9c2b1',
total_length: 2740
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
total_length | number | Optional | Total duration of the content in seconds |
video_playback_buffer_started
Fired when playback stalls and the player enters a buffering state.
_df.track('video_playback_buffer_started', {
session_id: 'vps-f3a9c2b1',
position: 721
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
position | number | Optional | Playback position in seconds when buffering began |
video_playback_buffer_completed
Fired when buffering ends and playback resumes.
_df.track('video_playback_buffer_completed', {
session_id: 'vps-f3a9c2b1',
position: 721
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
position | number | Optional | Playback position in seconds when buffering ended |
video_playback_seek_started
Fired when the user begins scrubbing or seeking to a new position in the timeline.
_df.track('video_playback_seek_started', {
session_id: 'vps-f3a9c2b1',
seek_position: 1200
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
seek_position | number | Required | Target position in seconds the user is seeking to |
video_playback_seek_completed
Fired when the seek operation completes and playback resumes at the new position.
_df.track('video_playback_seek_completed', {
session_id: 'vps-f3a9c2b1',
seek_position: 1200
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
seek_position | number | Optional | Position in seconds where playback resumed |
Video Content Events
These events describe the specific content item being played within a session.
video_content_started
Fired when a content item begins playing. In a playlist, fire this for each new item as it starts.
_df.track('video_content_started', {
session_id: 'vps-f3a9c2b1',
asset_id: 'ep-s2e4-breaking-ground',
title: 'Breaking Ground — Season 2, Episode 4',
description: 'The team discovers an unexpected obstacle beneath the foundation.',
keywords: ['construction', 'documentary', 'engineering'],
season: '2',
episode: '4',
genre: 'Documentary',
programme: 'Breaking Ground',
publisher: 'Northfield Studios',
channel: 'Documentary',
livestream: false,
airdate: '2026-01-14',
total_length: 2740,
position: 0
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
asset_id | string | Optional | Unique identifier for this content item |
title | string | Optional | Display title of the content |
description | string | Optional | Short description or synopsis |
keywords | string[] | Optional | Topic or genre keywords |
season | string | Optional | Season number (for episodic content) |
episode | string | Optional | Episode number (for episodic content) |
genre | string | Optional | Genre classification |
programme | string | Optional | Parent show or series name |
publisher | string | Optional | Production company or content owner |
channel | string | Optional | Channel or category within the platform |
livestream | boolean | Optional | Whether this is live content |
airdate | string | Optional | Original broadcast or release date (ISO 8601) |
total_length | number | Optional | Total duration of the content in seconds |
position | number | Optional | Position in seconds where the content started playing |
video_content_completed
Fired when a content item finishes playing. For playlists, this fires before video_content_started fires for the next item.
_df.track('video_content_completed', {
session_id: 'vps-f3a9c2b1',
asset_id: 'ep-s2e4-breaking-ground',
total_length: 2740
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
asset_id | string | Optional | Unique identifier for the completed content item |
total_length | number | Optional | Total duration of the content in seconds |
video_content_milestone
Fired when a user reaches a watch percentage milestone. Fire once each at 25%, 50%, and 75% completion. Do not fire at 100% — use video_content_completed instead.
_df.track('video_content_milestone', {
session_id: 'vps-f3a9c2b1',
asset_id: 'ep-s2e4-breaking-ground',
position: 685,
milestone: 25
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
asset_id | string | Optional | Identifier of the content item |
position | number | Optional | Playback position in seconds at the milestone |
milestone | number | Optional | Milestone reached. One of: 25, 50, 75 |
Milestone events are useful for measuring engaged viewing. Use them in pipeline transformations to send custom audience signals — for example, sending users who reach the 75% milestone to a retargeting list.
Video Ad Events
These events track ad impressions and interactions within the video player.
video_ad_started
Fired when an ad begins playing within the player.
_df.track('video_ad_started', {
session_id: 'vps-f3a9c2b1',
asset_id: 'ad-northedge-brand-001',
pod_id: 'pod-preroll-01',
type: 'pre-roll',
title: 'NorthEdge — Summer Collection',
publisher: 'NorthEdge',
total_length: 30,
position: 0,
load_type: 'linear'
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
asset_id | string | Optional | Unique identifier for the ad creative |
pod_id | string | Optional | Identifier for the ad break (pod) this ad belongs to |
type | string | Optional | Ad placement type. One of: pre-roll, mid-roll, post-roll |
title | string | Optional | Ad title or campaign name |
publisher | string | Optional | Advertiser or publisher serving the ad |
total_length | number | Optional | Duration of the ad in seconds |
position | number | Optional | Playback position within the content when the ad started |
load_type | string | Optional | Ad serving method. One of: linear (standard), dynamic (DAI) |
video_ad_completed
Fired when an ad plays through to completion without being skipped.
_df.track('video_ad_completed', {
session_id: 'vps-f3a9c2b1',
asset_id: 'ad-northedge-brand-001',
pod_id: 'pod-preroll-01'
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
asset_id | string | Optional | Identifier for the completed ad |
pod_id | string | Optional | Identifier for the ad break |
video_ad_skipped
Fired when a user skips a skippable ad before it completes.
_df.track('video_ad_skipped', {
session_id: 'vps-f3a9c2b1',
asset_id: 'ad-northedge-brand-001',
position: 6
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Playback session identifier |
asset_id | string | Optional | Identifier for the skipped ad |
position | number | Optional | Position in seconds within the ad at the point of skip |
Audio Events
audio_playback_started
Fired when audio playback begins — for music tracks, podcast episodes, or audio articles.
_df.track('audio_playback_started', {
session_id: 'aps-9b3f21a0',
asset_id: 'pod-signal-ep-041',
title: 'Server-Side Tracking in 2026',
artist: 'The Datafly Podcast',
album: 'Season 3',
genre: 'Technology',
duration: 3180,
position: 0
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Unique identifier for this audio playback session |
asset_id | string | Optional | Unique identifier for the audio asset |
title | string | Optional | Track or episode title |
artist | string | Optional | Artist, host, or creator name |
album | string | Optional | Album, show, or series name |
genre | string | Optional | Genre classification |
duration | number | Optional | Total duration of the audio asset in seconds |
position | number | Optional | Playback position in seconds at start |
audio_playback_paused
Fired when audio playback is paused.
_df.track('audio_playback_paused', {
session_id: 'aps-9b3f21a0',
position: 940
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Audio playback session identifier |
position | number | Optional | Playback position in seconds when paused |
audio_playback_completed
Fired when an audio asset plays through to the end.
_df.track('audio_playback_completed', {
session_id: 'aps-9b3f21a0',
asset_id: 'pod-signal-ep-041',
duration: 3180
})| Property | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | Audio playback session identifier |
asset_id | string | Optional | Identifier for the completed audio asset |
duration | number | Optional | Total duration of the audio asset in seconds |
podcast_subscribed
Fired when a user subscribes to a podcast show within the platform.
_df.track('podcast_subscribed', {
show_id: 'show-datafly-podcast',
show_title: 'The Datafly Podcast'
})| Property | Type | Required | Description |
|---|---|---|---|
show_id | string | Required | Unique identifier for the podcast show |
show_title | string | Optional | Display title of the podcast show |