How to keep your returning user’s legacy data when switching domain name

When we’re switching a site domain name we always have in mind some basic steps to take in mind so the migration doesn’t end being a mess. One of those steps is usually 301-ing our old domain content to the new one, but we never think on how will this affect our current Google Analytics data.

Universal Analytics cookie is based on the domain hostname, so if we switch the current domain a new cookie set will be created along with a new client ID, forcing that all the visits we redirect will end being new visitors. This mean we’ll be losing ALL our previous attributions/history data for returning visitors., doh!

This time, we’ll try to mitigate this problem using Google Tag Manager and some Mod Rewrite (htaccess) magic.

We’ll be using Apache’s Rewrite module to read the current user “_ga” cookie and passing it along our redirection, then from GTM we’ll force the clientId within our tracker in order to keep our old users clientId for our new domain 🙂

Below you can find our .htaccess. As you can see we check for _ga cookie value, and then we redirect the user to the new domain with a new parameters named “_mga” , that is going to hold the _ga cookie value and the timestamp.

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_COOKIE} _ga=([^;]+) [NC]
RewriteRule ^(.*)$$1?__mga=%1\.%{TIME} [R=301,QSA,L]
RewriteRule ^(.*)$$1 [R=301,QSA,L]

You may be asking yourself about why we are adding the current timestamp (%{TIME}) as a parameter value. The reason is pretty simple, we don’t want someone sharing that url to someone else and end having a lot of users sharing the same clientId, do we?

We’ll use that value later on Google Tag Manager to check is the redirection was generated less than 120 seconds ago if not we’ll just return any value. This is how native Universal cross-domain feature works too!

if ({{__mga.timestamp}}) > 120)

If _mga.timestamp and current user timestamp values substract is higher than “120”,  it means it was generated more than 2 minutes ago, so we don’t want to push any clientId back on this case.

The current format for the %{{TIME}} value from mod rewrite is the following:


And it will likely be using the UTC timezone. This is important since the check will be made client-side, and we’re gonna need to check the current user time in UTC time, not the current client timezone.

GTM Configuration

On the Google Tag Manager side, we’ll need one variable that will take care of grabing the _mga value,  and from there we’ll get the clientId and the link generation time.

Then we’ll be checking the current user browser’s UTC timestamp to see if this link was generated less than 120 second ago, to know if we should be returning any value.

Grab the variable code bellow:

    // Let's grab our custom linker value from QS
    var _mga_linker_value =[^&]*)/)[1].split('.').pop();

    // Let's convert the YYYYMMMDDHHMMSS date to timestamp format
    var _mga_date = new Date(_mga_linker_value.slice(0, 4), _mga_linker_value.slice(4, 6) - 1, _mga_linker_value.slice(6, 8), _mga_linker_value.slice(8, 10), _mga_linker_value.slice(10, 12), _mga_linker_value.slice(12, 14));

    // Let's add the current browser timezone offset
    var _mga_timestamp_utc = Math.round(_mga_date*1/1000)-new Date().getTimezoneOffset()*60;

    // This is the current browser UTC time
    var _browser_timestamp_utc = new Date()*1;

    // This is going to be the total seconds diff, between linker creation time and current user's browser time
    var _linking_offset_in_sec = Math.round(_browser_timestamp_utc/1000 - _mga_timestamp_utc);

    // Let's force the clientId value ONLY if the time difference is less than 2 minutes

Now we only need to use the returned value by this variables as the “clientId” value on our tracker this way:

Of this this may not be only applied for Google Analytics but for any other cookie value you want to keep, just modify the code to grab any other cookie value you may need

Google Tag Manager event tracking using data attribute elements

On the last #tip we talked about how to debug/qa our data attributes , and now we’re going to learn about how to natively track events/social interactions within Google Tag Manager .

We’re going to learn it, basing our tracking on Google Analytics Events and Social Interactions. Of course this can be expanded to any other tool just changing the data attributes, but hey, this is about to learning not about give me a copy and paste solution.

Let’s start saying that data-* attributes it’s and standard HTML5 mark up that we can use to manage our page functionality based on that data instead of relaying on classes or id.
A data attribute is intended to store values that are mean to the page or application and that doesn’t fit in any other appropiate attributes.

In our care the data that we’re storing is the hitype that we’ll be firing. In our example it could an “event” or a “social interaction” . For this we’re setting a data attribute named “wa-hittype“, and this attribut will hold the current hit to be fired, in our case “event” or “social”.

We’ll be using some other data attributes to define our events category, action, label, value and non-interactional switch, please take a look to the following table for more details:

Data Attr Description
data-wa-hittype Type of hit we want to fire on user's click
data-wa-event-category The Category value for our event
data-wa-event-action The action value for our event
data-wa-event-label *optional. The label for our even
data-wa-event-value *optional. The value for our event if any
data-wa-event-nonint *option. Is the event non interactional?

