Skip to main content

Media Tracking

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

Installation

  • npm install @snowplow/browser-plugin-media-tracking
  • yarn add @snowplow/browser-plugin-media-tracking
  • pnpm add @snowplow/browser-plugin-media-tracking

Initialization

import { newTracker, trackPageView } from '@snowplow/browser-tracker';
import { MediaTrackingPlugin, enableMediaTracking } from '@snowplow/browser-plugin-media-tracking';

newTracker('sp1', '{{collector_url}}', {
appId: 'my-app-id',
plugins: [ MediaTrackingPlugin() ],
});

enableMediaTracking(/* options */);

Quick Start

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

index.html

<html>
<head>
<title>Snowplow Media Tracking Example</title>
</head>
<body>
<video id='example-id' src='./example-video.mp4'></video>
</body>
</html>

main.js

import { enableMediaTracking } from '@snowplow/browser-plugin-media-tracking'

enableMediaTracking({
id: 'example-id'
})

The enableMediaTracking function

The enableMediaTracking function takes the form:

enableMediaTracking({ 
id,
options?: {
label?,
captureEvents?,
boundaries?,
volumeChangeTrackingInterval?
}
})
ParameterTypeDefaultDescriptionRequired
idstring-The HTML id attribute of the media elementYes
options.labelstring-An 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:

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

Usage

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

Case 1

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

index.html

<video id='example-id'></video>

main.js

enableMediaTracking({
id: 'example-id'
})

Case 2

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

index.html

<div id='example-id'>
<video src='./example-video.mp4'></video>
</div>

main.js

enableMediaTracking({
id: 'example-id'
})

Events

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 HTMLMediaElement.play() 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.

Note

Not all events are available in all browsers (though most are). To check, use the following links:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement#browser_compatibility

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#browser_compatibility

Event Groups

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

NameEvents
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 if you want all the events contained in the 'DefaultEvents' group, along with the 'emptied' event (for example). This could be expressed in the following way:

enableMediaTracking({
id: 'example-video',
options: {
captureEvents: ['DefaultEvents', 'emptied'],
}
})

Schemas and Example Data

Four schemas are used with this plugin:

An unstructured event with identifying information

{
"type": "play",
"label": "Identifying Label"
}

Snowplow platform-agnostic media context

{
"currentTime": 12.32,
"duration": 20,
"ended": false,
"loop": false,
"muted": true,
"paused": false,
"playbackRate": 1,
"volume": 100
}

HTML5 Media specific context

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

HTML5 Video specific context

{
"autoPictureInPicture": false,
"disablePictureInPicture": false,
"poster": "http://www.example.com/poster.jpg",
"videoHeight": 300,
"videoWidth": 400
}

Note

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

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement#browser_compatibility

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#browser_compatibility

Video Frameworks

This plugin has been tested with VideoJS and Plyr, but should work with almost any player framework that results in a <video> or <audio> element). You may find that some frameworks render out in a way that means the id given to the component doesn't exist in the actual DOM.


  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.

Was this page helpful?