Roku media tracking (v2)
Media tracking has multiple versions of schemas available. This document is for version 2 of the schemas; tracker versions earlier than v0.3.0 only support v1 tracking.
The Snowplow media tracking APIs enable you to track events from media playback on the web and in mobile apps. Track changes in playback state (play, pause, seek), playback position (ping and percentage progress events), and ad playback (ad breaks, ad progress, ad clicks).
For details on the events and entities tracked, see the media tracking overview.
See the tracked media events and entities live as you watch a video in our React example app. View the source code.
Quick start
A media tracking session follows this lifecycle:
- Start tracking when the player loads (before playback begins)
- Update player state every second during playback
- Track events as they occur (play, pause, seek, etc.)
- End tracking when the user leaves
' 1. Start tracking when player loads (events are auto-tracked)
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
label: "My Video Title"
}
' 2-3. Player state and events are automatically tracked from the Video node
' 4. End tracking when done
m.global.snowplow.disableMediaTracking = {
media: m.Video
}
Configuration
Configure media tracking when you call startMediaTracking. All configuration is optional.
Player properties
Set initial player properties to populate the media player entity. The label property is recommended as it helps identify content during analysis.
The Roku tracker automatically reads most player properties from the Audio/Video node. Configure additional options in enableMediaTracking:
m.global.snowplow.enableMediaTracking = {
media: m.Video, ' Audio/Video node to track (required)
version: 2, ' Schema version (defaults to 2)
id: "session-123", ' Custom session ID (auto-generated if not set)
label: "My Video", ' Human-readable title for the media_player entity
rokuVideoContext: true ' Whether to include the roku_video_context entity
}
Ping events
Media ping events are sent at regular intervals (default: 30 seconds) to report playback position. You can configure ping behavior in the starting configuration.
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
pings: true, ' Enabled by default
pingInterval: 30 ' Seconds between pings (default: 30)
}
' Or turn off pings entirely
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
pings: false
}
Percentage progress
Track events when playback reaches specified percentage boundaries.
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
boundaries: [25, 50, 75] ' By default, the tracker will fire events at these percentages
}
Session tracking
The media session entity is attached to all media events by default. It's optional for the Media Player data model, so you could choose not to include it.
We recommend tracking this entity.
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
sessions: true
}
Custom entities
You can attach custom entities to all events for this media tracking instance.
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
entities: [
{
schema: "iglu:com.example/video_metadata/jsonschema/1-0-0",
data: {"contentId": "abc123", "category": "tutorial"}
}
]
}
Filter events
Only track specific event types by providing an allowlist:
m.global.snowplow.enableMediaTracking = {
media: m.Video,
version: 2,
captureEvents: ["play", "pause", "end"]
}
Tracking events
Track events by calling the appropriate function when player events occur. For a complete list of available events and their properties, see the media events reference.
Playback events
The Roku tracker automatically tracks the following events from Audio/Video nodes:
- Ready, play, pause, end events
- Seek start, seek end events
- Ping events
- Percent progress events (if configured)
- Buffer start, buffer end events
- Quality change events
- Error events
To track events manually or track events not auto-tracked, use trackMediaEvent:
m.global.snowplow.trackMediaEvent = {
media: m.Video,
schema: "iglu:com.snowplowanalytics.snowplow.media/ad_click_event/jsonschema/1-0-0",
data: { "percentProgress": 50 }
}
Player state events
m.global.snowplow.trackMediaEvent = {
media: m.Video,
schema: "iglu:com.snowplowanalytics.snowplow.media/playback_rate_change_event/jsonschema/1-0-0",
data: { "newRate": 1.5 }
}
m.global.snowplow.trackMediaEvent = {
media: m.Video,
schema: "iglu:com.snowplowanalytics.snowplow.media/volume_change_event/jsonschema/1-0-0",
data: { "newVolume": 80 }
}
Ad events
Track advertising events with ad and ad break information. See the media ad and media ad break entity schemas for property details.
' Ad break start
m.global.snowplow.trackMediaEvent = {
media: m.Video,
schema: "iglu:com.snowplowanalytics.snowplow.media/ad_break_start_event/jsonschema/1-0-0",
data: {},
adBreak: {
"breakId": "break-1",
"name": "pre-roll",
"breakType": "linear",
"podSize": 3
}
}
' Ad start
m.global.snowplow.trackMediaEvent = {
media: m.Video,
schema: "iglu:com.snowplowanalytics.snowplow.media/ad_start_event/jsonschema/1-0-0",
data: {},
ad: {
"adId": "ad-1",
"name": "Product Ad",
"duration": 30
}
}
Custom events
Track custom self-describing events within the media session. The tracker automatically attaches media entities.
m.global.snowplow.trackMediaEvent = {
media: m.Video,
schema: "iglu:com.example/video_interaction/jsonschema/1-0-0",
data: { "action": "share", "platform": "twitter" }
}
Update player state
Manual player state updates aren't needed for the Roku tracker. The tracker automatically tracks player state from the registered media node.
Roku video entity
By default, the Roku tracker attaches a video entity to all media events.
video
EntityExample
{
"videoId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"contentId": "movie-12345",
"contentTitle": "Sample Movie",
"contentType": "movie",
"streamFormat": "mp4",
"measuredBitrate": 5000000,
"streamBitrate": 4500000,
"videoFormat": "hevc",
"timeToStartStreaming": 1.5,
"width": 1920,
"height": 1080
}
Properties and schema
- Table
- JSON schema
| Property | Description |
|---|---|
videoIdstring | Required. ID generated when video tracking of the video node was initialized. |
contentIdstring | Optional. ID of video provided in content metadata. |
contentTitlestring | Optional. Title of video provided in content metadata. |
contentUrlstring | Optional. URL of video provided in content metadata. |
contentTypestring | Optional. Category of video (e.g., movie, season, series) provided in content metadata. |
streamFormatstring | Optional. Container format of video (e.g., mp4, wma, mkv) provided in content metadata. |
streamUrlstring | Optional. URL of the current stream. |
measuredBitrateinteger | Optional. Measured bitrate (bps) of the network when the stream was selected. |
streamBitrateinteger | Optional. Current bitrate of the stream. |
isUnderrunboolean | Optional. Indicates whether the stream was downloaded due to an underrun. |
isResumedboolean | Optional. Indicates whether the playback was resumed after trickplay. |
videoFormatstring | Optional. Video codec of the currently playing video stream (e.g., hevc, mpeg2, mpeg4_15). |
timeToStartStreamingnumber | Optional. Time in seconds from playback being started until the video actually began playing. |
widthinteger | Required. Width of the video play window in pixels. 0 if the play window is set to the width of the entire display screen. |
heightinteger | Required. Height of the video play window in pixels. 0 if the play window is set to the height of the entire display screen. |
errorStrstring | Optional. A diagnostic message indicating a video play error. Refer to the Roku Video documentation for the format of the string. |
{
"$schema": "http://iglucentral.com/schemas/com.snowplowanalytics.self-desc/schema/jsonschema/1-0-0#",
"description": "Schema for a Roku video event (reflects the Video node: https://developer.roku.com/en-gb/docs/references/scenegraph/media-playback-nodes/video.md)",
"self": {
"format": "jsonschema",
"name": "video",
"vendor": "com.roku",
"version": "1-0-0"
},
"type": "object",
"properties": {
"videoId": {
"type": "string",
"description": "ID generated when video tracking of the video node was initialized.",
"maxLength": 255
},
"contentId": {
"type": [
"string",
"null"
],
"description": "ID of video provided in content metadata.",
"maxLength": 255
},
"contentTitle": {
"description": "Title of video provided in content metadata.",
"type": [
"string",
"null"
],
"maxLength": 65535
},
"contentUrl": {
"description": "URL of video provided in content metadata.",
"type": [
"string",
"null"
],
"maxLength": 65535,
"format": "uri"
},
"contentType": {
"description": "Category of video (e.g., movie, season, series) provided in content metadata.",
"type": [
"string",
"null"
],
"maxLength": 255
},
"streamFormat": {
"description": "Container format of video (e.g., mp4, wma, mkv) provided in content metadata.",
"type": [
"string",
"null"
],
"maxLength": 255
},
"streamUrl": {
"type": [
"string",
"null"
],
"description": "URL of the current stream.",
"maxLength": 65535,
"format": "uri"
},
"measuredBitrate": {
"type": [
"integer",
"null"
],
"description": "Measured bitrate (bps) of the network when the stream was selected.",
"minimum": 0,
"maximum": 2147483647
},
"streamBitrate": {
"type": [
"integer",
"null"
],
"description": "Current bitrate of the stream.",
"minimum": 0,
"maximum": 2147483647
},
"isUnderrun": {
"type": [
"boolean",
"null"
],
"description": "Indicates whether the stream was downloaded due to an underrun."
},
"isResumed": {
"type": [
"boolean",
"null"
],
"description": "Indicates whether the playback was resumed after trickplay."
},
"videoFormat": {
"type": [
"string",
"null"
],
"description": "Video codec of the currently playing video stream (e.g., hevc, mpeg2, mpeg4_15).",
"maxLength": 255
},
"timeToStartStreaming": {
"type": [
"number",
"null"
],
"description": "Time in seconds from playback being started until the video actually began playing.",
"minimum": 0,
"maximum": 9007199254740991
},
"width": {
"type": "integer",
"description": "Width of the video play window in pixels. 0 if the play window is set to the width of the entire display screen.",
"minimum": 0,
"maximum": 65535
},
"height": {
"type": "integer",
"description": "Height of the video play window in pixels. 0 if the play window is set to the height of the entire display screen.",
"minimum": 0,
"maximum": 65535
},
"errorStr": {
"type": [
"string",
"null"
],
"description": "A diagnostic message indicating a video play error. Refer to the Roku Video documentation for the format of the string.",
"maxLength": 65535
}
},
"required": [
"videoId",
"width",
"height"
],
"additionalProperties": false
}
Migrating from media v1 APIs
If you are migrating from the v1 media tracking, v2 has compatibility options to make the change easier.
For backwards compatibility with the earlier tracking API, you can continue using enableVideoTracking or enableAudioTracking instead of enableMediaTracking, and pass the node via the audio/video option instead of media.
For most other options, v2 will accept either v1 or v2 roAssociativeArray formats.
The tracking will work with any combination of these method and option names regardless of node type, as long as version: 2 is specified.
You can also specifically opt into version 1 by passing version: 1 for any of these methods, though v2 options may not be recognized.
If using specific version values, the same version should also be specified for the corresponding disable*Tracking method.
Similarly, mixing enableVideoTracking and disableMediaTracking will not work unless versions are specified consistently.
The additional options differ by version; but version 2 will accept the options from version 1 if it can't find the newer equivalent settings.
| v2 Attribute | v1 Fallback | Type | Description |
|---|---|---|---|
media / audio / video | media / audio / video | Audio / Video | Audio/Video node to be tracked |
version | version | Integer | Tracking schema version to use; should be set to 2 if not using enableMediaTracking |
id | N/A | UUID | A unique ID to use for the media session entity to group all tracked events |
label | options.label | String | An identifiable custom label sent with the event in the media_player entity |
sessions | Default enabled | boolean | Whether to attach the media session entity on tracked events |
pings | Default enabled | boolean | Whether to periodically generate media ping_events while content is playing |
pingInterval | options.positionInterval | Integer | Interval in seconds in which ping_events should be reported |
boundaries | options.boundaries | Integer[] | Percentage boundaries in playback for which percentage_progress_events will be sent |
captureEvents | options.captureEvents | String[] | Types of events to capture. If specified, the event names should not have the _event suffix |
context / entities | context | SelfDescribingJSON[] | Array of custom entities to include with all generated events |