Category: web analytics

  • Google using ISPs to cache Google Analytics endpoint

    I don’t really know if this is happening users using different ISP’s but starting from today I’ve noticed that all my requests to www.google-analytics.com were being served from a not usual but familiar IP address range, and the response time was just 9ms. Hey just a great improvement from the 42ms of average I’m usually getting from Google Analytics servers.

    thyngster@hq:~$ ping www.google-analytics.com
    PING www-google-analytics.l.google.com (212.142.160.238) 56(84) bytes of data.
    64 bytes from cache.google.com (212.142.160.238): icmp_seq=1 ttl=59 time=8.80 ms
    64 bytes from cache.google.com (212.142.160.238): icmp_seq=2 ttl=59 time=9.12 ms
    64 bytes from cache.google.com (212.142.160.238): icmp_seq=3 ttl=59 time=8.66 ms
    64 bytes from cache.google.com (212.142.160.238): icmp_seq=4 ttl=59 time=8.19 ms
    
    --- www-google-analytics.l.google.com ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3004ms
    rtt min/avg/max/mdev = 8.190/8.698/9.129/0.344 ms

    That’s is, Google Analytics files are hits are being server locally from my ISP. It doesn’t seems to be a problem with my ISP, since it’s the Google Nameservers who are delegating that dns response:

    thyngster@hq:~$ dig +trace www.google-analytics.com
    
    ; <<>> DiG 9.9.5-3-Ubuntu <<>> +trace www.google-analytics.com
    ;; global options: +cmd
    .                       443274  IN      NS      b.root-servers.net.
    .                       443274  IN      NS      j.root-servers.net.
    .                       443274  IN      NS      e.root-servers.net.
    .                       443274  IN      NS      a.root-servers.net.
    .                       443274  IN      NS      m.root-servers.net.
    .                       443274  IN      NS      h.root-servers.net.
    .                       443274  IN      NS      i.root-servers.net.
    .                       443274  IN      NS      c.root-servers.net.
    .                       443274  IN      NS      d.root-servers.net.
    .                       443274  IN      NS      k.root-servers.net.
    .                       443274  IN      NS      l.root-servers.net.
    .                       443274  IN      NS      g.root-servers.net.
    .                       443274  IN      NS      f.root-servers.net.
    ;; Received 531 bytes from 212.142.144.66#53(212.142.144.66) in 295 ms
    
    com.                    172800  IN      NS      m.gtld-servers.net.
    com.                    172800  IN      NS      l.gtld-servers.net.
    com.                    172800  IN      NS      k.gtld-servers.net.
    com.                    172800  IN      NS      j.gtld-servers.net.
    com.                    172800  IN      NS      i.gtld-servers.net.
    com.                    172800  IN      NS      h.gtld-servers.net.
    com.                    172800  IN      NS      g.gtld-servers.net.
    com.                    172800  IN      NS      f.gtld-servers.net.
    com.                    172800  IN      NS      e.gtld-servers.net.
    com.                    172800  IN      NS      d.gtld-servers.net.
    com.                    172800  IN      NS      c.gtld-servers.net.
    com.                    172800  IN      NS      b.gtld-servers.net.
    com.                    172800  IN      NS      a.gtld-servers.net.
    com.                    86400   IN      DS      30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
    com.                    86400   IN      RRSIG   DS 8 1 86400 20141130170000 20141123160000 22603 . KcH1dZuKA0dS9oDK2Wy8Iq/axbkR1/Dd0OnU3zgAUI88ym4rezyeHIJQ z6f7T2Ym2Ese+4ma1n0/9Q8iMvvTw8LAv+0ICzCuBtGQuCY3LhJ8uaRG AHoCVwv772zkalcRQuq07cxfllZmNykMyUgPcp/ViyQZtWcB/3eGFwJj mII=
    ;; Received 748 bytes from 198.41.0.4#53(a.root-servers.net) in 915 ms
    
    google-analytics.com.   172800  IN      NS      ns2.google.com.
    google-analytics.com.   172800  IN      NS      ns1.google.com.
    google-analytics.com.   172800  IN      NS      ns3.google.com.
    google-analytics.com.   172800  IN      NS      ns4.google.com.
    CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0QFMDQRCSRU0651QLVA1JQB21IF7UR NS SOA RRSIG DNSKEY NSEC3PARAM
    CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20141129055344 20141122044344 48758 com. mKMCjqttB9SBFDa9+UYTil3/baYuVXdwSsrBjWybi05WCkGUvVBe14yF HrrQUMAue5E8qBwbESuqqhwgEdspaybxel8gCwFHFCAAl12Ok5VGtMCK gYlu3/nXwfFtN46WYMPU3k83n1j/UhSypjE6OajPWV/nKVzcKfHwYQ39 NM4=
    PMC1T49FLPALQ6HR7VPE0GQRFGSM38PS.com. 86400 IN NSEC3 1 1 0 - PMCAVG0VD8T2G2NPG5K6HV9F6T4VRMVT NS DS RRSIG
    PMC1T49FLPALQ6HR7VPE0GQRFGSM38PS.com. 86400 IN RRSIG NSEC3 8 2 86400 20141128052656 20141121041656 48758 com. cPUz3qVmzylXFxkLa870sFXMxAjAodtPcK3Nkoric83FKdaegulpxd9c eoY5zs3q5fKDNz8MjSkp4GO6MXsrbU2zOi9mueWmhVbb5OPAW7Od0DNg C6g+fSCRbIaOzsFHStWry9i7Rj9ZKPW8tayKQWuP2+p7FyTfATeg5IBA Jto=
    ;; Received 681 bytes from 192.41.162.30#53(l.gtld-servers.net) in 297 ms
    
    www.google-analytics.com. 86400 IN      CNAME   www-google-analytics.l.google.com.
    www-google-analytics.l.google.com. 300 IN A     212.142.160.238
    www-google-analytics.l.google.com. 300 IN A     212.142.160.223
    www-google-analytics.l.google.com. 300 IN A     212.142.160.240
    www-google-analytics.l.google.com. 300 IN A     212.142.160.229
    www-google-analytics.l.google.com. 300 IN A     212.142.160.234
    www-google-analytics.l.google.com. 300 IN A     212.142.160.230
    www-google-analytics.l.google.com. 300 IN A     212.142.160.251
    www-google-analytics.l.google.com. 300 IN A     212.142.160.212
    www-google-analytics.l.google.com. 300 IN A     212.142.160.218
    www-google-analytics.l.google.com. 300 IN A     212.142.160.216
    www-google-analytics.l.google.com. 300 IN A     212.142.160.208
    www-google-analytics.l.google.com. 300 IN A     212.142.160.249
    www-google-analytics.l.google.com. 300 IN A     212.142.160.241
    www-google-analytics.l.google.com. 300 IN A     212.142.160.227
    www-google-analytics.l.google.com. 300 IN A     212.142.160.245
    www-google-analytics.l.google.com. 300 IN A     212.142.160.219
    ;; Received 342 bytes from 216.239.32.10#53(ns1.google.com) in 42 ms
    

    So it seems that’s not really my isp who’s acting by it’s own serving me the ga.js/analytics.js and receiving my hits to the Google Analytics endpoint in some of their caching servers.

    ga_caching

    Actually even if a 304 Not Modified response code is being returned, hits are being registered in Google Analytics, so that shouldn’t be something about I should care about at the moment. I must add that ssl.google-analytics.com is not being cached for me at the moment:

    thyngster@hq:~$ host ssl.google-analytics.com
    ssl.google-analytics.com is an alias for ssl-google-analytics.l.google.com.
    ssl-google-analytics.l.google.com has address 74.125.230.62
    ssl-google-analytics.l.google.com has IPv6 address 2a00:1450:4003:807::101e
    

    I must say that this looks like a good thing for our Google Analytics implementations as hits will be sent faster by our user’s browsers, but in any case if you have any server-side implemention on Google Analytics using the Measurement Protocol, I’d add the “z” parameter to avoid any kind of malfunction on those cache servers preventing the hits being sent to real Google Analytics endpoint , even if that parameter is not obligatory ( it just needs to be a randomly generated number ).

    As I said I noticed this today, I’m not sure since when it has been up, or if Google is doing the same with any other ISPs . I think that they have some agreements with some isp’s to caché YouTube content too, saving bandwidth to Google and the ISP’s and giving to users a better experience while viewing videos.

    I tried with different browsers, different computers, different Operating systems and I’m experiencing the same behaviour for all of them, so I’m discarding some kind of configuration by me.

  • Protected: Keeping your Google Analytics clientId value as long as possible

    This content is password protected. To view it please enter your password below:

  • 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 Supported

    Talking 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

    1. 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 )
    2. Wait till page’s DOM has been fully loaded ( gtm.dom )
    3. Fire the HTML5 Video Tracking Tag.

    Tags, Rules and Macros

    Tag

    html5_video_gtm_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

    html5_video_gtm_rule

    Macro

    html5_video_gtm_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>

  • 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

    1. Comprobar que addthis está disponible en la página.
    2. Esperar a que el DOM de la página se haya cargado completamente ( gtm.dom )
    3. 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

    addthis_tag

    Reglas

    Tan solo vamos a utilizar una regla, que se va a encargar de lanzar nuestra etiqueta cuando sucedan dos cosas:

    1. Que el dom de la página haya sido completamente cargado (gtm.dom)
    2. Qué la página actual tenga el objeto de addthis disponible en el DOM . ( Para sacar esta información utilizaremos una Macro )
    addthis_rule

    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.

    gaSocialTag

    Código Fuente:

  • 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

    1. Check if  addthis has been loaded into the current page.
    2. Wait till page’s DOM has been fully loaded ( gtm.dom )
    3. 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 ).

    addthis_tag

    Rule

    We’re going to need two rules , one to fire our Addthis Tracking Tag, and it will have 2 conditions:

    1. Current page DOM must be loaded (gtm.dom)
    2. 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 )
    addthis_rule

    And another one that will be used to fire the our Social Tracking Hit:

    social_rule

    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 ) .

    addthis_macro

    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_tag_macros

    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).

    gaSocialTag

    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 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

    1. Comprobar que disqus está disponible en la página.
    2. Esperar a que la página se haya cargado completamente ( gtm.load )
    3. 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

    disqus_tracking_tag

    Reglas

    Tan solo vamos a utilizar una regla, que se va a encargar de lanzar nuestra etiqueta cuando sucedan dos cosas:

    1. Que la página haya sido completamente cargada ( gtm.load )
    2. Qué la página actual tenga el script del embed de Disqus cargado. ( Para sacar esta información utilizaremos una Macro )
    tracking_disqus_rule

    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.

    isDisqusAvailableMacro

    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;
        }
    }
    
  • 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

    1. We’ll chjeck that the current page is really using  Disqus ( we don’t want to fire the tag if it’s not present! )
    2. We’ll wait till the page has been fully loaded before firing the Tag ( gtm.load )
    3. 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

    disqus_tracking_tag

    Rule

    In this case we’re going to use just one rule, that will need to match 2 conditions:

    1. Current page must be fully loaded ( gtm.load Event )
    2. 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  )
    tracking_disqus_rule

    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.

    isDisqusAvailableMacro

    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;
        }
    }
    
  • 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 TareaDescripción
    previewTaskAborta el hit, si tan solo se está renderizando la página para el ‘Top Sites’ de Safari.
    checkProtocolTaskAborta el hit si el protocolo no es http(s).
    validationTaskAborta el hit si los campos requeridos no son válidos .
    checkStorageTaskAborts el hit si analytics.js está fijado para utilizar cookies y estás no están disponibles en el navegador del usuario.
    historyImportTaskImporta la information de las cookies __utm* para preservar el historial del usuario durante la migración a Unviersal Analytics.
    samplerTaskEstá función se encargar de filtrar los hits de forma aleatoría en base al valor de “sampleRate“.
    buildHitTaskConstruye el its y lo almacena en el campo “hitPayload“.
    sendHitTaskEnvía el hit, con el payload almacenado en el campo “hitPayload“.
    timingTaskGenera 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:

    local_hits_universal_analytics

    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 🙂