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.
Time to close the gtm blog … it was fun while it lasted
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.
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).
This time, we’ll be using Google Tag Manager itself, to find pages in our site that may be missing Google Tag Manager. Ok, it may sound strange, but was not able to find any other way to say it .
Basically we’re going to use a custom html tag, to detect is the previous page had loaded Google Tag Manager code.
To achive this we’ll be using a single Custom HTML tag ,a cookie and the onbeforeunload event.
The following flow chart will show you the logic that we’re going to follow to detect the pages that are missing the Google Tag Manager snipper for our site.
So we’ll create a new custom HTML tag (that will be fired for ALL pages default trigger), and then add the following code to it, remember to update the “hostName” variable value to your domain root:
<script>
(function(){
// Change this to your root domain name
var hostName = 'thyngster.com';
// On before Unload
window.onbeforeunload = function(e) {
expire = new Date();
expire.setTime(new Date()*1+10*1000);
document.cookie = "__ttt="+escape(1) + ";expires="+expire.toGMTString()+ ";domain=."+hostName+";path=/";
};
// If user's coming from elsewhere but our domain, exit.
if(location.hostname.split('.')[location.hostname.split('.').length -2].length==2)
var rootDomainName = location.hostname.split('.').slice(-3).join('.');
else
var rootDomainName = location.hostname.split('.').slice(-2).join('.');
if(document.referrer.indexOf(rootDomainName)==-1)
{return;}
function isCookiePresent(name) {
match = document.cookie.match(new RegExp(name + '=([^;]+)'));
if (match) return true; else return null;
}
if(!isCookiePresent('_ttt')){
dataLayer.push({
'event':'missingtag',
'referrer': document.referrer
});
document.cookie = '__ttt=; expires=Thu, 2 Aug 2001 20:47:11 UTC; domain=.'+hostName+';path=/';
}
})();
</script>
Ok, that’s all!
Now we could create a new Event tag that fires when the event equals to “missingtag” to send that data to Google Analytics.
At the moment, Google Tag Manager listeners are limited to Form Submits, Link Clicks and Clicks (for any DOM element). We are going to write a custom listener for hover intents by users. This means that we’re not only to do something when the user pass the mouse pointer over an element, but instead we’re waiting a certain time with the mouse over the element before submitting the action to GTM.
For this we’re going to use the mouseenter and the mouseleave javascript events.
The mouseenter event is fired when the mouse is moved over a DOM element, e mouseleave in the other side is fired when the mouse leaves the DOM Element.
So we are going to start a time, when the mouseenter event occurs, and then the mouseleave event to disable the previous time. This way, if the pointer is not over an element for the set time, nothing will be sent to Google Tag Manager.
Instead of pushing our data as we usually do, this time we’ll do it the same way Google Tag Manager does with it’s built-in listeners, so we’ll be pushing a gtm.hover event to the dataLayer that will look this way:
We’ll have the current gtm.element info, and the gtm.elementClasses , gtm.elementId as we have with the others listeners in Google Tag Manager to allow us to set our triggers.
We’ll need to create a new tag, let’s call it for example : “TOOL – Hover Intents Listener” and let’s put the following code into that tag:
// Tracking Top Links Hover Menus
function trackHoverIntent(selector, time) {
var timeoutId;
var elements = window.document.querySelectorAll(selector);
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('mouseenter', function(event) {
var targetElement = event.target || event.srcElement;
var classes = targetElement.className;
var id = targetElement.id;
if (!timeoutId) {
timeoutId = window.setTimeout(function() {
dataLayer.push({
'event': 'gtm.hover',
'gtm.element': targetElement,
'gtm.elementClasses': classes,
'gtm.elementId': id,
'gtm.elementHoverTime': time
});
timeoutId = null;
}, time);
}
});
}
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('mouseleave', function() {
if (timeoutId) {
window.clearTimeout(timeoutId);
timeoutId = null;
}
});
}
}
#Tip: Remember to put the code above betweentags if you don’t wanna inject a bunch of code into your visible HTML code.
Then we’ll need to add the listeners to the elements we want this way:
trackHoverIntent('img.thumbnail', 1500);
For example this code above will send a gtm.hover event everytime the visitor moves his mouse over an image with the class “thumbnail” for more than 1.5 seconds.
I’m going to share some of the tips and tricks I’ve learnt (and that I use on my daily basics work) in the almost past 3 years since Google Tag Manager was released.
Tip #1 – Grabbing a dataLayer value from the console
If we want to grab the current value in the Google Tag Manager’s dataLayer, it offers a built-in get method for it. When GTM loads a global object is created named google_tag_manager, that has a key that is the current GTM Id value.
google_tag_manager["GTM-XXXX"]
And it the we can get a dataLayer value using dataLayer.get(‘value’)
This will return the current value for the ‘event’ key, at the time we execute it. As all sites have a different GTM Id string, we could use it this way to it works on any site, as the Id will be grabbed dinamically:
Tip #2 – Using console.table for a fancy view of your objects
Most common use of the “console” command is to print values into your console tab, but we can do some other nice things, like easily printing a full object in a table using the “console.table” command.
For example for printing the whole dataLayer into a fancy table like this:
console.table(dataLayer);
But this has became a must for me, when trying to debug my Enhanced Ecommerce implementations, for example for the products impressions, cart content, or for the transactions. We could view with a quick look if all our data is there, and in the format we really want. It’s so easy to detect any misspelling on the key’s, or some wrong typed key in some of the pushes, or whatever.
Combining it with the previous tip is even more helpful. Here is an example for checking the sent product items within an standard ecommerce push for Google Tag Manager:
Tip #3 – Printing the dataLayer in a plain text format
Any browsers allows you to print your dataLayer just typing it into the console, but when you have a large pushes it’s a bit difficult to search for the data, or if we have a lot of pushes you may end going crazy trying to look for something.
All browsers have the JSON object that can easy and help us debugging and checking our dataLayer. We can get a plain text version of our dataLayer using the following command:
JSON.stringify(dataLayer,true,"\t")
Tip #4 – Beautifying JavaScript code with Chrome
Most of the actual scripts are minified to save space, and in some way to ofuscate the code. If you need to dig inside the pages code it’s difficult to find things if the code is ofuscasted/uglfied/minified, and till now I’ve been copying the JavaScript code, copying it on some online service like ( asdad ) and copying the returned code back to my editor, what takes a lot of time.
Today by a lucky change, I’ve found that Chrome DevTools already has an in-built code beautifier feature!.
One of the most common headaches while implementing the ecommerce tracking on a site is trying to match the tracked transactions by the shop backend to Google Analytics. As most tracking solutions are JavaScript based, there’s a small chance of losing some of them and there’s nothing we can do without playing with the measurement protocol and some server-side tracking.
Another problem that is usually present is having duplicated transactions. And this hopefully is something we can prevent with some code.
We can setup a tag to write a cookie each time a visitor views our “thank you” page, that is not a bad approach, but that way we won’t be sure that the transaction has been really tracked on Google Analytics.
We’re going to use the hitCallback feature available for Universal Analytics, to set the cookies just right after the data has been successfully sent to Google Analytics.
We’ll need to set the hitCallback value in our Google Tag Manager Tag to a Custom JavaScript Variable. As I was pointed by Simo Ahava on Twitter , hitCallback is expecting a function, so we’re going to return a function that does the following:
1. Grabs the current transactionId from the dataLayer
2. Checks for the “transactions” cookie
2.1. If if doesn’t exists we’ll create it with the current transactionId value
2.2. If the cookies already exists, we’ll check the current values, and if the current transaction is not there, we’ll add it.
To avoid having a new cookie for each transaction, we’ll be using just one cookie with all the transactions joined by a pipe ( “|” ) symbol.
Ok, now every time that a transaction hit is sent to Google Analytics, the current transactionId will be added to our tracking cookie.
We’ll need a 1st party variable too to grab the transacctions cookie this way:
You may noticed that the first 2 lines of the code is checking for the transactionId, this is because in this example we’re using the Enhanced Ecommerce feature and populating the transaction info from the dataLayer, and we don’t want to do anything for all the pageviews on the site but just for our thankyou page one. You may need to tune this for your needs.
Ok, let’s move on. Now we’ll need to add another customJS variable to check if the current transaction is already in the cookie, and we’ll use this variable to create a blocking trigger for our tag.
I’ve named it as “Should I Track Transaction”, (yeah, not the best name), but it helps to understand the trigger:
We only need to add this blocking rule to our pageview tag and we’ll be finish.
Let’s do a resume of the tracking flow:
“Should I Track Transaction”, will return “blockTransaction” if the current transactionId is present in our tracking Cookie
“Block Transaction” Trigger will block the pageview tag firing if #1 is true.
If the first 2 points are not met, the pageview tag will be fired.
When the pageview tag is fired, the hitCallback function will be executed right after the transactions has been sent to Google Analytics Endpoint
The hitCallback will execute the function returned by the variable “transactionCallback”, which will be in charge of creating the cookie if is doesn’t exist and adding the current transactionId to it.
I know that this will not be functional for some cases and there’re a lot of different implementations, sending the transaction based on events, sending the transactions based on a macro value (enhanced ecommerce), but that’s something you’ll need to figure out as isn’t there any stardard tracking solution. Hopefully you have learnt how hitcallbacks work in Google Tag Manager and you could get it working for your enviroment, if not drop a message in the post and I (or any other reader), will try to help you.
function()
{
// If isn't there a transaction ID, we don't need to do anything.
if(!{{transactionId From DL}})
return;
return function(){
var transactionId = {{transactionId From DL}};
if({{transactions}}){
var trackedTransactions = {{transactions}}.split("|");
if(trackedTransactions.indexOf(transactionId)==-1){
trackedTransactions.push(transactionId);
var d = new Date();
d.setTime(d.getTime() + (180*24*60*60*1000));
var expires = "expires="+d.toUTCString();
document.cookie = "transactions=" + trackedTransactions.join('|') + "; " + expires;
}
}else{
var trackedTransactions = [];
trackedTransactions.push(transactionId);
var d = new Date();
d.setTime(d.getTime() + (180*24*60*60*1000));
var expires = "expires="+d.toUTCString();
document.cookie = "transactions=" + trackedTransactions.join('|') + "; " + expires;
}
}
}
Should I track transaction Code
function()
{
if(!{{transactionId From DL}})
return;
var transactionId = {{transactionId From DL}};
if({{transactions}}){
var trackedTransactions = {{transactions}}.split("|");
if(trackedTransactions.indexOf(transactionId)>-1)
{
return "blockTransaction";
}
}
}
If you’re migrating from classic Google Analytics (_gaq object) to Universal Analytics, or planning to migrate your old hardcoded events to use Google Tag Manager you may have run in the case that not all old tracked was really removed from the site by the client. And it’s really hard to find it out.
We’ll learn today how to track this situation natively using just in-built Google Tag Manager features and allowing us to track all those all coded tracked within our Google Analytics data using events, so we can fix them and without the need of crawling your website.
We’re going to use Google Tag Manager CSS Selectors to find out those old tags and then firing an events to help us to easily view in GA where are those old codes hidden without needing to deep-crawl the sites and helping us having a clean migration.
We’ll need to create a new variable in Google Tag Manager, as it’s shown in the screenshot below:
This variable will look for all onclick attributes available in the current page, containing the “_gaq” string. If there’s any onclick containing a _gaq push, the whole value of the onclick attribute will be returned, if not the value for this variable will be “null”. Knowing this let’s configure our trigger that is going to be fired when there’s a match.
Now we only need to setup an Event to record the pages where the old hardcoded tracking is present.
We’ll record the current page path, along with the full push that was found.
Note: We’ll need to set the event Non-Interaction switch to true, to avoid messing the bounce rate. After this an event will be fired is any old _gaq push is found within all the onclick attributes in the current page.
I was looking for something new to track within the websites interactions, and I decided to give a try to track the user’s intent to print our pages.
So I’m going to show you my own approach for tracking this user action using Google Tag Manager.
We’ll need to create a new tag with the following code will allow us to track the user printing intent when he clicks on printing from the File Menu or when he uses the keys shortcut (Control-P on Windows)
It may happen that a browser does have support for the onBeforePrinting event and mediaQueries, so the code is looking into the dataLayer for a previously send printing event to avoid duplicate events.
Reminder: The code above needs to be wrapped between <script></script> tags or you will end having this text code injected on your page.
Just to be safe, we’ll run this tag on the “gtm.dom” event. Then we’ll have a push into the dataLayer telling us the user tried to print the current page, and we’ll be able to fire an event for Google Analytics or use it with any other tool.
If you using Facebook, Twitter, Github or any other service to autenticate your users, you may have noticed that they end showing up as referral traffic from the oauth service.
User lands from CPC -> Logs in -> Respawns a new visit as referral
We could think on adding those domains to the ignored referrals within our view configuration, but this will and hidding the real referal traffic from those networks.
The screenshot above is an example for the referral paths for the domain facebook.com. We only want to avoid the ones that comes from certain paths and not the whole domain.
Simo posted above How to implement the referral exlusiong using GTM some days ago, and it’s kinda similar to what I did some time ago in one implementation to get ride of fake referrals traffic from Facebook Login.
For doing this we’ll only need to take a look to the referrals paths for the domain note the ones we want to ignore, and then use create a new variable on Google Tag Manager.
Note that we’ll need to enable the built-in Variable in Google Tag Manager, configure the fixFBarr array with our paths. This variable will return “null” as the referrer when the paths match the ones we want to ignore, and will continue returning the original referrer is there is not match.
CODE
function(){
var fixFBarr = ['/dialog/oauth',
'/v2.1/dialog/oauth',
'/login.php',
'/v2.1/dialog/oauth/read'
];
for (var i = 0; i < fixFBarr.length; i++) {
if (document.referrer.indexOf(fixFBarr[i]) > -1)
return null;
}
return {{Referrer}};
}
It will be a good idea instead of checking the path to check a combination of domain + paths array. If someone if interested on it, drop a message in the post and I’ll publish a full script covering this option.
Now, we just need to set the referrer value for our pageview tag as follows:
Ok, we’re ready right after publishing all the traffic from Facebook/Twitter/Github or any other oAuth provider will start to dissapear slowly but relentlessly.
With the new Universal Analytics cookies and everything being calculated server-side, it’s more difficult to detect some attribution problems or verifying if they were already fixed.
For example after fixing a self-referrals problem we can continue getting more of them in our reports if some users were previusly tagged in Google Analytics.
One little trick we could use is to grab the cookie creation date from the “_ga” cookie, convert it to an understandable format like YYYYMMDD, and then use it a custom dimension in order to see if those self-referrals where created before fixing our site implementation.
Ok, I know we could directly segment those sessions by the “User Type” dimension but this way we could run some cool cohort analysis based on that data, for example days since an user landed on our site for first time to when he registered or performed any other action like buying something, signing up in our newsletter or whatever.
We’re going to use a single Variable in Google Tag Manager to get this value, and then we could use it whenever we want, to directly send that date into a custom dimension or calculate any other dimension/metric
CODE
function(){
var regex = new RegExp("_ga=([^;]+)");
var value = regex.exec(document.cookie);
var cookieCreationDate = (value != null) ? new Date(value[1].split('.')[3]*1000) : undefined;
if(typeof(cookieCreationDate)!=="undefined")
{
var year = cookieCreationDate.getFullYear().toString();
var month = (cookieCreationDate.getMonth()+1).toString();
var day = cookieCreationDate.getDate().toString();
cookieCreationDate = year + (month[1]?month:"0"+month[0]) + (day[1]?day:"0"+day[0]);
}
return cookieCreationDate;
}