Detailed Video Engagement Analytics for HTML5 Video
Published: 2012-12-27 08:35:31 -0500
Updated: 2012-12-27 08:41:31 -0500
If you have published video on the Web with HTML5 Video, then you will want to know how engaged your viewers are with your video. This post will lead you through collecting the data you need to assess your video publishing efforts. Services like Google Analytics only get you so far. To get deeper insights into how your video is being used, you may want to track detailed video engagement analytics.
If you’ve not published video with HTML5 Video yet, then you may want to read everything I know about HTML5 Video and then return here.
I’ll try to update this post as I learn better ways to do video analytics or make corrections to the examples given here.
Video Play Page
For a very basic understanding of how folks are using your video, you will first want to track views of your video play pages. If folks aren’t even getting to your video play pages, they do not even have the chance of engaging with your video.
Remember that it is best for search engines like Google if your video plays only on a single page. This makes implementation easier since every video will have one and only one page from which it can be played. This makes it easy to track video play pages.
I won’t cover how to set up something like Google Analytics page view tracking.
What I can show you is how to begin to track various video-related events like clicks on the play and pause controls. If you are just using the browser’s native controls, they may not expose elements which you can bind event listeners to. So instead we will listen for the
pause events of the
pause events just the same.
We’ll begin with this demo and extend it to add this simple event tracking.
First, we’ll create a simple object to hold our
track function. All we need to send into the
track function is the action we want to track. In the
track function we’ll just log the tracking parameters to the browser’s console. If we were really implementing this we would replace the “console.log()” line with however you queue up a tracking event with whatever analytics program you’re using.
We will, though, model the parameters sent to the tracking function on the parameters used for Google Analytics event tracking. The parameters in order then will be category, action, and label. The category will always be “Videos”. The action will be “Play” or “Pause”. The value will always be the identifier for the video. We’ll determine the video by taking the current source of the video and removing the extension.
One thing you’ll notice is that we are wrapping everything within a event handler for “loadedmetadata”. We only want to apply any of this if there is a video element on the page and the video actually loads its metadata. This means that you can use
video.currentSrc to determine the current video file URL.
You can try this tracking function out in the console as follows:
Now to track the
pause events, we can add simple event handlers like the following. While we’re at it we can track whether the
ended event is fired. This will tell us that a viewer got to the end of the video but it will not tell us that they have actually watched the whole video. We can also track the
seeked event. When the current time is set the
seeked event fires. It also gets triggered when a user clicks on the time rail control.
Interpreting Simple Events
When looking at your analytics for these kinds of simple events, there are some things to keep in mind. The
pause event fires just before the
ended event (at least in Chrome and Firefox). It is unclear in the spec whether this doubling of events is correct or not. What this means, though, is that a
pause event does not necessarily mean that someone took an action to pause the video. To tell the number of
pause events that are real user interactions, you may have to subtract the number of
Note the meaning of the
ended event. This event tells us that a viewer got to the end of the video but it will not tell us that they have actually watched the whole video. The user could have clicked the time rail or chapters (from a
<track> polyfill) to seek ahead or used some other control on the page to get near the end, possibly skipping most of the content.
But just tracking these kinds of events does not give us the full picture. Do visitors watch the whole video or do they drop off or go somewhere else on your site before finishing the video? How much of the video do visitors actually watch? How far do they get through the video? Is there a particular point in the video where most users have dropped off? Are there portions of a video that are watched more often than others? Are parts skipped? What we really want to know about is video engagement. Answering these questions can help determine whether there are ways that you might make your video more engaging.
It will take more information than just play and pause events to get at this data. We need more detailed information about how the video is being watched.
Simplistic Video Engagement
Some have suggested a way to track video engagement with Google Analtyics. The basic idea is that the time of the video can be divided into equal parts. If a 100 second video is divided into 10 parts then once the video plays the 10th second it triggers a tracking event that “10%”“ of the video has been played. The same if the 90th second is played, then "90%” is recorded in the tracking event. (Here is an example of this approach.)
As standards like Media Fragments get implemented, it will be easier to deep link into videos similarly to how you can link to a section of a page that has an
id attribute. So a user may begin a video in the middle depending on the URI they follow.
The current problem with these simple analytics schemes is that visitors can jump around arbitrarily through a video by clicking anywhere on the time rail. If the video has an associated chapter track then the user can also jump to a specific section of the video. Just because the second at 80% of the video has been played does not mean that 80% of the video has actually been viewed.
Deeper Video Engagement
I want more information than that the second at 80% of the video has been played. The most exact way to get at that information is by keeping track of which seconds have actually been played. Let’s look at what it takes to implement some deeper analytics tracking.
Rather than keeping a tally of discreet events on the page or faulty engagement analytics, we want to track the ranges of time within each video that have been watched during a particular visitor page view session. So the data we want to collect is the identifier for the video, an identifier for a particular visitor page view session, the current date-time of the tracker, and the ranges of time that have been watched within that session. Let’s unpack each of those a bit.
To aggregate all of the data about a particular video, we want to have a unique identifier for the video. We could use and munge the current video source to supply that identifier like we have above. There we just took the URL for the video and stripped off the last 3 characters (the dot and extension). In my own applications, I could do that because I can be certain that it will easily map to a unique video.
It may be that your video is hosted somewhere else and the URL of the video file will not provide the identifier you would want. For our engagement analytics we’ll change our approach and I’ll add a data- attribute
engagement object within the module VideoAnalytics) we can set the variable for the current video identifier.
Page View Session
To make sure that we are tracking a single page view we need to create a page view session. I do not want to track a bunch of other data about users. I just want to know how much of a video is watched within a particular page view. If you wanted to associate what videos a user watched you could do more server side using a cookie-based session, but I will leave that and other server-side work to the reader.
Creating a timestamp for the tracking event is as simple as
The last piece of data that we need is what parts of the video are actually watched. Luckily HTML5 Video provides a straightforward way to get at exactly which parts of a video (or audio) have been played.
The media elements API provides a
played property for a
video element that returns a
TimeRanges object. Since users can click on the time rail to jump around a video, there may be more than one range which has been played. Reload the demo page, and then run the following script in your console to simulate a user starting to play a video from the beginning and then jumping to near the end.
currentTime setter allows us to jump in time to a point towards the end of our example video. A
TimeRanges object has a
length property which returns the total number of time ranges it contains. Each time range can then be retrieved with indexing starting at zero. A
TimeRanges object has
end methods which must be passed the index of the time range you want. You can see that time ranges are zero based.
Here a function to turn a
TimeRanges object into an array of objects. Each object will have the appropriate seconds value for each start and end key.
The result from this
time_ranges_to_array function will look something like this for our “a look at TimeRanges” script above:
Now we have all the pieces we need in order to track time ranges. We can attach event listeners for various events to send the tracking data. To make sure that we capture most of the use we will send the data to the server every so often by listening for the
timeupdate event. The
timeupdate event can be triggered much more often than every second. If you’re looking at our example, you’ll see in the console that every time the
timeupdate event it fired that the current time gets output to the console. There are also differences between browsers. Chrome seems to trigger the
timeupdate event 8 times a second, while Firefox appears to only fire the event 4 times every second.
We set and increment a counter so that every N times (25 in our example) the
timeupdate event fires, the tracking data is sent (in our case logged to the console). This prevents us from posting data to the server up to 8 times a second needlessly. Delaying by 25
timeupdates may be too few, so adjust to something where you’re ensuring that you’re not dropping data if someone closes a tab, but you’re also not sending data too frequently.
We also will listen for
The demo does not POST data to a server, but just outputs the data to the console. Open up your developers tools console, start and stop the video, click around the time rail, and see what data gets created. It would be trivial for us to change this to use jQuery to POST the data.
The result is that we can use this data to graph out engagement. Within an administrative console for one of my sites, I have embedded the video into the page along with a chart created with D3.js. As the video plays the line of the current time moves along the chart. Since I can watch the video alongside the chart, I can see exactly when visitors start to drop off. To show how it works, here’s an video with dummy data:
While this seems to work across browsers that understand the
video element, you are likely to have a Flash fallback for older browsers or in the case that you only encode to one codec. My favorite HTML5 video polyfill with Flash fallback is MediaElement.js. The player has an API which allows you to work consistently across HTML5 video and Flash fallback using something similar to the standard API, but it does not implement the
played property. (Do you know a polyfill which does implement
played for its Flash fallback?) This means that you would have to come up with a different solution for the Flash fallback player if you receive traffic from older browsers.
What I have done in one application to work around this limitation is to duplicate the functionality of
TimeRanges. Each time the
timeupdate event fires, I collect the current time into a array. Every so often I send this array of seconds to the server and also clear out the array so it does not get too big. This seems to work well enough, but would likely have some performance problems.
It is relatively simple with the HTML5 video API to hook into video events for video engagement analytics. The main problem is coming up with a solution that works on older browsers using a Flash fallback.
What other questions would you like to answer about your videos? What data would you need to answer those questions? As I launch the video site I’ve worked on and take a look at the analytics we’re already grabbing, I may have the opportunity to expand on my work and this post. I’d be interested to hear what your use cases are for better video analytics.