Video tracking for Youtube videos can easily be configured with build-in Google Tag Manager triggers. But other video players are not currently supported. Fortunatly most of the popular video players have JavaScript API which allows to create listeners and push data about video player events to dataLayer.
JWPlayer Tracking
JWPlayer has very detailed API reference here https://developer.jwplayer.com/jw-player/docs/developer-guide/api/javascript_api_introduction/
Using JWPlayer API it is possible to track a number of different events: play, pause, volume change, resize, advertising interactions, etc.
Here is a sample script that can be either implemented to the web page or added as custom tag in Google Tag Manager to push data about some of these events to dataLayer.
(function(dataLayer){ var i = 0; var markers = [10,25,50,75,90]; //adjust these values if you want different progress reports var playersMarkers = []; function findObjectIndexById(haystack, key, needle) { for (var i = 0; i < haystack.length; i++) { if (haystack[i][key] == needle) { return i; } } return null; } //Function call to push to dataLayer, passing in current scope of this, // the eventType value and the eventInteraction value for the DL push function eventToDataLayer (thisObject, eventType, eventInteraction) { var eventName; if (thisObject.getPlaylistItem().title) { eventName = thisObject.getPlaylistItem().title; } else { eventName = 'not set'; } dataLayer.push({ event: "video", eventCategory: "JW Player", eventAction: eventType, eventLabel: eventName }); } //loops through all JWPlayers on the page while (window.jwplayer(i).id) { var player = window.jwplayer(i++); //Pushes an object of player.id and progress markers to the array playersMarkers playersMarkers.push({ 'id': player.id, 'markers': [] }); player.on('setupError', function(e) { eventToDataLayer (this, 'Video error', e.message); } ); player.on('play', function(e){ var playResume ; if (this.getPosition() < 2) { playResume = 'Played video'; } else { playResume = 'Resumed video'; } eventToDataLayer (this, 'Played video', playResume); } ); player.on('pause', function(e){ eventToDataLayer (this, 'Paused video', 'Paused video'); } ); player.on('complete', function(e){ eventToDataLayer (this, '100%', '100%'); } ); player.on('time', function(e){ var percentPlayed = Math.floor(e.position*100/e.duration); var playerMarkerIndex = findObjectIndexById(playersMarkers,'id',this.id); if(markers.indexOf(percentPlayed)>-1 && playersMarkers[playerMarkerIndex].markers.indexOf(percentPlayed)==-1) { playersMarkers[playerMarkerIndex].markers.push(percentPlayed); eventToDataLayer (this, percentPlayed + '%', percentPlayed + '%'); } } ); player.on('error', function(e){ eventToDataLayer (this, 'Video error', e.message); } ); } })(window.dataLayer = window.dataLayer || []);
Vimeo Tracking
Another popular video plauer is Vimeo. Here is the documentation on the JavaScript API for Vimeo player https://github.com/vimeo/player.js.
Here is a sample tracking code that uses the Vimeo JavaScript API.
var dataLayer = (typeof(dataLayer) !== "undefined" && dataLayer instanceof Array) ? dataLayer : []; var videoLabels=[]; var lastP=[]; //we declare variables that will hold information about the video being played var _playerTitle = {}, _playerAuthor = {}, _playerAuthorURL = {}, _playerUploadDate = {}; try{ init(); } catch(err){ dataLayer.push({ 'event': 'gtm.error', 'errorMessage': e.message, 'tag': 'CP - UA - Vimeo Video Listener' }) } function init(){ try{ var player=document.getElementsByTagName("iframe"); for (i = 0; i < player.length; ++i) { var url=player[i].getAttribute("src"); if(/player\.vimeo\.com\/video/.test(url)){ // vimeo iframe found if(!player[i].hasAttribute("id")){ // id attribute missing player[i].setAttribute("id","vimeo_id_"+i); // add id attribute } var urlUpdated=false; if(!/api=/.test(url)){ // check to see if api parameter is in src attribute url=updateUrl(url,"api",1); urlUpdated=true; } if(!/player_id=/.test(url)){ // check if player_id is in src attribute url=updateUrl(url,"player_id",player[i].getAttribute("id")); urlUpdated=true; } if(urlUpdated){ // repopulate src attribute with added parameters player[i].setAttribute("src",url) } videoLabels[player[i].getAttribute("id")]=player[i].getAttribute("src"); // id to label dictionary } } // Listen for messages from the player if (window.addEventListener){ window.addEventListener('message', onMessageReceived, false); } else { window.attachEvent('onmessage', onMessageReceived, false); } } catch(err){ } } function updateUrl(url,param,value){ try{ return url+((/\?/.test(url)) ? "&" : "?")+param+"="+value; } catch(err){ } } // Handle messages received from the player function onMessageReceived(e) { try{ var data = e.data; if(typeof data === "string"){ data = JSON.parse(data); } switch (data.event) { case 'ready': onReady(data); break; case 'play': onPlay(data); break; case 'pause': onPause(data); break; case 'playProgress': onPlayProgress(data); break; } } catch(err){ } } // Helper function for sending a message to the player function post(action, value) { try{ var data = { method: action }; if (value) { data.value = value; } var message = JSON.stringify(data); var player = document.getElementsByTagName("iframe"); var url; var prot; for (i = 0; i < player.length; ++i) { url=player[i].getAttribute("src"); if(/player\.vimeo\.com\/video/.test(url)){ // Check if protocol exists prot = player[i].getAttribute('src').split('?')[0].split('//')[0]; // If protocol doesn't exist, then need to append to "url" if (!prot){ url="https:" + player[i].getAttribute("src").split('?')[0]; } player[i].contentWindow.postMessage(data, url); } } } catch(err){ } } function getLabel(id){ try{ return videoLabels[id].split('?')[0].split('/').pop(); } catch(err){ } } //our function that will use the Vimeo oEmbed API to retrieve additional information about the video function getVimeoInfo(url, callback) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; document.getElementsByTagName('body')[0].appendChild(script); } //the callback function which takes the data received from the Vimeo oEmbed API and places it into the corresponding objectes function vimeoCallback(e){ //console.log(e); _playerTitle[e['video_id']] = e['title']; _playerAuthor[e['video_id']] = e['author_name'] _playerAuthorURL[e['video_id']] = e['author_url'] _playerUploadDate[e['video_id']] = e['upload_date'] } function onReady(data) { try{ //execute our function which queries the Vimeo oEmbed API once the embedded videos are "ready" getVimeoInfo("https://www.vimeo.com/api/oembed.json?url=https://vimeo.com/"+getLabel(data.player_id)+"&callback=vimeoCallback", vimeoCallback); post('addEventListener', 'play'); post('addEventListener', 'pause'); post('addEventListener', 'finish'); post('addEventListener', 'playProgress'); } catch(err){ } } function onPlay(data){ try{ dataLayer.push({ event: "vimeo", eventCategory: "vimeo", eventAction: "vimeo play", eventLabel: _playerTitle[getLabel(data.player_id)].toLowerCase() + " - " + getLabel(data.player_id), vimeo_playerID: getLabel(data.player_id), vimeo_playerTitle: _playerTitle[getLabel(data.player_id)].toLowerCase(), vimeo_playerAuthor: _playerAuthor[getLabel(data.player_id)].toLowerCase(), vimeo_playerAuthorURL: _playerAuthorURL[getLabel(data.player_id)].toLowerCase(), vimeo_playerUploadDate: _playerUploadDate[getLabel(data.player_id)], nonInteractive: true }); } catch(err){ } } function onPause(data){ try{ dataLayer.push({ event: "vimeo", eventCategory: "vimeo", eventAction: "vimeo video pause", eventLabel: _playerTitle[getLabel(data.player_id)].toLowerCase() + " - " + getLabel(data.player_id), vimeo_playerID: getLabel(data.player_id), vimeo_playerTitle: _playerTitle[getLabel(data.player_id)].toLowerCase(), vimeo_playerAuthor: _playerAuthor[getLabel(data.player_id)].toLowerCase(), vimeo_playerAuthorURL: _playerAuthorURL[getLabel(data.player_id)].toLowerCase(), vimeo_playerUploadDate: _playerUploadDate[getLabel(data.player_id)], nonInteractive: true }); } catch(err){ } } // Track progress: 25%, 50%, 75%, 100% function onPlayProgress(data) { try{ var t = data.data.duration - data.data.seconds <= 1.5 ? 1 : (Math.floor(data.data.seconds / data.data.duration * 4) / 4).toFixed(2); if (!lastP[data.player_id] || t > lastP[data.player_id]) { lastP[data.player_id]=t; if (parseFloat(t) != 0){ dataLayer.push({ event: "vimeo", eventCategory: "vimeo", eventAction: "vimeo video " +t*100+ "% Complete", eventLabel: _playerTitle[getLabel(data.player_id)].toLowerCase() + " - " + getLabel(data.player_id), vimeo_playerID: getLabel(data.player_id), vimeo_playerTitle: _playerTitle[getLabel(data.player_id)].toLowerCase(), vimeo_playerAuthor: _playerAuthor[getLabel(data.player_id)].toLowerCase(), vimeo_playerAuthorURL: _playerAuthorURL[getLabel(data.player_id)].toLowerCase(), vimeo_playerUploadDate: _playerUploadDate[getLabel(data.player_id)], nonInteractive: true }) } } } catch(err){ } }
Leave a comment