Let’s check an example:

 data-wa-event-action="Add To Cart" 
>Add To Cart<a/>

So we have a data attribute that will allow us to know when fire a tab based on a CSS selector, and we’ve too all the info needed to populate the information for our event.

Next step is to configure some variables to read these values when the user clicks on the element.

So now when the user clicks on some element, we’ll have all our event needed data on those new variables. Let’s work on the trigger that will make our tag to fire.

We’re using the In-build {{Click Element}} Variable and some magic with a CSS Selector.

There we’re, now we just need to setup our event tag, add our variables to the tag fields, and set the trigger on this new event tag.

Now everytime you need to track a new click on some page element, you’ll just need to ask the developers to add some “standard” data mark-up to the right element.  Even if you do something wrong, the variables will take care of fixing the values were possible (like an event value expecting an integer value instead of a string) or setting a right boolean value for the non-interactional switch for the event.

Any suggestion or improvement to this tracking method is welcome 🙂

P.D. Yeah! I know I talked about tracking Social Interactions too, but I’m pretty sure that you’ll be able to figure it out. Think about like a good moment to learn how to do things instead of just trying to copy and paste and hoping it will work.

GAUPET Release: Google Analytics User Permissions Explorer Tool

Some months ago I asked some friends to test a new tool I was working on and past week I released something close to an open alpha, today after pulling some details, a new UI redesign 100% mobile compatible. I’m announcing the GAUPET release.

At first I named it as GA Governance Tool, but after some interesting chat with the “osom” Yehoshua Coren . I(we)’ve decided to change the tool’s name to something that it’s closer to what it is and here is it: GAUPET , which stands for Google Analytics User Permissions Explorer Tool. (yep, you’re right I didn’t rack my brain on this one)

You can find It the the following link : GAUPET

This will allow you to easily manage and pivot all your Google Analytics users and permissions in order to have a clear view of your current accounts User Governance status.

GAUPET will allow you to gather all your account user emails and permissions and draw them into an interactive pivot table. Even will allow you to merge different accounts users within the same report (thanks goes to Peter O’neill for this and another nice suggestions that will come in a future).

The tool comes with some predefined reports, but you will be able to pivot any data in the way you need. Just drag and drop the fields that’s it!.

The included fields are:

  • Email Address
  • Email Domain
  • Access Level
  • Account ID
  • Account Name
  • Account Access Rights
  • Account Permissions
  • Property ID
  • Property Name
  • Property Access Rights
  • Property Permissions
  • View ID
  • View Name
  • View Access Rights
  • View PermissionsLet’s take a look to a sample the report for user’s with view access:

    I’m offering this tool for free, and I’m hosting it for free, and this means that it’s offered “as it is”. Still you’ll have a feedback section on the page to report bugs, or ask for new features and I’ll try to make updates in my free time.

    Extra thanks fly to Damion Brown , Ani Lopez , Simo Ahava , Natzir Turrado , Doug Hall and Brian Clifton for their comments and testing. #tip Each of them worth a follow 🙂

#Tip – How to quickly debug/qa data attributes

With the years I learned that using CSS selectors to track user actions is really great but sadly I learned too that it’s really dangerous too.

It’s true that we won’t need to ask the IT team to add some dataLayer or ga pushes into the page, and therefore saving a lot of precious time, but in the other side, any single page update or testing will break our tracking.

Now I try to use data attributes whereas is possible, since those are more likely going to be kept for layout updates.

Checking elements for data attributes can be a tedious task, so I’m going to show you a little piece of code that I hope will make your life easier if you based some of your implementations on data attributes.

On this little snippet is where the magic happens:

(function() {
    var elements = []'*')).filter(function(el) {
        if (typeof (el.dataset) != "undefined")
            return Object.keys(el.dataset).length != 0;
    var data = [];
    var i = elements.length;
    while (i--) {
        var el = JSON.parse(JSON.stringify(elements[i].dataset));
        el["_element_type"] = elements[i].nodeName;


As an example I’m going to show you the output for Google Tag Manager‘s Homepage.

This has been a great time saver for me. Hope you find it useful too 🙂

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:

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', '', {
    property: 'UA-123123123213-11',
    debug: true,
    transport: 'image'
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.





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

        // 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){
                delete qsParamsObject[p];
        var rw_qs = '?' + 
                Object.keys(qsParamsObject).map(function(key) {
                    return encodeURIComponent(key) + '=' +
        if(rw_qs=="?") rw_qs="";
        return rw_qs;
     return qsParamsSanitizer(,paramsList);
       // 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=[];
    for(i in google_tag_manager){

The we could do something like:


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

        var i = window.gtm_datalayer_names.length;
           var dlName = gtm_datalayer_names[i];
           window[gtm_datalayer_names] = window[gtm_datalayer_names] || [];                 
              '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.

   // JS Variable Code Goes Here
    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:


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:



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 || [];

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.

    window.optimizely = window.optimizely || [];

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:

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