Universal Analytics Plugin Online Hackathon – Dual tracking

I’ve been thinking about doing a Google Analytics related hackaton for a long time. Some months ago, I started to take a look about how Universal Analytics Plugins work and I decided that coding a plugin to all the data to a secondary property using just a plugin would be a real nice example.

For years now, I’ve sharing a lot of code that I’ve worked on, some tracking ideas too, but still I don’t consider myself a developer, if i must say it, I really think that I really suck at programming even if I can do some stuff myself.

So here I am trying to organize an online Universal Analytics Hackaton. I hope this can turn on a great change to learn from other people, and understand how plugins work!!!

Of course you may be asking what’s a “Hackathon” (don’t be shy about asking). Let’s quote the Wikipedia:

A hackathon (also known as a hack day, hackfest or codefest) is an event in which computer programmers and others involved in software development and hardware development, including graphic designers, interface designers and project managers, collaborate intensively on software projects. Occasionally, there is a hardware component as well. Hackathons typically last between a day and a week. Some hackathons are intended simply for educational or social purposes, although in many cases the goal is to create usable software. Hackathons tend to have a specific focus, which can include the programming language used, the operating system, an application, an API, or the subject and the demographic group of the programmers. In other cases, there is no restriction on the type of software being created.

GitHub Repository:

https://github.com/thyngster/universal-analytics-dual-tracking-plugin

For now I’ve pushed to the repository  with some “core” code, that “already” works.

How to load the plugin:

ga('create', 'UA-286304-123', 'auto');
ga('require', 'dualtracking', 'http://www.yourdomain.com/js/dualtracking.js', {
    property: 'UA-123123123213-11',
    debug: true,
    transport: 'image'
});
ga('dualtracking:doDualTracking');
ga('send', 'pageview');

Some stuff you need to take in mind when loading a plugin in Google Analytics:

  • The plugin needs to be hosted within your domain
  • It needs to be “initialized” AFTER the “create” method call and BEFORE the “pageview” method.
  • If for some reason the plugin crashes it may affect your data collection, please don’t use this in production before it has been fully tested.

Still it needs to be improved, for example:

  1. We don’t want to use global variables
  2. Payload size check, and based on the results send a POST or GET request
  3. Add XHR transport method
  4. Code cleanup/Best practises
  5. Plugin option to send a local copy for the hits
  6. Better debug messages
  7. Name convention improvement
  8. Any other idea?

Anyone is welcome to push code, add ideas, give testing feedback, through the Github repository or the comments on this blog post.

 

 

 

 

Keep your dataLayer integrity safe using Custom JavaScripts in Google Tag Manager

In JavaScript when you want to copy an object into another variable is not an easy as doing var myVar = myObjectVar; and you should be really careful when working with your dataLayer info in your customHtml Tags and your Custom Javascript Variables.

Let’s try to explain this is the best way I can. When  you’re doing that you’re not copying the current object data to a new variable but instead you’re pointing your new variable to the object one.

What does this mean?, that if that you change a value into your new variable that change will be reflected in the original one. Let’s see an example:

var OriginalData = {'a': 1, 'b':2};
var CopiedData = OriginalData;

CopiedData.a = "MEC!";

console.log("Old 'a' Value: ", OriginalData.a);

Before trying it in your browser console, could you please think what will be “mydata.a” value printed into the console?. If you’re thinking on a “1” value I’m sorry to say that you’re wrong:

 

You may be thinking, why “OriginalData.a” has changed if we only modified the value for our “CopiedData” object.

In programming you we can pass the data in 2 ways:

Call-by-value: This means that the data from the original variable will be copied/cloned into the new variable. 

Call-by-reference or Pass-by-reference: This means that the data on the new variable will be a pointer/reference to the original varialbe one. So if we want to print CopiedData.a , instead of returning a value, it will go to get the value to OriginalData.a (where CopiedData.a POINTS TO) .

How the data is passed in the different programming language is specific to each language, but let’s take a look on how JavaScript does it. Basically any variable type but the object will be called by value. If we do the same example as above, but instead of using an object we use a integer, we’ll be getting a different behaviour.

