Youtube API event distinguish pause from seek/buffer

2k views Asked by At

We've set up event tracking for videos start/play/pause/complete events.

We have a unified way of reporting the events for HTML5, Youtube and Youku videos. For HTML5 and mobile Youku videos there's no issue. For desktop Youku (flash) we've had to set up a setInterval poll to check what state the video is in, it's not pretty but it works well.

The issue is with the Youtube embedded video. We listen to the onStateChange event:

player.addEventListener('onStateChange', function(e) {

    if(e.data === 0) {
        // Complete

    } else if(e.data === 1) {
        // Play

    } else if(e.data === 2) {
        // Pause
    }
}

But when the user seeks in the video while the video is playing, interacts with the timeline bar, the player will trigger a pause a play and a buffer (e.data === 3) event. We do not want to track the pause and play caused by seeking.

In chrome we can distinguish the seek action since the buffer event will always trigger first. Like 3, 2 and when the player is done buffering 1. So we ignore any pause event that closely follows a buffer event, and any play event following a buffer event regardless of time passed. This works well.

In firefox however the sequence of events is very different. In firefox the buffer event is trailing. So we get the order 2, 1, 3. If the video is already buffering we get 2, 3, 1.

Is there another way of detecting seek events for youtube videos? Or a way to capture sequences?

1

There are 1 answers

0
pstenstrm On BEST ANSWER

This is how I ended up solving this issue. It will track play and pause events but not track anything when the user seeks. As far as I can tell it works as expected in the browsers I've tested.

var youtubeTrackingGate = youtubeTrackingGateFactory();

youtubePlayer.addEventListener('onStateChange', function(e) {
    if(e.data === -1 || e.data === 3) {

        youTubeTrackingGate({type: e.data});
    } else if(e.data === 1) {
        youTubeTrackingGate({type: e.data, event: 'PLAY'});
    } else if(e.data === 2) {
        youTubeTrackingGate({type: e.data, event: 'PAUSE'});
    }
});

function youtubeTrackingGateFactory () {
    var
        sequence = [],
        preventNextTracking = false,
        data,
        timeout;

    return function(obj) {

        // Chrome seek event
        if(util.compareArrays(sequence, [3]) && obj.type === 2) {
            preventNextTracking = true;

        // Prevent next play
        } else if(preventNextTracking && obj.type === 1) {
            preventNextTracking = false;

        } else {
            clearTimeout(timeout);

            // Save event
            sequence.push(obj.type);
            data = obj.event;

            timeout = setTimeout(function() {

                // Single event, let it pass if it's (play/pause)
                if(sequence.length === 1 && [1, 2].indexOf(sequence[0]) > -1) {

                    sendTracking(data);
                }

                sequence = [];
            }, 500);
        }

        // Suppress any (play/pause) after buffer event
        if(obj.type === 3) {

            // If not inital play
            if(!util.compareArrays(sequence, [-1, 3])) {
                preventNextTracking = true;

            // If is initial play
            } else {
                sequence = [];
            }
        }
    };
}


sendTracking(event) { 
    // code
}