Skip to content

Instantly share code, notes, and snippets.

@mzaman
Forked from Daphonia/BCHTML5GATracker.js
Created April 21, 2017 03:48
Show Gist options
  • Select an option

  • Save mzaman/6a6a81923cb4b70a3f42672a3918da06 to your computer and use it in GitHub Desktop.

Select an option

Save mzaman/6a6a81923cb4b70a3f42672a3918da06 to your computer and use it in GitHub Desktop.
Google Analytics Tracker Plugin for BC HTML5 Players
/**
* Brightcove HTML5 Player Google Analytics Tracker 1.0.0 Alpha (02 Sep 2012)
*
* REFERENCES:
* Website:
* Source:
*
* AUTHORS:
* Darius Oleskevicius <doleskevicius@brightcove.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the “Software”),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, alter, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, subject to the following conditions:
*
* 1. The permission granted herein does not extend to commercial use of
* the Software by entities primarily engaged in providing online video and
* related services.
*
* 2. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, SUITABILITY, TITLE,
* NONINFRINGEMENT, OR THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT
* SHALL THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY WHATSOEVER, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
* THE SOFTWARE OR THE USE, INABILITY TO USE, OR OTHER DEALINGS IN THE SOFTWARE.
*
* 3. NONE OF THE AUTHORS, CONTRIBUTORS, NOR BRIGHTCOVE SHALL BE RESPONSIBLE
* IN ANY MANNER FOR USE OF THE SOFTWARE. THE SOFTWARE IS PROVIDED FOR YOUR
* CONVENIENCE AND ANY USE IS SOLELY AT YOUR OWN RISK. NO MAINTENANCE AND/OR
* SUPPORT OF ANY KIND IS PROVIDED FOR THE SOFTWARE.
*/
(function(){
BCHTML5GATracker = {};
/*
GA account ID can be hardcoded here, or passed in via a parameter on the plugin,
in the embed code for the player:
Plugin Parameter: http://mydomain.com/BCHTML5GATracker.js?accountNumber=UA-123456-0
*/
BCHTML5GATracker.GAACCOUNT_ID = "";
BCHTML5GATracker.VERSION = "1.0.0";
BCHTML5GATracker.REFERRER_URL = "Referrer URL: ";
BCHTML5GATracker.PLAYER_NAME = "Brightcove Player";
BCHTML5GATracker.PLAYER_LOAD = "Player Load";
BCHTML5GATracker.VIDEO_LOAD = "Video Load";
BCHTML5GATracker.MEDIA_BEGIN = "Media Begin";
BCHTML5GATracker.MEDIA_PAUSE = "Media Pause";
BCHTML5GATracker.MEDIA_RESUME = "Media Resume";
BCHTML5GATracker.MEDIA_COMPLETE = "Media Complete";
BCHTML5GATracker.MEDIA_ABANDONED = "Media Abandoned";
BCHTML5GATracker.SEEK_FORWARD = "Seeked Forward";
BCHTML5GATracker.SEEK_BACKWARD = "Seeked Backward";
BCHTML5GATracker.MILESTONE_25 = "25% Milestone Passed";
BCHTML5GATracker.MILESTONE_50 = "50% Milestone Passed";
BCHTML5GATracker.MILESTONE_75 = "75% Milestone Passed";
var _player,
_experienceModule,
_videoPlayerModule,
_cuePointsModule,
_currentVideo,
_customVideoID,
_currentPosition,
_previousTimestamp,
_timeWatched,
_storedTimeWatched = {}; //stored in milliseconds
_storedTimeWatched.data = {};
//flags for tracking
var _mediaBegin = false,
_mediaComplete = true,
_mediaPaused = false,
_mediaSeeking = false,
_trackSeekForward = false,
_trackSeekBackward = false;
//GA
var _gaq = _gaq || [];
BCHTML5GATracker.initialize = function(){
//get reference to player itself
_player = brightcove.api.getExperience();
//get references to player modules
_videoPlayerModule = _player.getModule(brightcove.api.modules.APIModules.VIDEO_PLAYER);
_experienceModule = _player.getModule(brightcove.api.modules.APIModules.EXPERIENCE);
_cuePointsModule = _player.getModule(brightcove.api.modules.APIModules.CUE_POINTS);
//settup event listeners
BCHTML5GATracker.setupEventListeners();
//initialise GA
BCHTML5GATracker.initGA();
//set loaded player
BCHTML5GATracker.setPlayerName();
//check if a video didn't get a completion tracked
BCHTML5GATracker.checkAbandonedVideo();
};
BCHTML5GATracker.setupEventListeners = function(){
//add event listners
_experienceModule.addEventListener(brightcove.api.events.ExperienceEvent.TEMPLATE_READY, BCHTML5GATracker.onTemplateReady);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.CHANGE, BCHTML5GATracker.onMediaBegin);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.BEGIN, BCHTML5GATracker.onMediaChange);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.PLAY, BCHTML5GATracker.onMediaPlay);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.STOP, BCHTML5GATracker.onMediaStop);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.PROGRESS, BCHTML5GATracker.onMediaProgress);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.SEEK_NOTIFY, BCHTML5GATracker.onMediaSeek);
_videoPlayerModule.addEventListener(brightcove.api.events.MediaEvent.COMPLETE, BCHTML5GATracker.onMediaComplete);
_cuePointsModule.addEventListener(brightcove.api.events.CuePointEvent.CUE, BCHTML5GATracker.onCuePoint);
};
BCHTML5GATracker.onTemplateReady = function(){
var referrerURL = document.referrer;
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.PLAYER_LOAD, referrerURL]);
};
BCHTML5GATracker.onMediaChange = function(){
_currentVideo = _videoPlayerModule.getCurrentVideo();
_storedTimeWatched.data.abandonedVideo = _currentVideo;
_customVideoID = BCHTML5GATracker.getLoadedVideo(_currentVideo);
//tracks even if referrer URL is not available
var referrerURL = document.referrer;
var trackingAction = BCHTML5GATracker.REFERRER_URL + referrerURL;
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, trackingAction, BCHTML5GATracker.getLoadedVideo(_currentVideo)]);
BCHTML5GATracker.createCuePoints(_currentVideo);
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.VIDEO_LOAD, BCHTML5GATracker.getLoadedVideo(_currentVideo)]);
_previousTimestamp = new Date().getTime();
_timeWatched = 0;
};
BCHTML5GATracker.onMediaBegin = function(){
if(!_mediaBegin){
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MEDIA_BEGIN, BCHTML5GATracker.getLoadedVideo(_videoPlayerModule.getCurrentVideo())]);
_previousTimestamp = new Date().getTime();
_timeWatched = 0;
_mediaComplete = false;
_mediaBegin = true;
}
};
BCHTML5GATracker.onMediaPlay = function(){
if(_mediaPaused){
_mediaPaused = false;
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MEDIA_RESUME, BCHTML5GATracker.getLoadedVideo(_currentVideo)]);
}
};
BCHTML5GATracker.onMediaStop = function(){
if(!_mediaComplete && !_mediaPaused){
_mediaPaused = true;
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MEDIA_PAUSE, BCHTML5GATracker.getLoadedVideo(_currentVideo)]);
}
};
BCHTML5GATracker.onMediaProgress = function(pEvent){
_currentPosition = pEvent.position;
//update tracked time
BCHTML5GATracker.updateTrackedTime();
/*
This will track the media complete event when the user has watched 98% or more of the video.
Why do it this way and not use the Smart Player API's event? The mediaComplete event will
only fire once, so if a video is replayed, it won't fire again.
*/
if(pEvent.position/pEvent.duration > .98 && !_mediaComplete){
BCHTML5GATracker.onMediaComplete(pEvent);
//empty these since we don't want to track it when someone comes back
_storedTimeWatched.data.abandonedVideo = null;
_storedTimeWatched.data.abandonedTimeWatched = null;
}
//track seek events
if(!_mediaSeeking){
if(_trackSeekForward){
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.SEEK_FORWARD, _customVideoID]);
_trackSeekForward = false;
}
if(_trackSeekBackward){
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.SEEK_BACKWARD, _customVideoID]);
_trackSeekBackward = false;
}
}else{
_mediaSeeking = false;
}
};
BCHTML5GATracker.onMediaSeek = function(pEvent){
if(pEvent.position > _currentPosition){
_trackSeekForward = true;
}else{
_trackSeekBackward = true;
}
_mediaSeeking = true;
};
BCHTML5GATracker.onCuePoint = function(pEvent){
if(pEvent.cuePoint.type == 2 && pEvent.cuePoint.name == "milestone"){
switch(pEvent.cuePoint.metadata){
case "25%":
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MILESTONE_25, _customVideoID]);
break;
case "50%":
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MILESTONE_50, _customVideoID]);
break;
case "75%":
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MILESTONE_75, _customVideoID]);
break;
}
}
};
BCHTML5GATracker.initGA = function(){
BCHTML5GATracker.GAACCOUNT_ID = (BCHTML5GATracker.GAACCOUNT_ID == null) ? BCHTML5GATracker.getParamValue('GAID') : BCHTML5GATracker.GAACCOUNT_ID;
if(BCHTML5GATracker.GAACCOUNT_ID == null){
console.log("The Google Analytics account number has not been defined. This is required for the analytics plugin to function properly.");
}else{
console.log("GA Account Number: " + BCHTML5GATracker.GAACCOUNT_ID);
_gaq.push(['_setAccount', BCHTML5GATracker.GAACCOUNT_ID]);
_gaq.push(['_trackPageview']);
try{
// determine whether to include the normal or SSL version
var gaURL = (location.href.indexOf('https') == 0 ? 'https://ssl' : 'http://www');
gaURL += '.google-analytics.com/ga.js';
// include the ga.js
$.getScript(gaURL);
}catch(error){
console.log('Failed to load ga.js:' + error);
}
}
};
BCHTML5GATracker.getParamValue = function(key){
//check plugin params for the value
var pluginURL = experienceJSON.data.configuredProperties.plugins.list;
var vars = [], hash;
var hashes = pluginURL.slice(pluginURL.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++){
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars[key];
};
BCHTML5GATracker.setPlayerName = function(){
var playerName = unescape(BCHTML5GATracker.getParamValue('PlayerName'));
var playerId = _experienceModule.getExperienceID();
if(playerName != "undefined"){
BCHTML5GATracker.PLAYER_NAME = playerName + " ID " + playerId;
}else{
BCHTML5GATracker.PLAYER_NAME = BCHTML5GATracker.PLAYER_NAME + " ID " + playerId;
}
};
BCHTML5GATracker.getLoadedVideo = function(videoDTO){
var loadedVideo = videoDTO.id + " | " + videoDTO.displayName;
return loadedVideo;
};
BCHTML5GATracker.checkAbandonedVideo = function(){
if(_storedTimeWatched.data.abandonedVideo && _storedTimeWatched.data.abandonedTimeWatched){
var customVideoID = getCustomVideoID(_storedTimeWatched.data.abandonedVideo);
var timeWatched = Math.round(_storedTimeWatched.data.abandonedTimeWatched);
console.log("Tracking video that was previously unclosed: " + customVideoID + " : " + timeWatched);
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MEDIA_ABANDONED, customVideoID, timeWatched]);
}
};
BCHTML5GATracker.updateTrackedTime = function(){
var currentTimestamp = new Date().getTime();
var timeElapsed = (currentTimestamp - _previousTimestamp)/1000;
_previousTimestamp = currentTimestamp;
//check if it's more than 2 seconds in case the user paused or changed their local time or something
if(timeElapsed < 2){
_timeWatched += timeElapsed;
}
//update time watched in case the user bails out before mediaComplete
if(!_mediaComplete){//make sure mediaComplete hasn't fired yet, otherwise it gets set to null and the repopulated: not what we want
_storedTimeWatched.data.abandonedTimeWatched = _timeWatched; //automatically gets flushed when flash player is closed
}
};
BCHTML5GATracker.onMediaComplete = function(pEvent){
if(!_mediaComplete){
_mediaComplete = true;
_mediaBegin = false;
_gaq.push(['_trackEvent', BCHTML5GATracker.PLAYER_NAME, BCHTML5GATracker.MEDIA_COMPLETE, _customVideoID, Math.round(_timeWatched)]);
}
};
BCHTML5GATracker.createCuePoints = function(pVideo){
var percent25 = {
type: 2, //chapter cue point
name: "milestone",
metadata: "25%",
time: (pVideo.length/1000) * .25
};
var percent50 = {
type: 2, //chapter cue point
name: "milestone",
metadata: "50%",
time: (pVideo.length/1000) * .5
};
var percent75 = {
type: 2, //chapter cue point
name: "milestone",
metadata: "75%",
time: (pVideo.length/1000) * .75
};
_cuePointsModule.addCuePoints(_currentVideo.id, [percent25, percent50, percent75]);
};
//initialise the tracker
BCHTML5GATracker.initialize();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment