Event SpecsMedia & Streaming

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
})
PropertyTypeRequiredDescription
session_idstringRequiredUnique identifier for this playback session
content_asset_idstringOptionalID of the content item currently loaded
content_pod_idstringOptionalID of the content playlist or pod
ad_asset_idstringOptionalID of an ad playing at session start (pre-roll)
positionnumberOptionalPlayback position in seconds at start
total_lengthnumberOptionalTotal duration of the content in seconds
bitratenumberOptionalCurrent stream bitrate in kbps
qualitystringOptionalVideo quality label (e.g. 1080p, 720p, 480p, auto)
fullscreenbooleanOptionalWhether the player is in fullscreen mode
soundnumberOptionalVolume level at start, expressed as 0–100
livestreambooleanOptionalWhether 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
positionnumberOptionalPlayback position in seconds when paused
total_lengthnumberOptionalTotal 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
total_lengthnumberOptionalTotal 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
positionnumberOptionalPlayback 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
positionnumberOptionalPlayback 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
seek_positionnumberRequiredTarget 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
seek_positionnumberOptionalPosition 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
asset_idstringOptionalUnique identifier for this content item
titlestringOptionalDisplay title of the content
descriptionstringOptionalShort description or synopsis
keywordsstring[]OptionalTopic or genre keywords
seasonstringOptionalSeason number (for episodic content)
episodestringOptionalEpisode number (for episodic content)
genrestringOptionalGenre classification
programmestringOptionalParent show or series name
publisherstringOptionalProduction company or content owner
channelstringOptionalChannel or category within the platform
livestreambooleanOptionalWhether this is live content
airdatestringOptionalOriginal broadcast or release date (ISO 8601)
total_lengthnumberOptionalTotal duration of the content in seconds
positionnumberOptionalPosition 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
asset_idstringOptionalUnique identifier for the completed content item
total_lengthnumberOptionalTotal 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
asset_idstringOptionalIdentifier of the content item
positionnumberOptionalPlayback position in seconds at the milestone
milestonenumberOptionalMilestone 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'
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
asset_idstringOptionalUnique identifier for the ad creative
pod_idstringOptionalIdentifier for the ad break (pod) this ad belongs to
typestringOptionalAd placement type. One of: pre-roll, mid-roll, post-roll
titlestringOptionalAd title or campaign name
publisherstringOptionalAdvertiser or publisher serving the ad
total_lengthnumberOptionalDuration of the ad in seconds
positionnumberOptionalPlayback position within the content when the ad started
load_typestringOptionalAd 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'
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
asset_idstringOptionalIdentifier for the completed ad
pod_idstringOptionalIdentifier 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
})
PropertyTypeRequiredDescription
session_idstringRequiredPlayback session identifier
asset_idstringOptionalIdentifier for the skipped ad
positionnumberOptionalPosition 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
})
PropertyTypeRequiredDescription
session_idstringRequiredUnique identifier for this audio playback session
asset_idstringOptionalUnique identifier for the audio asset
titlestringOptionalTrack or episode title
artiststringOptionalArtist, host, or creator name
albumstringOptionalAlbum, show, or series name
genrestringOptionalGenre classification
durationnumberOptionalTotal duration of the audio asset in seconds
positionnumberOptionalPlayback 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
})
PropertyTypeRequiredDescription
session_idstringRequiredAudio playback session identifier
positionnumberOptionalPlayback 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
})
PropertyTypeRequiredDescription
session_idstringRequiredAudio playback session identifier
asset_idstringOptionalIdentifier for the completed audio asset
durationnumberOptionalTotal 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'
})
PropertyTypeRequiredDescription
show_idstringRequiredUnique identifier for the podcast show
show_titlestringOptionalDisplay title of the podcast show