Collecting data with Trackers and Webhooks

  1. Home
  2. Docs
  3. Collecting data with Trackers and Webhooks
  4. Trackers – collecting data from your own applications
  5. JavaScript Trackers (Web and Node.js)
  6. JavaScript Tracker
  7. JavaScript Tracker v3 Reference
  8. Plugins
  9. Media Tracking

Media Tracking

This plugin will allow the tracking of any HTML5 <video> or <audio> element, along with many HTML5 based video player frameworks.

Tracker DistributionIncluded


Download from GitHub Releases (Recommended)Github Releases (
Available on jsDelivrjsDelivr (latest)
Available on unpkgunpkg (latest)

Note: The links to the CDNs above point to the current latest version. You should pin to a specific version when integrating this plugin on your website if you are using a third party CDN in production.

Quick Start

To start tracking media with default settings, use the snippet below, using your id and source:


window.snowplow('addPlugin', "", ["snowplowMediaTracking", "MediaTrackingPlugin"] ); window.snowplow('enableMediaTracking', { id: 'example-id' })
Code language: JavaScript (javascript)


<html> <head> <title>Snowplow Media Tracking Example</title> </head> <body> <video id='example-id' src='./example-video.mp4'></video> </body> </html>
Code language: HTML, XML (xml)

The enableMediaTracking function

The enableMediaTracking function takes the form:

window.snowplow('enableMediaTracking', { id, options?: { label?, captureEvents?, boundaries?, volumeChangeTrackingInterval? } })
Code language: JavaScript (javascript)
idstringThe HTML id attribute of the media elementYes
options.labelstringAn identifiable custom label sent with the eventNo
options.captureEventsstring[]['DefaultEvents']The events or Event Group to capture. For a full list of events and groups, check the section belowNo
options.boundariesnumber[][10, 25, 50, 75]The progress percentages to fire an event at (valid values 1 – 99 inclusive) [1]No
options.volumeChangeTrackingIntervalnumber250The rate at which volume events can be sent [2]No

Below is an example of the full enableMediaTracking function:

window.snowplow('enableMediaTracking', { id: 'example-video', options: { label: 'My Custom Video Label', captureEvents: ['play', 'pause', 'ended'], boundaries: [20, 80], volumeChangeTrackingInterval: 200, } }
Code language: JavaScript (javascript)


For this plugin to find your media element, one of the following conditions must be true:

The <audio> or <video> element has the HTML id passed into enableMediaTracking


... <body> <video id='example-id' src='./example-video.mp4'></video> <script> window.snowplow('enableMediaTracking', { id: 'example-id' }) </script> </body> ...
Code language: HTML, XML (xml)


The media element is the only <audio> or <video> child of a parent element with the HTML id passed into enableMediaTracking


... <body> <div id="example-id"> <video id='example-id' src='./example-video.mp4'></video> </div> <script> window.snowplow('enableMediaTracking', { id: 'example-id' }) </script> </body> ...
Code language: HTML, XML (xml)


Capturable Events

Below is a table of all the events that can be used in options.captureEvents

NameFire Condition
abortThe resource was not fully loaded, but not as the result of an error.
canplayThe user agent can play the media, but estimates that not enough data has been loaded to play the media up to its end without having to stop for further buffering of content
canplaythroughThe user agent can play the media, and estimates that enough data has been loaded to play the media up to its end without having to stop for further buffering of content.
durationchangeThe duration attribute has been updated.
emptiedThe media has become empty; for example, when the media has already been loaded (or partially loaded), and the HTMLMediaElement.load() method is called to reload it.
endedWhen playback stops when end of the media (<audio> or <video>) is reached or because no further data is available.
errorThe resource could not be loaded due to an error.
loadeddataThe first frame of the media has finished loading.
loadedmetadataThe metadata has been loaded
loadstartThe browser has started to load a resource.
pauseWhen a request to pause play is handled and the activity has entered its paused state, most commonly occurring when the media’s HTMLMediaElement.pause() method is called.
playThe paused property is changed from true to false, as a result of the method, or the autoplay attribute
playingWhen playback is ready to start after having been paused or delayed due to lack of data
progressFired periodically as the browser loads a resource.
ratechangeThe playback rate has changed.
seekedWhen a seek operation completes
seekingWhen a seek operation begins
stalledThe user agent is trying to fetch media data, but data is unexpectedly not forthcoming.
suspendThe media data loading has been suspended.
timeupdateThe time indicated by the currentTime attribute has been updated.
volumechangeThe volume has changed.
waitingWhen playback has stopped because of a temporary lack of data.
enterpictureinpictureWhen the element enters picture-in-picture mode
leavepictureinpictureWhen the element leaves picture-in-picture mode
fullscreenchangeFired immediately after the browser switches into or out of full-screen. mode.
cuechangeWhen a text track has changed the currently displaying cues.
percentprogressWhen a percentage boundary set in options.boundaries is reached.

Event Groups

You can also use a pre-made event group in options.captureEvents:

DefaultEvents['pause', 'play', 'seeked', 'ratechange', 'volumechange', 'ended', 'fullscreenchange', 'percentprogress']
AllEventsEvery event listed in Capturable Events

It is possible to extend an event group with any event in the Events table above. This could be useful, for example, if you want all the events contained in the ‘DefaultEvents’ group, along with the ’emptied’ event. This is expressed in the following way:

window.snowplow('enableMediaTracking', { id: 'example-video', options: { captureEvents: ['DefaultEvents', 'emptied'], } })
Code language: JavaScript (javascript)

Schemas and Example Data

Four schemas are used with this plugin:

An unstructured event with identifying information

{ "type": "play", "label": "Identifying Label" }
Code language: JSON / JSON with Comments (json)

Snowplow platform-agnostic media context

{ "currentTime": 12.32, "duration": 20, "ended": false, "loop": false, "muted": true, "paused": false, "playbackRate": 1, "volume": 100 }
Code language: JSON / JSON with Comments (json)

HTML5 Media specific context

{ "htmlId": "my-video", "mediaType": "VIDEO", "autoPlay": false, "buffered": [ { "start": 0, "end" : 20 } ], "controls": true, "currentSrc": "", "defaultMuted": true, "defaultPlaybackRate": 1, "disableRemotePlayback": false, "error": null, "networkState": "IDLE", "preload": "metadata", "readyState": "ENOUGH_DATA", "seekable": [ { "start": 0, "end" : 20 } ], "seeking": false, "src": "", "textTracks": [ { "label": "English", "language": "en", "kind": "captions", "mode": "showing", }, ], "fileExtension": "mp4", "fullscreen": false, "pictureInPicture": false }
Code language: JSON / JSON with Comments (json)

HTML5 Video specific context

{ "autoPictureInPicture": false, "disablePictureInPicture": false, "poster": "", "videoHeight": 300, "videoWidth": 400 }
Code language: JSON / JSON with Comments (json)


Not all properties in the HTML5 Media/Video specific schemas will be available on all browsers. Use the following links to check availability:

Video Frameworks

This plugin has been tested with VideoJS and Plyr, but should work with almost any player framework that results in a <video> element).

  1. To track when a video ends, use the ‘ended’ event. 

2. When holding and dragging the volume slider, ‘volumechange’ events would be fired extremely quickly. This is used to limit the rate they can be sent out at. The default value is likely to be appropriate, but you can adjust it if you find you want fewer/more volume events through.

If you’d like to learn more about Snowplow BDP you can book a demo with our team, or if you’d prefer, you can try Snowplow technology for yourself quickly and easily.