Analítica web
Reflexiones desde el mercado español de Analítica Web

Medición de vídeos de YouTube con Google Analytics

Se lee en 13 minutos

A menudo, uno de los problemas más comunes en el mundo de la analítica, es realizar etiquetados (mediciones) de activos en una web que no se integran directamente en el DOM, como puede ser contenidos de iframes cargados desde fuentes remotas, aplicaciones java o flash, vídeos en general (HTML5, Flash, YouTube, etc.) o cualquier elemento cuyos cambios no puedan verse directamente en el DOM, por lo que su captura es más compleja.

En este artículo, comentaremos cómo realizar el etiquetado de vídeos de YouTube a partir de la propia API Javascript que nos ofrece Google.

Hemos utilizado JavaScript y el framework jQuery para obtener los datos y enviar los eventos. Además, cabe destacar que el script puede realizar los envíos a Google Analytics directamente o a través de un data layer de Google Tag Manager, con lo cual se adapta automáticamente a la mayoría de casuísticas.

Para ello, hemos utilizado, como fuente, un script proporcionado por los chicos de LunaMetrics, que hemos modificado y ampliado para nuestro propósito.

Objetivo de la medición: detectar cuándo un vídeo se empieza a reproducir, cuándo se pausa, cuándo se ve el vídeo completo y, además, detectar porcentajes intermedios de reproducción. En este caso, queremos que nos envíe un evento de reproducción alcanzada, en los porcentajes 10%, 25%, 45%, 50%, 75% y 90%. Por la propia naturaleza de un vídeo, las mediciones se enviarán como eventos y no como páginas vistas.

Vamos explicando paso a paso las partes del código (al final del artículo se encuentra el código completo).

Parte 1: Configuración

Aquí se configurará la propiedad de Google Analytics a la que se enviará la información, los eventos a medir (play, pause y vídeo completo) y los porcentajes que se quieren enviar (se enviará una custom metric diferente para cada uno).

// ###################################################
// ######## CONFIGURACION DE GOOGLE ANALYTICS ########
// ###################################################

// EDITAR ESTE PARAMETRO PARA PONER LA PROPIEDAD DE GA
// A LA QUE SE VAN A ENVIAR LOS DATOS.

var GA_PROPERTY = 'UA-XXXXXX-01';


// ###################################################
// ######## CONFIGURACION DE LA MEDICION #############
// ################################################### 

// Por un lado se configuran los eventos a lanzar,
// por otro se configuran los porcentajes de video  
// a medir, en este caso cada 25% y además el 10%, 45%
// y 90%.

(document, window, {
  'events': {
    'Play': true,
    'Pause': true,
    'Watch to End': true
  },
  'percentageTracking': {
    'every': 25,
    'each': [10, 45, 90]
  }
});ja

Parte 2: Carga de la API

En esta parte se incluye la huella de Google Analytics, se carga la API de YouTube y se hacen las primeras inicializaciones.

// INCLUSION DE LA HUELLA DE GOOGLE ANALYTICS