var OriginalData = 1
var CopiedData = OriginalData;

CopiedData = "MEC!";

console.log("Original Object 'a' Value: ", OriginalData);
console.log("Copied Object 'a' Value: ", CopiedData);

 

As you can see if the variable to be “cloned” is not an object, it will be “passed by value“.

So we need to take in mind that we may be overwriting the original object values. When working with GTM variables, this may equal with updating the original dataLayer values.

There’s not any in-built way to do a deep copy of an object in JavaScript. As we’re mostly refering to data, we could just stringify our object and then parse it again ( never use eval() for converting ).

So when trying to make a copy of some object from the dataLayer (for example when working on a Enhanced Ecommerce implementation and using variables to feed our hits). I would recomend doing it this way:

var ecommerce = JSON.parse(JSON.stringify({{ecommerce}}));

This will only work for objects not including functions/date values/etc. Just plain data. But for now it will keep our dataLayer integrity safe.

Just googleing a bit, you’ll find some functions around to make a full deep copy of an object, but we’re just working with data, so we’re not going to cover that at the moment.

Tips for working with Custom HTML & Custom JavaScript tags in Google Tag Manager

This time I’m writting down some tips for when you guys are playing around with the custom HTML tags or custom JavaScript variables not only for Google Tag Manager, but for any other TMS or website.

Most times due the projects deadlines or maybe just lazyness, the code we use (I include myself here), is not fail proof, and we need to think that we may broke some page functionality or even some page load. So using customHTML/custom JavaScript is a serious thing. Even a lot of companies are forbidden to use them in Google Tag Manager.

  1. Don’t use lazy/generic variable names

    As you all know (right) all the scripts share the same window object. So if you declare a variable

    myVariable = "myValue";

    you will then be able to get that variable value from the main window object

    console.log(window.myVariable)

    and this means that if we using some variable like “counter”, and another script uses it, it’s going to be overrided. D’oh, our loop just became a neverending loop (indeed, that’s not good).

  2. Always use “var” for declaring your variables if you are not planning to use them as a global data

    Usually you may think that declaring a variable inside a function will make it just available inside that function, but that’s not right, if you declare a variable without using “var”, it’s gonna became a global variable, if you want to try it, create a new tag an put this code on it:

    <script>
        (function(){ 
           myVariable = "myValuetest";
        })();
    </script>

    Now if you go to your console you will notice that windows.myVariable is there. Even if it was inside anonymous function, it became a global variable.

    This is the right way to do it:

    <script>
        (function(){ 
           var myVariable = "myValuetest";
        })();
    </script>
  3. Always check for the variable value before doing something with it

    Usually being a lazy programmer will lead to problems, I know that it takes a lot of time to get everything checked as it should, and our code may be working for us in our tests, but we need to think that there will be thousands of users, with different browsers, browser versions, internet connections (some things may load slow, or not even load) , pluggins installed, and that’s why we need to perform the checks in the right way, we’re interacting with a client-side tracking, so we just CAN’T cover all the possible situations.

    Take this simple screenshot as an example:

    Let’s see how should we had code the previous snippet:

    Instead of printing an error, we could have send an error event, in order to track on which pages that errors is happening, for which browsers, or at which time 🙂

  4. Be careful with the loops, always set a break in the case the condition is never met

    We may need to loop around some array, for example, we want to grab all the product SKU for our transactions to pass that data into a marketing pixel. For that we’ll need to loop thru all the ecommerce.purchase.products . but we need to be sure that our loop will end at some point. For the previous example it’s easy, as we’ll easily know when it needs to end (when there’re no mor products in the array).
    But let’s think on another example. We want to wait for some object to be available to fire something, and for that we use a setInterval to check for the variable availability each 100 milliseconds.

    Let’s see some code for this:

    (function(){
    var checkExist = setInterval(function() {
      if(typeof(window.myObject)!="undefined") {
      dataLayer.push({
        "event":"myObject-is-available-notify-gtm-with-a-push"
      });
       clearInterval(checkExist); 
       }
    
      }, 100);
      })();

    Hey, it works, it sets an interval each 100 milliseconds and get our object is already available it clears the interval. We tested it, and it works, we’re so proud of ourselves. But this time we didn’t consider what will happen IF that object NEVER gets available… yep, you’re right that code will be running forever, and depending on the code that it’s ran inside it, it may kill the user’s browser.

    If using loops in Variable you may need to take in mind that variables are being ran several times (not just once), so the problem is going to be even bigger.

    In this case we could have an incremental counter, so we could exit the interval execution, after 20 tries (20×100 = 2seconds).

      (function(){
      var counter = 0;
      var checkExist = setInterval(function() {
            if(counter > 20)
                clearInterval(checkExist); 
    
      if(typeof(window.myObject)!="undefined") {
        dataLayer.push({
          "event":"myObject-is-available-notify-gtm-with-a-push"
        });
      clearInterval(checkExist); 
      }
      counter++; 
        }, 100);
    })();

    So always think on a way for our loops to end in the case the condition is never met.

