Track YouTube Video Events and Checkpoints in Google Analytics using jQuery

Michael Roma on Mar 9, 2014

This post shows how to track user’s activity when viewing YouTube videos on your site. It can track when a user starts/stops/pauses a video, watches a video all the way through, and also tracks at different points 25%/50%/75%. I used example code from lunametrics that creates YouTube objects from any existing iframe plugins on the site. Reference: http://www.lunametrics.com @lunametrics.

First, first this to work - all iframe src value needs to contain the following:&enablejsapi=1&origin=http%3a%2f%2fwww.mroma.net. Where www.mroma.net would be the domain you are running your site on.

var tag = document.createElement(‘script’);
tag.src = “//www.youtube.com/iframe_api”;
var firstScriptTag = document.getElementsByTagName(‘script’)[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

var videoArray = new Array();
var playerArray = new Array();

// find all existing iframes, convert to youtube objects
(function (\() {
    function trackYouTube() {
        var i = 0;

        jQuery('iframe').each(function () {
            var video = \)(this);

            if (video.attr(‘src’) === undefined) {
                var vidSrc = “”;
            } else {
                var vidSrc = video.attr(‘src’);
            }

            var regex = /h?t?t?p?s?:?\/\/www.youtube.com\/embed\/([\w-]{11})(?:\?.*)?/;
            var matches = vidSrc.match(regex);

            if (matches && matches.length > 1) {
                videoArray[i] = matches[1];
                \((this).attr('id', matches[1]);
                i++;
            }            
        });
        onYouTubeIframeAPIReady();
    }

    \)(document).ready(function () {
        trackYouTube();
    });
})(jQuery);

// handle when iframe api is ready
function onYouTubeIframeAPIReady() {

    // check if already executed
    if (videoArray.length == 0 || playerArray.length > 0) {
        return;
    }
    
    // go through each video, get the player object
    for (var i = 0; i < videoArray.length; i++) {
        playerArray[i] = new YT.Player(videoArray[i], {
            events: {
                ‘onReady’: onPlayerReady,
                ‘onStateChange’: onPlayerStateChange
            }
        });
    }    
}

// youtube player ready
function onPlayerReady(event) { }

// youtube player state change
function onPlayerStateChange(event) {

    // track state change
    YouTubeTracking.checkStateChange(event);
}

Now that we have a player object for each YouTube video on the page, here is the code that tracks each event and tracks have checkpoints met. The checkpoints array contains which percents to check.

// define youtube tracking api
var YouTubeTracking = {

    // define checkpoints to track
    checkpointsToTrack: [25, 50, 75],

    // define player array
    players: [],

    // define pause flag
    _pauseFlag: false,


    // define interval id 
    intervalId: 0,

    // function that gets the player info, creates new if not exists
    get: function (id) {
        if (YouTubeTracking.players[id] == undefined) {
            YouTubeTracking.players[id] = { timePercent: 0 };
        }
        return YouTubeTracking.players[id];
    },

    // function that start the interval, if not already started
    startChecking: function () {

        // check if not already started
        if (YouTubeTracking.intervalId == 0) {
            YouTubeTracking.intervalId = setInterval(YouTubeTracking.checkPlayers, 500);
        }
    },

    // function that checks players on an interval
    checkPlayers: function () {

        // go through each player make sure atleast one playing
        var anyPlaying = false;
        \(.each(playerArray, function (i, p) {

            // check if playing
            if (p.getPlayerState() == YT.PlayerState.PLAYING) {
                anyPlaying = true;

                // get the video info
                var duration = p.getDuration();
                var timeSoFar = p.getCurrentTime();
                var id = p.getVideoData().video_id;

                // get what we tracked so far on this video
                var playerPerc = YouTubeTracking.get(id).timePercent;

                // check if any duraction
                if (duration > 0) {

                    // get the percentage played
                    var thisPerc = timeSoFar / duration * 100;

                    // check each checkpoint
                    \).each(YouTubeTracking.checkpointsToTrack, function (j, checkpoint) {

                        // check if we reached a checkpoint milestone
                        if (playerPerc < checkpoint && thisPerc > checkpoint) {
                            YouTubeTracking.players[id].timePercent = checkpoint;
                            YouTubeTracking.pushEvent(id, “Watched ” + checkpoint + “%”);
                        }
                    });
                }
            }
        });

        // check if none player, stop intveral
        if (!anyPlaying) {
            clearInterval(YouTubeTracking.intervalId);
            YouTubeTracking.intervalId = 0;
        }
    },

    // track state check
    checkStateChange: function (event) {

        // get the id
        var id = event.target.a.id;

        // video playing
        if (event.data == YT.PlayerState.PLAYING) {
            YouTubeTracking.pushEvent(id, “Play”);
            YouTubeTracking.pauseFlag = false;

            // start checkpoint checking
            YouTubeTracking.startChecking();
        }

        // video end
        if (event.data == YT.PlayerState.ENDED) {
            YouTubeTracking.pushEvent(id, “Watch to End”);
        }

        // video paused
        if (event.data == YT.PlayerState.PAUSED && YouTubeTracking.pauseFlag == false) {
            YouTubeTracking.pushEvent(id, “Pause”);
            YouTubeTracking.pauseFlag = true;
        }

        // buffering
        if (event.data == YT.PlayerState.BUFFERING) {
            YouTubeTracking.pushEvent(id, “Buffering”);
        }

        // cued
        if (event.data == YT.PlayerState.CUED) {
            YouTubeTracking.pushEvent(id, “Cueing”);
        }
    },

    // track in GA
    pushEvent: function (id, catg) {

        // get the title, then trach
        \(.get("https://gdata.youtube.com/feeds/api/videos/" + id + "?v=2&alt=json", function (d) {
            _gaq.push(['_trackEvent', 'Videos', catg, d.entry.title.\)t]);
        });
    }
};

The full source file can be downloaded here: mroma-youtube-tracking.js