(function(i, s, o, g, r, a, m) {
  i['GoogleAnalyticsObject'] = r;
  i[r] = i[r] || function() {
    (i[r].q = i[r].q || []).push(arguments);
  }, i[r].l = 1 * new Date();
  a = s.createElement(o),
    m = s.getElementsByTagName(o)[0];
  a.async = 1;
  a.src = g;
  m.parentNode.insertBefore(a, m);
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', GA_PROPERTY, 'auto');

// ###################################################
// ######## ETIQUETADO DE VIDEOS DE YOUTUBE ##########
// ###################################################


(function(document, window, config) {

  // ###################################################
  // ######## IMPLEMENTACION DE LA LOGICA ##############
  // ###################################################

  'use strict';
  var _config = config || {};
  var forceSyntax = _config.forceSyntax || 0;
  var dataLayerName = _config.dataLayerName || 'dataLayer';

  // Se configuran los eventos que se van a lanzar,
  // inicio video, pausa video, video visto hasta el final.
  // Para desactivarlos basta con setearlos a false.

  var eventsFired = {
    'Play': true,
    'Pause': true,
    'Watch to End': true
  };
  var key;

  // Carga la API Javascript de YouTube

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

  // Lee la configuración de los eventos a lanzar

  for (key in _config.events) {
    if (_config.events.hasOwnProperty(key)) {
      eventsFired[key] = _config.events[key];
    }
  }
  window.onYouTubeIframeAPIReady = (function() {
    var cached = window.onYouTubeIframeAPIReady;
    return function() {
      if (cached) {
        cached.apply(this, arguments);
      }

      // En caso de detectar Internet Explorer 6 o 7 el script finaliza
      // por problemas de compatibilidad.

      if (navigator.userAgent.match(/MSIE [67]\./gi)) return;
      if (document.readyState !== 'loading') {
        init();
      } else {
        // Fix para Internet Explorer 8, ya que el DOM ready se llama window.load

        if (document.addEventListener) {
          addEvent(document, 'DOMContentLoaded', init);
        } else {
          addEvent(window, 'load', init);
        }
      }
    };
  })();

  // Una vez cargada la API de YouTube se llama a esta función que obtiene los videos
  // de la página para poder medirlos.

  function init() {
    var potentialVideos = getTagsAsArr_('iframe').concat(getTagsAsArr_('embed'));
    digestPotentialVideos(potentialVideos);

    // Si se añaden nuevos videos al DOM de forma dinámica también se cargarán, excepto en IE8

    if ('addEventListener' in document) {
      document.addEventListener('load', bindToNewVideos_, true);
    }

  }

Parte 3: Implementación de la lógica.

Con este código se añade toda la funcionalidad para la identificación y procesado de los vídeos.

// Función que procesa los objetos de los videos para poder medirlos.

  function digestPotentialVideos(potentialVideos) {
    var i;
    for (i = 0; i < potentialVideos.length; i++) {
      var isYouTubeVideo = checkIfYouTubeVideo(potentialVideos[i]);
      if (isYouTubeVideo) {
        var normalizedYouTubeIframe = normalizeYouTubeIframe(potentialVideos[i]);
        addYouTubeEvents(normalizedYouTubeIframe);
      }
    }
  }
  // Función que determina si el video que se ha cargado realmente es de YouTube o no
  function checkIfYouTubeVideo(potentialYouTubeVideo) {
    var potentialYouTubeVideoSrc = potentialYouTubeVideo.src || '';
    if (potentialYouTubeVideoSrc.indexOf('youtube.com/embed/') > -1 ||
      potentialYouTubeVideoSrc.indexOf('youtube.com/v/') > -1) {
      return true;
    }
    return false;
  }
  // Función que determina si el video tiene el parámetro 'enablejsapi', imprescindible
  // para realizar la medición, ya que habilita el acceso via API.

  function jsApiEnabled(url) {
    return url.indexOf('enablejsapi') > -1;
  }

  // Función que determina si el video tiene el parámetro 'origin'

  function originEnabled(url) {
    return url.indexOf('origin') > -1;
  }

  // Función que procesa los videos embebidos para convertirlos en iframes y asignarles los parametros correctos.

  function normalizeYouTubeIframe(youTubeVideo) {
    var loc = window.location;
    var a = document.createElement('a');
    a.href = youTubeVideo.src;
    a.hostname = 'www.youtube.com';
    a.protocol = loc.protocol;
    var tmpPathname = a.pathname.charAt(0) === '/' ? a.pathname : '/' + a.pathname; // IE10 shim

    // Por motivos de seguridad, YouTube requiere el parametro origen, si no está, lo creamos.

    if (!jsApiEnabled(a.search)) {
      a.search = (a.search.length > 0 ? a.search + '&' : '') + 'enablejsapi=1';
    }
    if (!originEnabled(a.search) && loc.hostname.indexOf('localhost') === -1) {

      var port = loc.port ? ':' + loc.port : '';
      var origin = loc.protocol + '%2F%2F' + loc.hostname + port;
      a.search = a.search + '&origin=' + origin;
    }
    if (youTubeVideo.type === 'application/x-shockwave-flash') {
      var newIframe = document.createElement('iframe');
      newIframe.height = youTubeVideo.height;
      newIframe.width = youTubeVideo.width;
      tmpPathname = tmpPathname.replace('/v/', '/embed/');
      youTubeVideo.parentNode.parentNode.replaceChild(newIframe, youTubeVideo.parentNode);
      youTubeVideo = newIframe;
    }
    a.pathname = tmpPathname;
    if (youTubeVideo.src !== a.href + a.hash) {
      youTubeVideo.src = a.href + a.hash;
    }
    return youTubeVideo;
  }
  // Función que asigna handlers para los eventos emitidos por la API de YouTube

  function addYouTubeEvents(youTubeIframe) {
    var player = YT.get(youTubeIframe.id);
    if (!player) {
      player = new YT.Player(youTubeIframe, {});
    }
    if (typeof youTubeIframe.pauseFlag === 'undefined') {
      youTubeIframe.pauseFlag = false;
      player.addEventListener('onStateChange', function(evt) {
        onStateChangeHandler(evt, youTubeIframe);
      });
    }
  }

  // Funcion que retorna los porcentajes de video vistos.

  function getMarks(duration) {
    var marks = {};
    if (_config.events['Watch to End']) {
      marks['Watch to End'] = Math.min(duration - 3, Math.floor(duration * 0.99));
    }
    if (_config.percentageTracking) {
      var points = [];
      var i;
      if (_config.percentageTracking.each) {
        points = points.concat(_config.percentageTracking.each);
      }
      if (_config.percentageTracking.every) {
        var every = parseInt(_config.percentageTracking.every, 10);
        var num = 100 / every;
        for (i = 1; i < num; i++) {
          points.push(i * every);
        }
      }
      for (i = 0; i < points.length; i++) {
        var _point = points[i];
        var _mark = _point + '%';
        var _time = duration * _point / 100;
        marks[_mark] = Math.floor(_time);
      }
    }
    return marks;
  }

  // Función que devuelve si el video se ha visto por completo o no

  function checkCompletion(player, marks, videoId) {
    var currentTime = player.getCurrentTime();
    var key;
    player[videoId] = player[videoId] || {};
    for (key in marks) {
      if (marks[key] <= currentTime && !player[videoId][key]) {
        player[videoId][key] = true;
        fireAnalyticsEvent(videoId, key);
      }
    }
  }

  // Función que gestiona los eventos devueltos por la API

  function onStateChangeHandler(evt, youTubeIframe) {
    var stateIndex = evt.data;
    var player = evt.target;
    var targetVideoUrl = player.getVideoUrl();
    var targetVideoId = targetVideoUrl.match(/[?&]v=([^&#]*)/)[1];
    var playerState = player.getPlayerState();
    var duration = Math.floor(player.getDuration());
    var marks = getMarks(duration);
    var playerStatesIndex = {
      '1': 'Play',
      '2': 'Pause'
    };
    var state = playerStatesIndex[stateIndex];
    youTubeIframe.playTracker = youTubeIframe.playTracker || {};
    if (playerState === 1 && !youTubeIframe.timer) {
      clearInterval(youTubeIframe.timer);
      youTubeIframe.timer = setInterval(function() {
        // Comprueba los porcentajes cada 1 segundo
        checkCompletion(player, marks, youTubeIframe.videoId);
      }, 1000);
    } else {
      clearInterval(youTubeIframe.timer);
      youTubeIframe.timer = false;
    }
    if (stateIndex === 1) {
      youTubeIframe.playTracker[targetVideoId] = true;
      youTubeIframe.videoId = targetVideoId;
      youTubeIframe.pauseFlag = false;
    }
    if (!youTubeIframe.playTracker[youTubeIframe.videoId]) {

      // Excluye la publicidad inicial

      return false;
    }
    if (stateIndex === 2) {
      if (!youTubeIframe.pauseFlag) {
        youTubeIframe.pauseFlag = true;
      } else {
        // Fix para evitar enviar varios pauses seguidos
        return false;
      }
    }

    // Elimina los eventos que no se quieren trackear

    if (eventsFired[state]) {
      fireAnalyticsEvent(youTubeIframe.videoId, state);
    }
  }

  // Función que hace compatibles los eventos con todos los navegadores.

  function addEvent(el, name, fn) {
    if (el.addEventListener) {
      el.addEventListener(name, fn);
    } else if (el.attachEvent) {
      el.attachEvent('on' + name, function(evt) {
        evt.target = evt.target || evt.srcElement;
        // Call the event to ensure uniform 'this' handling, pass it event
        fn.call(el, evt);
      });
    } else if (typeof el['on' + name] === 'undefined' || el['on' + name] === null) {

      el['on' + name] = function(evt) {
        evt.target = evt.target || evt.srcElement;
        // Call the event to ensure uniform 'this' handling, pass it event
        fn.call(el, evt);
      };
    }
  }

  // Función que obtiene tags

  function getTagsAsArr_(tagName) {
    return [].slice.call(document.getElementsByTagName(tagName));
  }

  // Función que bindea videos como videos nuevos

  function bindToNewVideos_(evt) {
    var el = evt.target || evt.srcElement;
    var isYT = checkIfYouTubeVideo(el);
    if (el.tagName === 'IFRAME' && isYT && jsApiEnabled(el.src) && originEnabled(el.src)) {
      addYouTubeEvents(el);
    }
  }

Parte 4: Envíos a Google Analytics

Finalmente, realizamos el envío a Google Analytics. Aquí, podemos configurar las dimensiones a enviar y las custom metrics (en nuestro caso se envió una custom metric por cada evento de porcentaje).

Nota: no olvidéis definir las custom dimensions y las custom metrics en vuestra propiedad de Google Analytics que va a recibir los datos o de lo contrario no se quedarán almacenados.

// Funcion que dice si el evento va a Google Analytics o a Google Tag Manager
  // en función de si hay dataLayer o no.

  function fireAnalyticsEvent(videoId, state) {
    var videoUrl = 'https://www.youtube.com/watch?v=' + videoId;
    var _ga = window.GoogleAnalyticsObject;
    if (typeof window[dataLayerName] !== 'undefined' && !_config.forceSyntax) {
      window[dataLayerName].push({
        'event': 'youTubeTrack',
        'attributes': {
          'videoUrl': videoUrl,
          'videoAction': state
        }
      });
    } else if (typeof window[_ga] === 'function' &&
      typeof window[_ga].getAll === 'function' &&
      _config.forceSyntax !== 2) {
      // Envio a Google Analytics, con configuración de Custom Dimensions y
      // Custom Metrics, una para cada porcentaje medido
      window[_ga]('send', 'event', 'medicion de videos', state, videoUrl, {
        title: 'titulo a enviar',
        language: 'idioma a enviar',
        dimension1: 'contenido de la custom dimension1',
        dimension2: 'contenido de la custom dimension2',
        dimension3: 'contenido de la custom dimension3',
        metric1: (state.indexOf('Play') != -1) ? 1 : null,
        metric2: (state.indexOf('Pause') != -1) ? 1 : null,
        metric3: (state.indexOf('Watch to End') != -1) ? 1 : null,
        metric4: (state.indexOf('10') != -1) ? 1 : null,
        metric5: (state.indexOf('25') != -1) ? 1 : null,
        metric6: (state.indexOf('45') != -1) ? 1 : null,
        metric7: (state.indexOf('50') != -1) ? 1 : null,
        metric8: (state.indexOf('75') != -1) ? 1 : null,
        metric9: (state.indexOf('90') != -1) ? 1 : null
      });
    } else if (typeof window._gaq !== 'undefined' && forceSyntax !== 1) {
      window._gaq.push(['_trackEvent', 'Videos', state, videoUrl]);
    }
  }

 

Por último, así nos queda el script final.

// ###################################################
// ######## CONFIGURACION DE GOOGLE ANALYTICS ########
// ###################################################

// EDITAR ESTE PARAMETRO PARA PONER LA PROPIEDAD DE GA
// A LA QUE SE VAN A ENVIAR LOS DATOS.

var GA_PROPERTY = 'UA-XXXXXX-01';


// ###################################################
// ######## CONFIGURACION DE LA MEDICION #############
// ################################################### 

// Por un lado se configuran los eventos a lanzar,
// por otro se configuran los porcentajes de video  
// a medir, en este caso cada 25% y además el 10%, 45%
// y 90%.

(document, window, {
  'events': {
    'Play': true,
    'Pause': true,
    'Watch to End': true
  },
  'percentageTracking': {
    'every': 25,
    'each': [10, 45, 90]
  }
});

// ###################################################
// ######## FIN DE CONFIGURACION DE LA MEDICION ######
// ################################################### 

// INCLUSION DE LA HUELLA DE GOOGLE ANALYTICS

(function(i, s, o, g, r, a, m) {
  i['GoogleAnalyticsObject'] = r;
  i[r] = i[r] || function() {
    (i[r].q = i[r].q || []).push(arguments);
  }, i[r].l = 1 * new Date();
  a = s.createElement(o),
    m = s.getElementsByTagName(o)[0];
  a.async = 1;
  a.src = g;
  m.parentNode.insertBefore(a, m);
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', GA_PROPERTY, 'auto');

// ###################################################
// ######## ETIQUETADO DE VIDEOS DE YOUTUBE ##########
// ###################################################


(function(document, window, config) {

  // ###################################################
  // ######## IMPLEMENTACION DE LA LOGICA ##############
  // ###################################################

  'use strict';
  var _config = config || {};
  var forceSyntax = _config.forceSyntax || 0;
  var dataLayerName = _config.dataLayerName || 'dataLayer';

  // Se configuran los eventos que se van a lanzar,
  // inicio video, pausa video, video visto hasta el final.
  // Para desactivarlos basta con setearlos a false.

  var eventsFired = {
    'Play': true,
    'Pause': true,
    'Watch to End': true
  };
  var key;

  // Carga la API Javascript de YouTube

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

  // Lee la configuración de los eventos a lanzar

  for (key in _config.events) {
    if (_config.events.hasOwnProperty(key)) {
      eventsFired[key] = _config.events[key];
    }
  }
  window.onYouTubeIframeAPIReady = (function() {
    var cached = window.onYouTubeIframeAPIReady;
    return function() {
      if (cached) {
        cached.apply(this, arguments);
      }

      // En caso de detectar Internet Explorer 6 o 7 el script finaliza
      // por problemas de compatibilidad.

      if (navigator.userAgent.match(/MSIE [67]\./gi)) return;
      if (document.readyState !== 'loading') {
        init();
      } else {
        // Fix para Internet Explorer 8, ya que el DOM ready se llama window.load

        if (document.addEventListener) {
          addEvent(document, 'DOMContentLoaded', init);
        } else {
          addEvent(window, 'load', init);
        }
      }
    };
  })();

  // Una vez cargada la API de YouTube se llama a esta función que obtiene los videos
  // de la página para poder medirlos.

  function init() {
    var potentialVideos = getTagsAsArr_('iframe').concat(getTagsAsArr_('embed'));
    digestPotentialVideos(potentialVideos);

    // Si se añaden nuevos videos al DOM de forma dinámica también se cargarán, excepto en IE8

    if ('addEventListener' in document) {
      document.addEventListener('load', bindToNewVideos_, true);
    }

  }

  // Función que procesa los objetos de los videos para poder medirlos.

  function digestPotentialVideos(potentialVideos) {
    var i;
    for (i = 0; i < potentialVideos.length; i++) {
      var isYouTubeVideo = checkIfYouTubeVideo(potentialVideos[i]);
      if (isYouTubeVideo) {
        var normalizedYouTubeIframe = normalizeYouTubeIframe(potentialVideos[i]);
        addYouTubeEvents(normalizedYouTubeIframe);
      }
    }
  }
  // Función que determina si el video que se ha cargado realmente es de YouTube o no
  function checkIfYouTubeVideo(potentialYouTubeVideo) {
    var potentialYouTubeVideoSrc = potentialYouTubeVideo.src || '';
    if (potentialYouTubeVideoSrc.indexOf('youtube.com/embed/') > -1 ||
      potentialYouTubeVideoSrc.indexOf('youtube.com/v/') > -1) {
      return true;
    }
    return false;
  }
  // Función que determina si el video tiene el parámetro 'enablejsapi', imprescindible
  // para realizar la medición, ya que habilita el acceso via API.

  function jsApiEnabled(url) {
    return url.indexOf('enablejsapi') > -1;
  }

  // Función que determina si el video tiene el parámetro 'origin'

  function originEnabled(url) {
    return url.indexOf('origin') > -1;
  }

  // Función que procesa los videos embebidos para convertirlos en iframes y asignarles los parametros correctos.

  function normalizeYouTubeIframe(youTubeVideo) {
    var loc = window.location;
    var a = document.createElement('a');
    a.href = youTubeVideo.src;
    a.hostname = 'www.youtube.com';
    a.protocol = loc.protocol;
    var tmpPathname = a.pathname.charAt(0) === '/' ? a.pathname : '/' + a.pathname; // IE10 shim

    // Por motivos de seguridad, YouTube requiere el parametro origen, si no está, lo creamos.

    if (!jsApiEnabled(a.search)) {
      a.search = (a.search.length > 0 ? a.search + '&' : '') + 'enablejsapi=1';
    }
    if (!originEnabled(a.search) && loc.hostname.indexOf('localhost') === -1) {

      var port = loc.port ? ':' + loc.port : '';
      var origin = loc.protocol + '%2F%2F' + loc.hostname + port;
      a.search = a.search + '&origin=' + origin;
    }
    if (youTubeVideo.type === 'application/x-shockwave-flash') {
      var newIframe = document.createElement('iframe');
      newIframe.height = youTubeVideo.height;
      newIframe.width = youTubeVideo.width;
      tmpPathname = tmpPathname.replace('/v/', '/embed/');
      youTubeVideo.parentNode.parentNode.replaceChild(newIframe, youTubeVideo.parentNode);
      youTubeVideo = newIframe;
    }
    a.pathname = tmpPathname;
    if (youTubeVideo.src !== a.href + a.hash) {
      youTubeVideo.src = a.href + a.hash;
    }
    return youTubeVideo;
  }
  // Función que asigna handlers para los eventos emitidos por la API de YouTube

  function addYouTubeEvents(youTubeIframe) {
    var player = YT.get(youTubeIframe.id);
    if (!player) {
      player = new YT.Player(youTubeIframe, {});
    }
    if (typeof youTubeIframe.pauseFlag === 'undefined') {
      youTubeIframe.pauseFlag = false;
      player.addEventListener('onStateChange', function(evt) {
        onStateChangeHandler(evt, youTubeIframe);
      });
    }
  }

  // Funcion que retorna los porcentajes de video vistos.

  function getMarks(duration) {
    var marks = {};
    if (_config.events['Watch to End']) {
      marks['Watch to End'] = Math.min(duration - 3, Math.floor(duration * 0.99));
    }
    if (_config.percentageTracking) {
      var points = [];
      var i;
      if (_config.percentageTracking.each) {
        points = points.concat(_config.percentageTracking.each);
      }
      if (_config.percentageTracking.every) {
        var every = parseInt(_config.percentageTracking.every, 10);
        var num = 100 / every;
        for (i = 1; i < num; i++) {
          points.push(i * every);
        }
      }
      for (i = 0; i < points.length; i++) {
        var _point = points[i];
        var _mark = _point + '%';
        var _time = duration * _point / 100;
        marks[_mark] = Math.floor(_time);
      }
    }
    return marks;
  }

  // Función que devuelve si el video se ha visto por completo o no

  function checkCompletion(player, marks, videoId) {
    var currentTime = player.getCurrentTime();
    var key;
    player[videoId] = player[videoId] || {};
    for (key in marks) {
      if (marks[key] <= currentTime && !player[videoId][key]) {
        player[videoId][key] = true;
        fireAnalyticsEvent(videoId, key);
      }
    }
  }

  // Función que gestiona los eventos devueltos por la API

  function onStateChangeHandler(evt, youTubeIframe) {
    var stateIndex = evt.data;
    var player = evt.target;
    var targetVideoUrl = player.getVideoUrl();
    var targetVideoId = targetVideoUrl.match(/[?&]v=([^&#]*)/)[1];
    var playerState = player.getPlayerState();
    var duration = Math.floor(player.getDuration());
    var marks = getMarks(duration);
    var playerStatesIndex = {
      '1': 'Play',
      '2': 'Pause'
    };
    var state = playerStatesIndex[stateIndex];
    youTubeIframe.playTracker = youTubeIframe.playTracker || {};
    if (playerState === 1 && !youTubeIframe.timer) {
      clearInterval(youTubeIframe.timer);
      youTubeIframe.timer = setInterval(function() {
        // Comprueba los porcentajes cada 1 segundo
        checkCompletion(player, marks, youTubeIframe.videoId);
      }, 1000);
    } else {
      clearInterval(youTubeIframe.timer);
      youTubeIframe.timer = false;
    }
    if (stateIndex === 1) {
      youTubeIframe.playTracker[targetVideoId] = true;
      youTubeIframe.videoId = targetVideoId;
      youTubeIframe.pauseFlag = false;
    }
    if (!youTubeIframe.playTracker[youTubeIframe.videoId]) {

      // Excluye la publicidad inicial

      return false;
    }
    if (stateIndex === 2) {
      if (!youTubeIframe.pauseFlag) {
        youTubeIframe.pauseFlag = true;
      } else {
        // Fix para evitar enviar varios pauses seguidos
        return false;
      }
    }

    // Elimina los eventos que no se quieren trackear

    if (eventsFired[state]) {
      fireAnalyticsEvent(youTubeIframe.videoId, state);
    }
  }

  // Funcion que dice si el evento va a Google Analytics o a Google Tag Manager
  // en función de si hay dataLayer o no.

  function fireAnalyticsEvent(videoId, state) {
    var videoUrl = 'https://www.youtube.com/watch?v=' + videoId;
    var _ga = window.GoogleAnalyticsObject;
    if (typeof window[dataLayerName] !== 'undefined' && !_config.forceSyntax) {
      window[dataLayerName].push({
        'event': 'youTubeTrack',
        'attributes': {
          'videoUrl': videoUrl,
          'videoAction': state
        }
      });
    } else if (typeof window[_ga] === 'function' &&
      typeof window[_ga].getAll === 'function' &&
      _config.forceSyntax !== 2) {
      // Envio a Google Analytics, con configuración de Custom Dimensions y
      // Custom Metrics, una para cada porcentaje medido
      window[_ga]('send', 'event', 'medicion de videos', state, videoUrl, {
        title: 'titulo a enviar',
        language: 'idioma a enviar',
        dimension1: 'contenido de la custom dimension1',
        dimension2: 'contenido de la custom dimension2',
        dimension3: 'contenido de la custom dimension3',
        metric1: (state.indexOf('Play') != -1) ? 1 : null,
        metric2: (state.indexOf('Pause') != -1) ? 1 : null,
        metric3: (state.indexOf('Watch to End') != -1) ? 1 : null,
        metric4: (state.indexOf('10') != -1) ? 1 : null,
        metric5: (state.indexOf('25') != -1) ? 1 : null,
        metric6: (state.indexOf('45') != -1) ? 1 : null,
        metric7: (state.indexOf('50') != -1) ? 1 : null,
        metric8: (state.indexOf('75') != -1) ? 1 : null,
        metric9: (state.indexOf('90') != -1) ? 1 : null
      });
    } else if (typeof window._gaq !== 'undefined' && forceSyntax !== 1) {
      window._gaq.push(['_trackEvent', 'Videos', state, videoUrl]);
    }
  }

  // Función que hace compatibles los eventos con todos los navegadores.

  function addEvent(el, name, fn) {
    if (el.addEventListener) {
      el.addEventListener(name, fn);
    } else if (el.attachEvent) {
      el.attachEvent('on' + name, function(evt) {
        evt.target = evt.target || evt.srcElement;
        // Call the event to ensure uniform 'this' handling, pass it event
        fn.call(el, evt);
      });
    } else if (typeof el['on' + name] === 'undefined' || el['on' + name] === null) {

      el['on' + name] = function(evt) {
        evt.target = evt.target || evt.srcElement;
        // Call the event to ensure uniform 'this' handling, pass it event
        fn.call(el, evt);
      };
    }
  }

  // Función que obtiene tags

  function getTagsAsArr_(tagName) {
    return [].slice.call(document.getElementsByTagName(tagName));
  }

  // Función que bindea videos como videos nuevos

  function bindToNewVideos_(evt) {
    var el = evt.target || evt.srcElement;
    var isYT = checkIfYouTubeVideo(el);
    if (el.tagName === 'IFRAME' && isYT && jsApiEnabled(el.src) && originEnabled(el.src)) {
      addYouTubeEvents(el);
    }
  }
})

De esta manera, tenemos nuestro script de medición de vídeos de YouTube con Google Analytics completo, con la inclusión de la huella de Google Analytics para realizar envíos a la propiedad correspondiente, la carga de la API de YouTube, la generación de eventos personalizados con las custom dimensions y custom metrics que queramos añadir y su posterior envío a Google para almacenar la información.

*Fuente imagen destacada: simplyzesty

Escribe tu comentario

2 × 5 =

Navegar