Getting super clean content reports in Google Analytics using GTM

In Google Analytics the urls are case sensitive, therefore in our content reports /index.html will be different to /Index.html, and querystring values will make Google Analytics to think that even if it’s the same page it will recorded as a new one, /index.html?cache=off and /index.html?cache=on will be recorded as 2 different pageviews for example.

The first problem its easily fixable with a lowercase filter within the views, but the querystring parameters it’s going to be a problem … I bet you’re saying that you can just add them to the Exclude URL Query Parameters list within your view configuration page and Yes! that’s right, but I’m pretty sure that you’re likely going to end having some marketing campaigns adding new parameters, or IT adding some parameters to get some funcionality switched on (like enabling some caching feature or whatever).

So today, we’ll be using Google Tag Manager to solve this problem of having all our content reports fragmented due the unexpected querystring parameters in our pages. So let’s think about it, wouldnt be easier to identify the real parameters and getting ride of the rest that are not expected for the page functionality?, If you think about it, it’s likely a better way to do it, we can know which parameters will be used in our site, but we cannot think on unexpected ones.

To achive this, we’re going to make use of just one single variable in Google Tag Manager, yeah that’s it, just one single Custom Javascript variable.

We’ll just need to configure the paramList array on the code top, and add there all the querystring parameters that we want to keep. Any other parameter that is not listed in our array will be removed from the querystring value that is going to be recorded by Google Analytics

function(){
  try{
    
        // We'll need to defined the QS values we want to keep in our reports         
        var paramsList = ["two","one","three"];

        // CrossBrowser inArray polyfill 
        if (!Array.prototype.indexOf) {  
            Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {  
                "use strict";  
                if (this == null) {  
                    throw new TypeError();  
                }  
                var t = Object(this);  
                var len = t.length >>> 0;  
                if (len === 0) {  
                    return -1;  
                }  
                var n = 0;  
                if (arguments.length > 0) {  
                    n = Number(arguments[1]);  
                    if (n != n) { // shortcut for verifying if it's NaN  
                        n = 0;  
                    } else if (n != 0 && n != Infinity && n != -Infinity) {  
                        n = (n > 0 || -1) * Math.floor(Math.abs(n));  
                    }  
                }  
                if (n >= len) {  
                    return -1;  
                }  
                var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);  
                for (; k < len; k++) {  
                    if (k in t && t[k] === searchElement) {  
                        return k;  
                    }  
                }  
                return -1;  
            }  
        }  
        var qsParamsSanitizer= function(qs,permitted_parameters){
        var pairs = qs.slice(1).split('&');
        var result = {};
        pairs.forEach(function(pair) {
            pair = pair.split('=');
            result[pair[0]] = decodeURIComponent(pair[1] || '');
        });

        var qsParamsObject = JSON.parse(JSON.stringify(result));
        for (var p in qsParamsObject){
            if(permitted_parameters.indexOf(p)==-1)
                delete qsParamsObject[p];
        }
        var rw_qs = '?' + 
                Object.keys(qsParamsObject).map(function(key) {
                    return encodeURIComponent(key) + '=' +
                        encodeURIComponent(qsParamsObject[key]);
                }).join('&');
        if(rw_qs=="?") rw_qs="";
        return rw_qs;
     }        
     return qsParamsSanitizer(document.location.search,paramsList);
    }catch(e){
       // let's let GA to use the current location.href if
       // for some reason our code fails.
       return undefined;
    }
}

