Blog
-
Google Analytics added sendBeacon functionality to Universal Analytics JavaScript API
New day and another not publicly published functionality (not that I was aware of) has been added by Google to Universal Analytics JavaScript API.
Till now, for example if we wanted to track our outgoing links or our PDF downloads using an event or a virtual pageview to be sure that the info was really sent to Google Analytics we needed to either write some javascript to delay the user redirection to the destination page or using the hitCallback functionality that was added to universal.js some months ago.
This approach has a problem by itself, it will delay our user’s navigation, and if for some reason our delay function or hitCallback code was failing it will prevent our users to navigate to clicked link ( that’s not good, is it ? )
So it seems that since lastest Google Chrome release ( v37 ) it’s supporting the
navigator.sendBeacon()
method . This method can be used to asynchronously transfer small HTTP data from the user’s browser to the endpoint we want using a POST request.Browsers Support:
Chrome : From v37
Firefox (Gecko) : From version 31
Internet Explorer: No supported ( This is really a surprise! )
Opera: From version 24
Safari: Not SupportedTalking about Mobile Browsers, just Firefox Mobile 31.0 supports it.
To use this feature, we will need to pass some extra object to our events this way:
ga('send', 'event', 'Clicks', 'Outgoing', 'Reddit', {useBeacon: true});
When passing this value to our event, Universal Analytics will try to send our hit using this new feature on the browsers that support it, this way our user’s navigation won’t be affected and the event info will be asynchronously sent to Google Analytics even if the user left our page, or even if the user’s closed the browser window. Yep you heard it right, we could even track when user’s close our site’s tab.
Writing navigator.sendBeacon will return undefined if it's not available in our browser
Tracking window.unload will allow us to see how many users close their browser/tab while being in our site. Let’s see how would we do it:
window.addEventListener('unload', trackUnload, false); function trackUnload() { ga('send', 'event', 'Unload', location.pathname, {useBeacon: true}); }
Let’s see a piece of pure JavaScript code to learn how this feature really works:
window.addEventListener('unload', trackUnload, false); function logData() { navigator.sendBeacon("/log", JSON.stringify({'unload': location.pathname})); }
This will send a POST request to /log path, with a POST payload inclusing the currentPathName were the user closed our browser window.
I’m sure that there are lot’s of smart people out there that could think in some good use cases for this new feature ( even if it isn’t fully supported by all browser at the moment ). Leave a comment if you have one in your head 🙂
-
Tracking HTML5 Videos with GTM
Almost all new browsers support the video playing using HTML5 including mobiles and tablets, so it may be way to embed videos that can be considerated when publishing videos on our pages. HTML5 has support for most of the videos format used on internet, even YouTube has been running an HTML5 version of their site for a long. So we’re going to teach you how you can track those videos embed’s using the built-in API and Event Listeners. We have setup a working page example at: http://stage.tags.ninja/html5.php Insert an HTML5 video player on a page, is as simple as adding this code:
<video controls="controls" width="320" height="240"> <source src="my_video_name.mp4" type="video/mp4"> </video>
So let’s start tracking our videos step by step, what features is going to have this tracking:
- Tracking of video percent played, the play button clicks, the pause button clicks, and video viewing
- It will keep a track of what % buckets of the video have been already sent to save hits.
- It will support multiple video embeds on the same page
Tracking Flow
- Check if there is any <video> tag in the current page. ( We don’t want to get the user’s browser executing this code if it’s not going to do anything )
- Wait till page’s DOM has been fully loaded ( gtm.dom )
- Fire the HTML5 Video Tracking Tag.
Tags, Rules and Macros
Tag
You can scroll down to see a fully comented code for this tag. The tag will have just 1 rule that will check for gtm.dom event from Google Tag Manager, and for the <video> tags presence that will be read using a Macro.
Rule
Macro
Thanks flys to Eliyahu Gusovsky from Analytics Ninja from who I learnt the markers piece of code.
Source Code
<script> // Let's wrap everything inside a function so variables are not defined as globals (function() { // This is gonna our percent buckets ( 10%-90% ) var divisor = 10; // We're going to save our players status on this object. var videos_status = {}; // This is the funcion that is gonna handle the event sent by the player listeners function eventHandler(e) { switch (e.type) { // This event type is sent everytime the player updated it's current time, // We're using for the % of the video played. case 'timeupdate': // Let's set the save the current player's video time in our status object videos_status[e.target.id].current = Math.round(e.target.currentTime); // We just want to send the percent events once var pct = Math.floor(100 * videos_status[e.target.id].current / e.target.duration); for (var j in videos_status[e.target.id]._progress_markers) { if (pct >= j && j > videos_status[e.target.id].greatest_marker) { videos_status[e.target.id].greatest_marker = j; } } // current bucket hasn't been already sent to GA?, let's push it to GTM if (videos_status[e.target.id].greatest_marker && !videos_status[e.target.id]._progress_markers[videos_status[e.target.id].greatest_marker]) { videos_status[e.target.id]._progress_markers[videos_status[e.target.id].greatest_marker] = true; dataLayer.push({ 'event': 'gaEvent', 'gaEventCategory': 'HTML5 Video', 'gaEventAction': 'Progress %' + videos_status[e.target.id].greatest_marker, // We are using sanitizing the current video src string, and getting just the video name part 'gaEventLabel': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1]) }); } break; // This event is fired when user's click on the play button case 'play': dataLayer.push({ 'event': 'gaEvent', 'gaEventCategory': 'HTML5 Video', 'gaEventAction': 'Play', 'gaEventLabel': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1]) }); break; // This event is fied when user's click on the pause button case 'pause': dataLayer.push({ 'event': 'gaEvent', 'gaEventCategory': 'HTML5 Video', 'gaEventAction': 'Pause', 'gaEventLabel': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1]), 'gaEventValue': videos_status[e.target.id].current }); break; // If the user ends playing the video, an Finish video will be pushed ( This equals to % played = 100 ) case 'ended': dataLayer.push({ 'event': 'gaEvent', 'gaEventCategory': 'HTML5 Video', 'gaEventAction': 'Finished', 'gaEventLabel': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1]) }); break; default: break; } } // We need to configure the listeners // Let's grab all the the "video" objects on the current page var videos = document.getElementsByTagName('video'); for (var i = 0; i < videos.length; i++) { // In order to have some id to reference in our status object, we are adding an id to the video objects // that don't have an id attribute. var videoTagId; if (!videos[i].getAttribute('id')) { // Generate a random alphanumeric string to use is as the id videoTagId = 'html5_video_' + Math.random().toString(36).slice(2); videos[i].setAttribute('id', videoTagId); }// Current video has alredy a id attribute, then let's use it <img draggable="false" class="emoji" alt="?" src="https://s.w.org/images/core/emoji/2/svg/1f642.svg"> else { videoTagId = videos[i].getAttribute('id'); } // Video Status Object declaration videos_status[videoTagId] = {}; // We'll save the highest percent mark played by the user in the current video. videos_status[videoTagId].greatest_marker = 0; // Let's set the progress markers, so we can know afterwards which ones have been already sent. videos_status[videoTagId]._progress_markers = {}; for (j = 0; j < 100; j++) { videos_status[videoTagId].progress_point = divisor * Math.floor(j / divisor); videos_status[videoTagId]._progress_markers[videos_status[videoTagId].progress_point] = false; } // On page DOM, all players currentTime is 0 videos_status[videoTagId].current = 0; // Now we're setting the event listeners. videos[i].addEventListener("play", eventHandler, false); videos[i].addEventListener("pause", eventHandler, false); videos[i].addEventListener("ended", eventHandler, false); videos[i].addEventListener("timeupdate", eventHandler, false); } })(); </script>
-
Tracking the content shared by users through AddThis with Google Tag Manager
Today we’re going to learn how to track our AddThis Widget , to know what content of our site is being shared by our users. To do it, we’re going to use the eventListeners available from AddThis API and a Social tracking Tag.
We’re going to use the same post format we used for our Tracking Disqus activity with Google Tag Manager post.
Tracking Flow
- Check if addthis has been loaded into the current page.
- Wait till page’s DOM has been fully loaded ( gtm.dom )
- Fire the AddThis Tracking Tag.
Tags, Rules and Macros
Addthis has a very useful API that will allow us to monitor and configure most of the options from the widget, one of them, is that it has Event Listeners for some of the users actions ( share, open, close ) that users can perform on the widget. We are going to use “share” event from Addthis to be able to launch a Social Tag based on the info proviced by the event. As we usually do, we are going to push the info into the dataLayer, so we can use that data afterwards to populate and fire your tracking tag.
Tracking Tag
We need to add a new Custom HTML tag, that will take care of setting up the AddThis listeners for when users shares something. ( The needed code is at the end on the post ).
Rule
We’re going to need two rules , one to fire our Addthis Tracking Tag, and it will have 2 conditions:
- Current page DOM must be loaded (gtm.dom)
- Current page must have the addthis global variable available. ( We’re using a Macro to gather this info. This Macro is defined in the next post section )
And another one that will be used to fire the our Social Tracking Hit:
Macros
Lastly we’re going to configure all the macros needed for our tracking.
We’ll need one JavaScript Variable Macro, this Macro will return the value of addthis variable ( window.addthis ) , if for any reason it isn’t available it will means that addthis has not been loaded on that current page therefore we will not fire our tracking tag. It will return “undefined” as value if it is not available ( why whould we want to fire a tag that is not going to do anything ) .
Secondly we will setup the needed macros to read the values we pushed to the dataLayer when the user shared something . The following screenshot shows the way the Macros have to be configured, the type for all of those one are “Data Layer Variable”:
Social Tracking Tag
We’re almost done, we have a new tag that is taking the care of adding the event listener and pushing the info into the dataLayer, we have one Macro that will tell Google Tag Manager if Addthis is available on the page, 3 Macros that will read the the values for our Social Tracking and finally we have a rule that will fire our tracking tag just when we need it.
So we’re just missing 1 tag, that is gonna fire a Social Interaction hit to Google Analytics. (*Note: We are using a Social Tracking Hit in thous example, but could use and Event, or a virtual page view, you will have all the info pushed to the dataLayer, so just set the Macros and tags at your convenience).
Source Code:
<script> function addThisEventHandler(evt) { switch (evt.type) { case "addthis.menu.share": // console.log(["_trackEvent", "Social Share", evt.data.service, evt.data.url]); dataLayer.push({ 'event': 'gaSocial', 'gaSocialNetwork': evt.data.service, 'gaSocialAction': 'Share', 'gaSocialTarget': evt.data.url }); break; } } // Let's set the events listener for addthis API addthis.addEventListener('addthis.menu.share', addThisEventHandler); </script>
-
Trackeando lo que comparten nuestros usuarios a través de AddThis con Google Tag Manager
Hoy vamos a aprender como hacer seguimiento de nuestro Widget de AddThis. Utilizando para ello los propios eventos que nos proporciona la herramienta y una etiqueta de Universal Analytics y tipo de tracking Social.
Para explicaros como realizar la medición, vamos a continuar con el formato de post que ya utilizamos para aprender a Trackear los comentarios en Disqus with Google Tag Manager.
Tracking Flow
- Comprobar que addthis está disponible en la página.
- Esperar a que el DOM de la página se haya cargado completamente ( gtm.dom )
- Lanzar el Tag de medición.
Etiqueta, Reglas y Macros
Addthis dispone de un API muy completo que nos permite realizar muchas acciones, una de ellas es utilizar Event Listeners para algunas de las acciones que realice el usuario con el widget. Y esto es lo que vamos a utilizar para poder lanzar eventos sociales sobre Google Analytics. Como habitualmente hacemos, vamos a realizar un push al dataLayer para después mediante macros poder recoger esta información y lanzar nuestros tags.
Etiqueta
Reglas
Tan solo vamos a utilizar una regla, que se va a encargar de lanzar nuestra etiqueta cuando sucedan dos cosas:
- Que el dom de la página haya sido completamente cargado (gtm.dom)
- Qué la página actual tenga el objeto de addthis disponible en el DOM . ( Para sacar esta información utilizaremos una Macro )
Macros
Y por último vamos a configurar una macro de tipo variable de JavaScript, esta macro se encargará de devolver el valor de esta variable ( window.addthis ) , si por algún motivo no estuviese presente significará que Addthis no está disponible en la página. Por ello entonces su valor sera “undefined“, que es la condición que hemos utilizado en la regla que se encarga de disparar el Tag.
Social Tracking Tag
Pues ya tenemos casi todo lo necesario, tenemos un tag que se encargar de enviar la información al dataLayer y tenemos una regla y unas macros que se encargan de que este tag tan solo se lance cuando addthis está disponible. Ahora nos hace falta configurar un tag nuevo para enviar esta interacción social a Google Analytics.
Código Fuente:
-
Tracking Disqus activity with Google Tag Manager
Today we’re starting a new serie of posts about how to track things with Google Tag Manager en Inside-GTM. So this time we’re going to learn how we can measure our visitors interactions with the Disqus Comments System.
The posts are going to be structured this way:
- Tracking Flow: Definition about the Definiremos que pasos vamos a seguir para poder realizar la medición
- Tags, Rules and Macros: Here you will be able to see the screenshots about the tags, rules and Macros configuration.
- Source Code: Here you’ll be able to copy the current javascript code used in Tags and Macros.
Tracking Flow
- We’ll chjeck that the current page is really using Disqus ( we don’t want to fire the tag if it’s not present! )
- We’ll wait till the page has been fully loaded before firing the Tag ( gtm.load )
- If 1 and 2 are already true, we will fire the tracking tag.
Tags, Rules and Macros
Disqus needs to have the callbacks defined before it loads. That’s is something that we can’t control in some cases, so in order to have it working in all cases, We are using Disqus API to reload their iframe with our new callbacks configuration when the page has been loaded. We are going to track for now new comments, when a visitor uses the pagination and when an users logs in into Disqus. After the visitos performs any of those actions we’re pushing the needed data to the dataLayer so we can configure a Event Tag to send that info to Google Analytics.
Tag
Rule
In this case we’re going to use just one rule, that will need to match 2 conditions:
- Current page must be fully loaded ( gtm.load Event )
- Current page needs to have Disqus iframe loaded and available within the page’s DOM. ( We’re using a Macro to gather this info. This Macro is defined in the next post section )
Macros
Finally we’re going to create a new Macro ( the one we were using as a condition on the tag firing rule ) , that will return “true” if Disqus iframe is available on the page DOM’s.
So now, everytime that a visitors leaves a comment , or performs any of the defined actions, our dataLayer will populated with that interaction data. We just need to fire an event based on the info available in the dataLayer.
Source Code:
function() { // Let's see if disqus embed iframe is available on the DOM, We don't want // to fire it in pages where it is not available var iframes = document.getElementsByTagName('iframe'); for (var i = 0; i < iframes.length; i++) { if(iframes[i].src.indexOf('//disqus.com/embed/comments/')>-1) return true; } }
-
Trackeando los comentarios en Disqus with Google Tag Manager
Vamos a empezar una serie de posts regulares sobre cómo medir cosas con Google Tag Manager en Inside-GTM. En este caso vamos a aprender cómo
medir las interacciones de los usuarios en nuestra web, si en ella disponemos del sistema de comentarios Disqus.Los posts se van a basar en la siguiente estructura:
- Tracking Flow: Definiremos que pasos vamos a seguir para poder realizar la medición
- Etiquetas, Reglas y Macros: Aquí se explicarán y mostrarán capturas de las configuraciones necesarias en nuestro contenedos
- Código Fuente: Se mostrará el código fuente utilizado en las macros y etiquetas para que sea posible copiarlo, cosa que no sería posible desde las capturas de pantalla.
Tracking Flow
- Comprobar que disqus está disponible en la página.
- Esperar a que la página se haya cargado completamente ( gtm.load )
- Lanzar el Tag de medición.
Etiqueta, Reglas y Macros
Disqus necesita disponer de la definición de los callbacks antes de que este sea cargado, es decir deberíamos tenerlo definido, antes de que el script
este cargado en la página. En muchas situacion esto no es posible por lo que utilizando el propio API de la herramienta vamos a definir los callbacks que se ejecutarán cuando los usuarios hagan un comentario, páginen o cuando se logeen. Lo que vamos a hacer es lanzar un push al dataLayer con la información de la acción del usuario, para después a través de Google Tag Manager poder lanzar un evento.Etiqueta
Reglas
Tan solo vamos a utilizar una regla, que se va a encargar de lanzar nuestra etiqueta cuando sucedan dos cosas:
- Que la página haya sido completamente cargada ( gtm.load )
- Qué la página actual tenga el script del embed de Disqus cargado. ( Para sacar esta información utilizaremos una Macro )
Macros
Y por último vamos a configurar una macro que nos va a devolver “true” en el caso de que el iframe del widget the Disqus esté disponible y cargado actualmente en el DOM de la página.
De está forma tan solo nos quedará configurar un tag de evento, y recoger las variables desde el dataLayer para enviar la información necesaria a Google Analytics.
Código Fuente:
function() { // Let's see if disqus embed iframe is available on the DOM, We don't want // to fire it in pages where it is not available var iframes = document.getElementsByTagName('iframe'); for (var i = 0; i < iframes.length; i++) { if(iframes[i].src.indexOf('//disqus.com/embed/comments/')>-1) return true; } }
-
Enviando una copia local de los hits de Universal Analytics
En muchas ocasiones por mucho que intentemos debuggear nuestras implementaciones, estas pueden fallar en algunas situaciones pues la cantidad de casuísticas que se pueden generar del lado del cliente pueden ser infinitas.
Con urchin.js y ga.js podríamos decirle a Google Analytics que enviase una copia de los hits de forma local, lo cual nos podía ayudar a ver todos los hits que se estaban envíando para poder ver si por algún motivo en una transacción no se estaban envíando de forma correcta todos los valores necesarios, o porqué en algúnas situaciones los datos no se están registrando como nosotros esperamos.
Para hacer esto vamos a utilizar las tareas ( “tasks” ) del API de Universal Analytics.
Cada vez que se utiliza el comando “send” , analytics.js ejecuta una serie de tareas para validar, construir y enviar el hit en base a protocolo de medicion ( “measurement protocol” ).
De acuerdo con la información publicada por Google, las siguiente table muestra las tareas actuales que ejecuta Universal Analytics a medida que se va cargando . Estas tareas se ejecutan en el orden en el que se muestran en la tabla.
Nombre Tarea Descripción previewTask
Aborta el hit, si tan solo se está renderizando la página para el ‘Top Sites’ de Safari. checkProtocolTask
Aborta el hit si el protocolo no es http(s). validationTask
Aborta el hit si los campos requeridos no son válidos . checkStorageTask
Aborts el hit si analytics.js está fijado para utilizar cookies y estás no están disponibles en el navegador del usuario. historyImportTask
Importa la information de las cookies __utm* para preservar el historial del usuario durante la migración a Unviersal Analytics. samplerTask
Está función se encargar de filtrar los hits de forma aleatoría en base al valor de “sampleRate“. buildHitTask
Construye el its y lo almacena en el campo “hitPayload“. sendHitTask
Envía el hit, con el payload almacenado en el campo “hitPayload“. timingTask
Genera el hit del SiteSpeed en base al sample rate fijado en “siteSpeedSampleRate“. Por lo tanto, en nuestro caso, vamos a sobreescribir la tarea “sendHitTask” para enviar una copia local de los hits, y utilizaremos el valor del campo “hitPayload” para contruir nuestro hit local.
A continuación, os muestro un pequeño snippet, donde podréis ver como realizar esto 🙂
ga('create', 'UA-XXXXXXX-YY', 'auto'); ga(function(tracker) { // Vamos a guardar la referencia a la funcion original que envía los hits var originalSendHitTask = tracker.get('sendHitTask'); // Modificamos la funcion sendHitTask para // enviar una copia local después de haber envíado // el hit a los servidores de Google Analytics tracker.set('sendHitTask', function(model) { // Vamos a recuperar los valores del payload, // para después añadirlos a nuestro hit local. var payLoad = model.get('hitPayload'); // Aquí envíamos le hit original generado por analytics.js originalSendHitTask(model); // Vamos a enviar una copia del hit a nuestro propio servidor var i = new Image(1, 1); i.src = "/__utm.gif" + "?" + payLoad; i.onload = function() { return; } }); }); ga('send', 'pageview');
Una vez que pongáis este código, esto es lo que sucederá al cargar vuestras páginas:
De esta forma podremos tener una copia local de los hits que se envien desde los navegadores de nuestros usuarios, bien para intentar buscar algún fallo en nuestras implementaciones, o si queremos saber si realmente Google Analytics procesa correctamente nuestras visitas 😉
-
Nueva herramienta para probar tus filtros de Google Analytics
Todos sabemos el peligro de jugar con los filtros de los perfiles ( ahora llamados vistas ) en Google Analytics, la posibilidad de que los hagamos mal y terminemos con datos con el formato que no queremos o con datos excluidos de forma incorrecta suele ser bastante alta. Además si nos equivocamos no hay manera de echar marcha atrás, los datos de las las horas y o incluso días en los que los filtros hayan estado configurados de manera incorrecta no serán recuperables.
Para paliar en la manera de lo posible este problema acabamos de publicar en Analytics Debugger ( Herramienta online para depurar implementaciones de Analítica Web ) una nueva funcionalidad que nos deja construir nuestros filtros viendo los resultados en tiempo real. Es decir podremos ver que datos se estarían capturando según las expresiones regulares que estemos utilizando así como podremos simular como quedarían los campos que estemos sobreescribendo.
Podéis ver el siguiente video donde se muestra cómo fácilmente podemos probar nuestros filtros y como ver en tiempo real el resultado que quedaría registrado en Google Analytics.
Con este paso Analytics Debugger deja de ser tan solo una herramienta de depurado y añade su primera herramienta que podrán utilizar los analistas para trabajar. Como hasta ahora esta utilidad es gratuita y podrá ser utilizada por cualquier usuario 🙂
-
Introducción al DataLayer de Google Tag Manager
Aunque parezca mentira hace ya casi año y medio que Google hizo público su herramienta de Tag Management. Durante todo este tiempo las actualizaciones de la herramienta ha sido continua aunque por desgracia no haya ningún changelog que reflejen los contínuos añadidos que va recibiendo la herramienta.
Por lo que voy leyendo por ahí, para la gran mayoría de la gente la herramienta no es más que la manera de moda de configurar Google Analytics ( añado el código de GTM a mi web y añado un tag de pegeview ), sin aprovechar la herramienta lo más mínimo.
Por ello vamos a hablar del dataLayer , que es como su propio nombre indica una “capa” de datos mediante la cual vamos a pasar los datos a Google Tag Manager ( recordar que todo esto será utilizable también con cualquier otra herramienta de Tag Management ) , para poder interactuar en base a esos datos.
Así pues el dataLayer no es más que un objeto que contendrá la información ( formato JSON ‘clave’:’valor’ ) que queramos tener accesible desde el Tag Manager.
Para ellos deberemos inicializarlo antes del tag de Google Tag Manager ( si bien el propio gtm lo inicializará de forma implícita ) de la siguiente manera:
<script> var dataLayer = datalayer || []; </script>
Con esto inicializaremos nuestro objecto tan solo si no lo estaba ya anteriormente, es decir si ya tuviese algún valor en el momento de ejecutarse este código se mantendrían los valores que tenga.
Por poner un ejemplo ilustrativo de esto pongamos un post de un blog, por ejemplo este mismo post
<script> dataLayer.push({ 'categoria' : 'Google Analytics', 'titulo' : 'Introducción al dataLayer de Google Tag Manager', 'autor' : 'David Vallejo', 'fecha' : '2014-02-08', 'lenguaje' : 'es', 'logeado': true, 'event' : 'pageview' }); </script>
Bien ya tenemos toda la info de la página que se está visualizando, ahora lo que tenemos que hacer es crear macros para poder acceder a los datos disponibles en el dataLayer desde nuestros tags.
Por lo tanto crearíamos una macro por cada uno de datos que tenemos de la siguiente manera:
Una vez hecho esto podremos utilizar los datos desde los tags o desde las reglas de la siguiente manera: {{NOMBRE_MACRO}} .
(more…)