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 datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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.
datafly.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 |