Now, we only need to set our pageview tag “page” parameter so Google Analytics uses the new sanitized array instead of the one that it’s on the url.

We’re done!. Let’s see how it works with a screenshot

Now you just need to sit down, and wait some hours to start seeing your reports in a clean way and with no fragmentation. Happy analyzing!


 

 

Tricks to deal with customized Google Analytics and Google Tag Manager integrations

In the past years, I worked on implementing Google Analytlics and Google Tag Manager in a lot of differences scenearios and almost any kind of integrations. So I’m gonna show you some code snippets that may help you integrating Google Tag Manager and Google Analytics into your libraries in the best way possible.

Checking is Universal Analytics is available

Most integrations I’ve seen does check for the ga object within the DOM before trying to push something to it. This is really nice, and a check that should be done ALWAYS, but Universal Analytics allows you to change the default name for the “ga” object, so under those situations our code may not work as we’re expecting.

Luckly for us, Universal Analytics creates another variable, named window.GoogleAnalyticsObject, that will allow us to grab the current object name being used by Universal Analytics.

So using the following code will allow us to check is Google Analytics is really available even if the current name has been changed:

if(window.GoogleAnalyticsObject && typeof(window[GoogleAnalyticsObject])=="function"){ 
   // Code Here
}

Checking for current dataLayer object name for Google Tag Manager

Google Tag Manager users the “dataLayer” name by default, but it may changed to use any other name.

This piece of code will allow us to find the right dataLayer name dinamically:

var gtm_datalayer_names=[];
if(typeof(google_tag_manager)!="undefined")
    for(i in google_tag_manager){
        if(google_tag_manager[i].gtmDom==true){
            gtm_datalayer_names.push(i);        
        }        
}

The we could do something like:

window[gtm_datalayer_names[0]].push({});

We’ll even be able to send pushes to all the different dataLayer available on the current page:

if(gtm_datalayer_names.length>0){
        var i = window.gtm_datalayer_names.length;
        while(i--){
           var dlName = gtm_datalayer_names[i];
           window[gtm_datalayer_names] = window[gtm_datalayer_names] || [];                 
           window[gtm_datalayer_names[i]].push({
              'event': 'my-event-name',
              'dataLayerName': gtm_datalayer_names[i]
           });                                           
        }    
}

Debugging and monitoring GTM Variables for errors

Google Tag Manager does not throw any error when the code in a variable fails. This is not bad per se as it would save us from having our sites failing if something is not coded as it should, but it will blind us agains some minor errors that may not be noticiables, for example if our Enhanced Ecommerce is failing for a certain product, or from some specific browser.

Thanksfully we can use try{}catch(e){} to capture those errors :). And we could use it to send an event to GA so we can monitor and fix the errors easily, having also all the info about where did the error happened, which browsers, location, etc.

The main problem of sending an event within a variable error is that we may end having dozens of duplicated events for each error as variables got executed several times and not just once . The following piece of code will loop thru all the dataLayer pushes to find out if the current error has been already pushed to avoid this problem.

try{
   // JS Variable Code Goes Here
}catch(e){
    if(dataLayer.filter(function (obj) { return obj.errorMsg === e.message; }).length==0){
        dataLayer.push({'event':'variable error','errorMsg': e.message});
    }
}

Now just set an event that fires on the custom event named “variable error”, and that reads errorMsg variable value from the dataLayer.
You can easily personalize this to your needs.

