# Roku media tracking (v2)
> Track Roku media playback with v2 schemas including session entities, ping events, and percentage progress tracking for audio and video nodes.
> Source: https://docs.snowplow.io/docs/sources/roku-tracker/media-tracking/v2/
> Documentation index: https://docs.snowplow.io/llms.txt

> **Note: Media version 2**
>
> Media tracking has [multiple versions](/docs/sources/web-trackers/tracking-events/media/) of schemas available. This document is for version 2 of the schemas; tracker versions earlier than v0.3.0 [only support v1 tracking](/docs/sources/roku-tracker/media-tracking/v1/).

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](/docs/events/ootb-data/media-events/).

> **Info: Example app**
>
> See the tracked media events and entities live as you watch a video in our [React example app](https://snowplow-industry-solutions.github.io/snowplow-javascript-tracker-examples/media). [View the source code](https://github.com/snowplow-industry-solutions/snowplow-javascript-tracker-examples/tree/master/react).

## Quick start

A media tracking session follows this lifecycle:

1. **Start tracking** when the player loads (before playback begins)
2. **Update player state** every second during playback
3. **Track events** as they occur (play, pause, seek, etc.)
4. **End tracking** when the user leaves

```brightscript
' 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](/docs/events/ootb-data/media-events/#media-player). 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`:

```brightscript
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.

```brightscript
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.

```brightscript
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](/docs/events/ootb-data/media-events/#media-session) is attached to all media events by default. It's optional for the [Media Player](/docs/modeling-your-data/modeling-your-data-with-dbt/dbt-models/dbt-media-player-data-model/) data model, so you could choose not to include it.

We recommend tracking this entity.

```brightscript
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.

```brightscript
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:

```brightscript
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](/docs/events/ootb-data/media-events/#playback-lifecycle-events).

### 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`:

```brightscript
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

```brightscript
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](/docs/events/ootb-data/media-events/#media-ad) and [media ad break](/docs/events/ootb-data/media-events/#media-ad-break) entity schemas for property details.

```brightscript
' 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.

```brightscript
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`

**Type:** Schema

Schema for a Roku video event (reflects the Video node: https\://developer.roku.com/en-gb/docs/references/scenegraph/media-playback-nodes/video.md)

**Properties:**

| Property                        | Description                                                                                                                         |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `videoId` _string_              | _Required._ ID generated when video tracking of the video node was initialized.                                                     |
| `contentId` _string_            | _Optional._ ID of video provided in content metadata.                                                                               |
| `contentTitle` _string_         | _Optional._ Title of video provided in content metadata.                                                                            |
| `contentUrl` _string_           | _Optional._ URL of video provided in content metadata.                                                                              |
| `contentType` _string_          | _Optional._ Category of video (e.g., movie, season, series) provided in content metadata.                                           |
| `streamFormat` _string_         | _Optional._ Container format of video (e.g., mp4, wma, mkv) provided in content metadata.                                           |
| `streamUrl` _string_            | _Optional._ URL of the current stream.                                                                                              |
| `measuredBitrate` _integer_     | _Optional._ Measured bitrate (bps) of the network when the stream was selected.                                                     |
| `streamBitrate` _integer_       | _Optional._ Current bitrate of the stream.                                                                                          |
| `isUnderrun` _boolean_          | _Optional._ Indicates whether the stream was downloaded due to an underrun.                                                         |
| `isResumed` _boolean_           | _Optional._ Indicates whether the playback was resumed after trickplay.                                                             |
| `videoFormat` _string_          | _Optional._ Video codec of the currently playing video stream (e.g., hevc, mpeg2, mpeg4\_15).                                       |
| `timeToStartStreaming` _number_ | _Optional._ Time in seconds from playback being started until the video actually began playing.                                     |
| `width` _integer_               | _Required._ Width of the video play window in pixels. 0 if the play window is set to the width of the entire display screen.        |
| `height` _integer_              | _Required._ Height of the video play window in pixels. 0 if the play window is set to the height of the entire display screen.      |
| `errorStr` _string_             | _Optional._ A diagnostic message indicating a video play error. Refer to the Roku Video documentation for the format of the string. |

## Migrating from media v1 APIs

If you are migrating from the [v1 media tracking](/docs/sources/roku-tracker/media-tracking/v1/), 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_event`s while content is playing                 |
| `pingInterval`              | `options.positionInterval`  | Integer               | Interval in seconds in which `ping_event`s should be reported                                 |
| `boundaries`                | `options.boundaries`        | Integer\[]            | Percentage boundaries in playback for which `percentage_progress_event`s 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                                 |
