Videos are now the standard for businesses who want to convey their messages to customers in a short concise way. However, they are expensive (well, at least the good ones are) and if you’re pouring money & time into a video for your site it’s important to see how people are using it or when it goes down. This post is going to go over how to approach the YouTube JavaScript API. There are lots of other tutorials and code snippets that can help you track youtube video but I am still seeing sites that aren’t using it AND I believe that it is important to understand how everything works– so this is my attempt to get you up to speed even if you’re not heavily technical. Additionally, I believe my solution is a little different then the other ways video’s have been tracked plus I go over some ways to calculate new metrics and track errors with the video player.
To track video with Google Analytics you need to connect event tracking to the actions that are taken on the player. Most of the mainstream video players allow you to do this with the player API. I will be using the Player API for iframe Embeds and showing how to hook it up with normal GA code and through GTM
Links to the 2 player API’s:
YouTube Player API Reference for iframe Embeds
YouTube JavaScript Player API Reference
Jump to the GTM implementation you can click here but skim through the JS implementation because that is where I explain the functions.
First we need to create a div that will act as the container for us to place the YouTube iFrame in.
<div id='player'></div>
Then with in an HTML script tag we add JavaScript and load the iframe player API code asynchronously.
var tag = document.createElement('script'); tag.src = 'https://www.youtube.com/iframe_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
Create a new player object with the height (video.h), width(video.w), and VideoID that you want played and declare the events you are going to use. There are other events that are apart of the YouTube API but for this example we are only going to add onStateChange and onError. There are other player events that you can listen for like Player Quality Change and Volume Change, you can read about those here.
var player; var video = 'YOUR_VIDEO_ID' video.h = '390' //video iframe height video.w = '640' //video iframe width function onYouTubeIframeAPIReady() { player = new YT.Player('player', { height: video.h, width: video.w, videoId: video, events: { 'onStateChange': onPlayerStateChange, 'onError': onPlayerError } }); };
onStateChange tracks when the player switches from different player states like play, pause and end. This is the main method that we will be using for our video tracking. The value that the API passes to your event listener function will specify an integer that corresponds to the new player state.
You can specify the numeric values above or you can use one of the following namespaced variables:
In my examples below I will be using the namespace values.
onError event triggers when their is an error with the youtube iframe player like if the video isn’t loading. This is great for QA and site redesigns knowing which videos are broken on your site.
When the error occurs the API passes a numeric value that represents the error. Below are a list of the errors:
This post is going over the basics of video tracking so the code is going to be… well, basic. I am planning to write posts in the future on more complex functions that I’ve created to analyze the video viewing behavior in different ways but I need to clean them up to make sense.
Here is the first function for onPlayerStateChange I want to call out 2 specific things with the youtube API that I accounted for/modded.
function onPlayerStateChange(event) { switch (event.data) { case YT.PlayerState.PLAYING: if (cleanTime() == 0) { //console.log('started ' + cleanTime()); ga('send', 'event', 'video', 'started', video); } else { //console.log('playing ' + cleanTime()) ga('send', 'event', 'video', 'played', 'v: ' + video + ' | t: ' + cleanTime()); }; break; case YT.PlayerState.PAUSED: if (player.getDuration() - player.getCurrentTime() != 0) { //console.log('paused' + ' @ ' + cleanTime()); ga('send', 'event', 'video', 'paused', 'v: ' + video + ' | t: ' + cleanTime()); }; break; case YT.PlayerState.ENDED: //console.log('ended '); ga('send', 'event', 'video', 'ended', video); break; }; }; //utility function cleanTime(){ return Math.round(player.getCurrentTime()) };
function onPlayerError (event) { switch(event.data) { case 2: //console.log('' + video.id) ga('send', 'event', 'video', 'invalid id',video); break; case 100: ga('send', 'event', 'video', 'not found',video); break; case 101 || 150: ga('send', 'event', 'video', 'not allowed',video); break; }; };
And now you’re tracking your video events! Continue reading if you want to see how it works with DTM.
If you are using Google Tag Manager you would want to set up 2 tags and 3 macros.
Create 3 new dataLayer macros, here is an example for eventCategory
Create one for eventAction and eventLabel the same way.
Create a new HTML Tag with the following rule:
Copy the following code to the HTML container. Notice that the code pushes all the video events to the dataLayer and then we grab them from the dataLayer and execute the GA tracking.
<script> //set video values var video = 'YOUR_VIDEO_ID_HERE' video.h = '390' video.w = '640' var player; var tag = document.createElement('script'); tag.src = 'http://www.youtube.com/player_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); function onYouTubePlayerAPIReady() { player = new YT.Player('player', { height: video.h, width: video.w, videoId: video, events: { 'onStateChange': onPlayerStateChange, 'onError': onPlayerError } }); } function onPlayerStateChange(event) { switch (event.data) { case YT.PlayerState.PLAYING: if (cleanTime() == 0) { dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'started', 'eventLabel': video }); } else { dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'played', 'eventLabel': 'v: ' + video + ' | t: ' + cleanTime() }); }; break; case YT.PlayerState.PAUSED: if (player.getDuration() - player.getCurrentTime() != 0) { dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'paused', 'eventLabel': 'v: ' + video + ' | t: ' + cleanTime() }); }; break; case YT.PlayerState.ENDED: dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'ended', 'eventLabel': video }); break; }; }; function onPlayerError(event) { switch (event.data) { case 2: dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'invalid id', 'eventLabel': video }) break; case 100: dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'not found', 'eventLabel': video }) break; case 101 || 150: dataLayer.push({ 'event': 'youtubeChange', 'eventCategory': 'video', 'eventAction': 'not allowed', 'eventLabel': video }) break; }; }; function cleanTime() { return Math.round(player.getCurrentTime()) }; </script>
Create a new Universal Analytics Tag with the following rule:
Set the track type to event and set the macros that we just made to the values of Event Category, Action, and Label.
And, boom. You’re tracking your video!
Once you have that tracking and all the data coming in you can use the Google Analytics Add-on extension to get the data in google sheets and do some cool stuff.
Here are some things you can learn:
* Note: The last 2 can’t be analyzed in GA right now because it requires making calculations or mods on the data.
I live in the Google Analytics Spreadsheets Add-on and highly suggest you check it out if you don’t have it installed. It’s great for pulling in data and doing your own calculations or customizing the data and dimension names to be more friendly.