Let’s see an small report for an Enhanced Ecommerce Implementation that is using Variables instead of the dataLayer values to populate the info:

debug_gtm_var_01

Those errors won’t prevent the hit to be sent, but ecommerce data will be missing on them.

But this is not where it ends, now you can use Real Time reporting to monitor your recently published container and be able to fix things in almost no time:

debug_gtm_var_02

 

Tracking Optimizely redirect type experiments

In my previous post I’ve talked about how to manage to use the native Optimizely tracking when using Google Tag Manager . Now we’re going further and we’ll learn how to track the experiment that are based on redirects in the best way possible.

So, firstly you’ll need to enable the Optimizely and Google Analytics integration. Now here is the tricky part. If we’re sending users to an experiment page that it’s based on a redirect we’ll be likely going to lost the original referral info (if not using utm parameters).  As it’s a javascript redirection, the original referrer info won’t be kept.

In case we’re lucky because optimizely will write a cookie with the original referral info, se we can read it later! :). That way we could override the referrer field within our pageview tag to keep the real attribution for those visits.

We’ll need a 1st Party Cookie variable to read this cookie value:

Then we’ll need to do use this variable in our pageview tag this way:

There we go, now even if something lands on a redirect experiment, the original referral will be tracked in Google Analytics.

Enabling Optimizely native Google Analytics Integration within Google Tag Manager

As you may already know, Optimizely has an in-built Google Analytics integration, which will allow us to track the experiments and variations being showed to a client using custom dimensions.

For enabling them, you’ll need to put the following lines after the create command and the pageview one:

window.optimizely = window.optimizely || [];
window.optimizely.push("activateUniversalAnalytics");

This is a bit tricky when using Google Tag Manager native tags, since it doesn’t allow you to execute anything after the tracker creation command.

To achive this we’ll be using a little hack ( using a Custom HTML tag ), and the tag secuencing that was released some months ago in Google Tag Manager.

Code
<script>
 
  window['ga']=window['ga']||function(){
  (window['ga'].q=window['ga'].q||[]).push(arguments);
  if(arguments[0]=="create")
  {
    window.optimizely = window.optimizely || [];
    window.optimizely.push("activateUniversalAnalytics");
  }
}
</script>

Now we’ll need to set a tracker name for our pageview tag, since Optimizely will try to set the custom dimension data to a tracker name and Google Tag Manager created a random tracker name for each fired Universal Analytics Tag.

After this we’ll need to enable Google Analytics within our experiment and define to which custom dimension index we want to send the data:

Closing “Inside GTM” Blog, all content now hosted here!

Two years ago I started “Inside GTM”, a blog focused on Google Tag Manager and other TMS tools along with @nikalytics, but we haven’t published anything since February, so we’ve agreed to close it 🙁 .

After publishing the notice in Twitter, some people asked what was going to happen with the content already hosted there, so I’m moving all the content I wrote there in my own blog, this is in this blog.

Luckily if you didn’t know about that blog, today’s is a good day for you, since you’ll discover 6 new cool posts about tracking things using Google Tag Manager.

Here is the list of the posts:

Hope you enjoy them.

#Tip – Finding Legacy GA code after migrating to Universal Analytics

 

You may have already migrated your Google Analytics Implementation to Universal Analytics. It may happen that you still have some legacy ga snippet lying around in some pages without having noticed it, for example in some landing pages that are not belong the default CMS system/templates.

But we can easily check this out just looking at Google Analytics data. It’s as easy as crossing your pageview/event reports with the “Data Source” dimension.

This dimension will be only set when using Universal Analytics endpoint. The hits sent to __utm.gif will have that dimension set as “(not set)” while Universal Analytics hit will force that dimension to be “web”.

 

So, that is!. It couldn’t be more easy, and I’d suggest to include this comprobation in your Universal Analytics migration checklist. 

In almost no time, you’ll be aware of :

  • Pages with an old tracking code.
  • Pages that may be missing the new code (if we did not remove the old one, it’s right to think that we may not tag them with the new one).
  • Pages with duplicate codes (GA + UA)