Category Archives: Google Analytics

Reporting on AdBlock usage with Google Analytics

Ad blocking is a really hot topic these days. Arguably there are two completely opposite stories to follow up on yet we are not dealing with that this time. This post explains how to report on ad blocking occurrence on the site and how it affects your ‘potential’ earnings as a publisher.

There are 3 main steps to this process:

  1. Detect ad blockers and send an event to Google Analytics (we will use it later on in a segment)
  2. Make the number of page ad slots available – ideally using dataLayer (if using GTM)
  3. Create the Custom metric(s) in Google Analytics interface and create the custom reports / dashboards

1. Detect AdBlockers

There are already numerous ways to detect clients / users with ad blocking apps activated so I will only list a few:

You will notice that almost all detection kits use a ‘dummy’ / ‘fake’ ad related file which will hopefully trigger an ad blocking app and this should fire a GA event. You can of course adapt it to detect your real ads being blocked without the need to add the fake script.

The logic

Using any of the for mentioned scripts fire a Google Analytics event e.g. in case you are using GTM push the info via dataLayer:

window.dataLayer = window.dataLayer || [];
'event' : 'trackEvent',
'eventCategory': 'Adblock',
'eventAction': 'Active'

Create a Google Analytics Event template tag using these values which is triggered on the custom event trackEvent and you’re almost done (variables and triggers should be created as well):


2. Make the number of page ad slots available

Again if using GTM just add the information to dataLayer which will represent the number of ad slots available on a single page. The idea is to simply use getElementsByClassName() which will return an object which has a property length – use this logic to obtain the number  of ad slots available on a specific page (the value which we are looking for is length +1 as the indexing starts at 0).

Easy as:

var adSlotIndex = document.getElementsByClassName('elementClassWhichContainsAnAd').length;

One thing worth noting is that you will probably want to send this info after DOM is ready so choose how to send this custom metric carefully – options are to send it with a pageview (so PV tracking should be DOM ready) or use an event for more flexibility just make sure non interaction is set to true.

In addition you can send another custom metric which will be currency type which will be calculated as total Ad Slots On Page * Average Revenue Per Impression – reporting with currency gives more weight to the whole concept.


3. GA prerequisites and building the dashboard

First take care of the segment – Session level segment which will be Event Category == AdBlock and Event Action == Active. This will allow reporting on sessions where AdBlock was active – in specific number of ad impressions or better say ads that were supposed to be delivered you could not be as they were … blocked. This segment can be applied to standard / custom reports, dashboards and used in API exports.

Secondly create the custom metric(s) on GA property level.

And now it is all up to you to show the data best way you can – the way it will make you do something to battle this revenue consuming trend.


Some reports details to consider: browser, browser version, geography based dimensions, content grouping (LP or page – to determine where this revenue source is most sensitive) – you will probably find more useful dimensions.

Hope this helps in determining how much money you loose from ad blockers:)

Happy tracking!

Time to complete a goal or transaction using GTM and Google Analytics

Here is a quick overview of how to track the time needed for a user to finalize a desired activity inside a session using Google Tag Manager and Google Analytics. The example in this article is a simplified overview of various hits and methods on how we can achieve process tracking inside Google Analytics. By default Analytics measures Session length / duration and time on page which is quite challenging in this cases and rarely applicable thus one may be forced to use features like custom metrics and / or user timing hits.

Case – time from session start to lead generation form submit

A user starts a session and is expected to fill and submit a lead generation form. We would really like to know how long this process usually takes (not the entire multichannel / multi device experience in this case but just the in session experience).  The experience will be highly affected by previous experience with the site – so using some segments while analysing would come in quite handy.

The idea on how to fetch these values is quite simple. Drop a cookie once a session starts, or in some specific cases when an on site process starts (e.g. checkout) – where the cookie value will be the session / process start time. After the user has completed the process – successfully completed the desired action (we basically mimic Analytics goal behaviour – so it is either a destination or an event based trigger in GTM) we send a User timing hit or an event hit with a time type custom metric.


The procedure

What is needed:

1. Cookie tag – Custom HTML
On session start we set a session level cookie.

var d = new Date().getTime();
document.cookie = "sessionStart=" + d + "; path=/;";

Trigger – Pageview using a 1st party cookie variable sessionStart (so fire only if sessionStart is undefined).
Variable – 1st party cookie – sessionsStart ({{gtm sessionStart}}).

trigger first page in a session

 2. Google Analytics pageview tag – Template tag – Universal Analytics

This is a basic GA universal pageview tag yet I added a hitCallback inside ‘Fields to set’ to safely set a clientId as a custom dimension (user level – do not forget to dreate the custom dimension inside GA admin) in an additional event tag (ty Simo!) – this will fire a Google Analytics event tag only when the Pageview tag has fired successfully. so the setup looks like this:

universal analytics main pageview tag

Trigger – All pages (default trigger).
Variable – custom js variable which send a custom event via dataLayer push – this event is used for the Utility Event responsible for adding a custom dimension with clientId value.

check if ua pageview fired

function() {
return function(){dataLayer.push({'event': 'pageViewFired'});}

3. Google Analytics Event tag – Template tag – Universal Analytics

A simple event tag which only purpose is to set the Custom Dimension value of the users clientId (this is used to further analyse time for each process based on the client Id – some randomization could be utilized if a user is expected to have multiple conversions or even add a process end time as a custom dimension or use time dimensions in GA).

event tag set cid

Trigger – event equals pageViewFired.
Variable – use a custom JS variable which will fetch the clientId value.

function() {
return ga.getAll()[0].get('clientId');

4. Google Analytics User timing tag – Template tag – Universal Analytics

This is where we send info to GA that the process has successfully ended and pass the time value. So the setup looks like this:

user timing hit

Trigger – any which identifies the session has resulted in a goal completion. For this case I used a simple custom event – trackConversion – dataLayer.push({‘event’:’trackConversion’});

Calculation and variables – as you noticed a different variable is used for the custom metric and user timing value. The reason for this is that user timing hit requires a value in milliseconds and custom metrics in seconds. The calculation is pretty simple.  You need 2 variables:

User timing value

function (){
var endTime = new Date().getTime(); // this could easily be a separate variable
return endTime - {{gtm sessionStart}};

and Custom metric value

function (){
var endTime = new Date().getTime(); // this could easily be a separate variable
return (endTime - {{gtm sessionStart}})/1000;

And that’s basically it – one word of caution though user timing hits are prone to sampling so consider sending the timing info through events with CD and CM defined.

When you are done setting this up the example report could be something like this:

report example


Hope the article was useful and of course happy tracking!


iFrame Google Tag Manager Cross domain tracking alternative

Hi to all who have dealt with the cross domain issue when working with iFrames – it can be a tedious endeavour yet using Google Tag Manager and Universal Analytics the process is somewhat simplified. This is also an updated version of a similar method yet this one uses the Google Analytics Template tag inside GTM.

There already are some great articles which offer a complete set up workflow such as a great Article by Claudia Kosny found on – – yet we found it to be a bit too complex when working without a decent developer support and the main issues were:

  • iFrame will not show if Google servers do not respond and
  • iFrame will not show if the GTM setup was misconfigured

If the iFrame was on the site to render some critical information such as Booking engine or any kind of Payment service it was just too big of a risk.
Fortunately Google updated the iFrame section of cross domain tracking with a new method which does not have this kind of problem – Tracking Cross Domain iFrames using postMessage –

Downside to this method is:

  • users with IE7 and earlier will be tracked as different clientIDs (cross domain tracking will not be in effect yet tracking will still occur)

To be clear the end goal of this implementation is to preserve the session and have accurate attribution reporting inside Google Analytics – this of course includes the ability to set up funnels and any additional hits within the existing session (without messing up traffic sources and session inflation when using Universal Analytics).

How to set up iFrame cross domain tracking for Universal Analytics via GTM

1. Referral exclusion

The first step is to always prepare the referral exclusion list. Our example will use the domains (parent domain) and (child domain – page on domain inside iFrame).

2. GTM container

Place the GTM container snippet on both domains! More info can be found in Google Help center

3. GTM settings (GTM Tags, triggers, variables and more)


Triggers help you define when a tag should be activated using various conditions.

1. all pages parent (parent domain)
A tag using this trigger will activate only on pages with hostname (our parent page). You can opt to change the trigger type to either DOM or Page View just make sure you test the setup.
{{Page Hostname}} > match case (can be any which defines the situation) >

all pages parent trigger

2. all pages child (child domain – inside iFrame)
A tag using this trigger will activate only on pages with hostname (our iFrame page).
{{Page Hostname}} > match case (can be any which defines the situation) >

all pages child trigger

3. event on child trackPage (fires the page on child domain after it has dealt with the cid retrieval)
A tag using this trigger will activate only on pages with hostname (optional) and only when the custom event trackPage has been pushed to dataLayer.
Event name: trackPage
{{Page Hostname}} > match case (can be any which defines the situation) > (optional)

event child domain trigger


The following examples are basically utility Variables with which you can easily reuse the entire setup in just a few edits – in short you do not need to mess with the code just edit everything with variables.

1. dl cid (Data Layer)
A Data Layer type variable which returns value of cid once it is pushed to dataLayer.

2. dl virtualPagePath and dl virtualPageTitle (Data Layer)
Just an example of what you can additionally define for tags e.g. booking steps or similar.

3. gtm allowedOrigins (Constant)
Used to set the whitelisted sites (i.e. your booking engine, payment system, CRM) which can communicate to our parent Domain.
Value:, (a list of comma separated domains where our page inside iFrame is placed)

4. gtm topOrigin (Constant)
Used to define the domain which holds our parent Page – parent domain.
Value: (our main domain)

5. gtm uaTrackingId (Constant)
We will store the UA tracking ID (property ID) in a Macro so we can reuse it all of our GA tags with less chance of human error:) (you can of course change it to lookup, dl or custom JS)


We will need 3 separate tags – 2 Custom HTML and one plain Universal Pageview tag for the complete setup to work. Custom HTML Tags are used to retrieve the cid parameter (code is provided in the full container download). Do not forget to add the clientId under fields to set!

Custom HTML #1 (on child domain only (inside iFrame)):

// Add the expected origin domain inside gtm topOrigin variable
// Must use the following format
var topOrigin = {{gtm topOrigin}}; 
function xDomainHandler(event) {
  event = event || window.event;
  var origin = event.origin;
  if (topOrigin != '*' && topOrigin != event.origin) {
  try {
    var data = JSON.parse(;
  } catch (e) {
    // SyntaxError or JSON is undefined.
  if (data.cid) {

if (window.addEventListener) {
  window.addEventListener('message', xDomainHandler, false);
} else if (window.attachEvent) {
  window.attachEvent('onmessage', xDomainHandler);

var alreadySent = false;
function sendHit(cid) {
  if (alreadySent) return;
  alreadySent = true;
  // If cid exists, it will overwrite any existing values
  var params = {};
  if (cid) params['clientId'] = cid;
  dataLayer.push({'event':'trackPage','cid': cid});
if (!window.postMessage) {
  // If no postMessage Support.
} else {
  // Tell top that we are ready.
  top.postMessage('send_client_id', topOrigin);
  // Set a timeout in case top doesn't respond.
  setTimeout(sendHit, 100);


Custom HTML #2 (on parent domain only ):

// Edit the gtm allowedOrigins variable and add your domains to the whitelist
var allowedOrigins = {{gtm allowedOrigins}}.split(',');
function xDomainHandler(event) {
  event = event || window.event;
  var origin = event.origin;
// Check for the whitelist.
  var found = false;
  for (var i = 0; i < allowedOrigins.length; i++) {
    if (allowedOrigins[i] == origin) {

      found = true;
  if (!found) return;
  if ( != 'send_client_id') return;

// Get the clientId and send the message.
  var tracker = ga.getAll()[0];
    var data = {cid: tracker.get('clientId')};
    event.source.postMessage(JSON.stringify(data), origin);
if (window.addEventListener) {
  window.addEventListener('message', xDomainHandler, false);
} else if (window.attachEvent) {
  window.attachEvent('onmessage', xDomainHandler);


The final tag setup will look like this:

cross domain tags




ua pv main tag



You can download the full container version here – please be careful when you import the  container you do not: overwrite your existing container or even import into a production container rather test it first in a new account / container and migrate settings after a successful testing process.

4. Publish

After you finish all of the setup please do not forget to debug, preview and create a version and publish in the end.
Happy (cross domain) tracking!

Travel sites and Google Analytics Site search – essentials

Travel industry is extremely rich in terms of data collection opportunities. Using Universal Analytics great new features online travel agencies and tour operators can easily implement and use this data for numerous tasks – mainly to gain insight on on site behavior and plan ahead (using data).

This, first in a series, article will deal with one of the main travel site tools – Search, Site search.

Why is Travel industry so specific when it comes to internal search?

Travel search usually does not use only one parameter in search but instead a series of parameters which best describe the end user intent – need.

The basic query usually consists of:

  1. Arrival date
  2. Check out date
  3. Destination and / or Location and / or Product (Hotel, Resort, Brand, Rental)
  4. Number of adults
  5. Number of children

If we were to translate this query in simple terms we would end up with a simple question:

What is the best offer for me and my better half in May 2015? We’d like to see Spain for 14 days and we believe Barcelona would be a great fit …

Now the search engine as the online salesperson – yes it is a 24/7 sales tool, needs to render best possible offers. If applicable it can/should ask additional questions to filter out offers not suited for the for mentioned couple.

These questions could be:

  1. Hotel category
  2. Price range
  3. Additional services (wifi, pool …)
  4. Activities (hiking, dancing, sleeping …)

The ideal follow up action set would include (a basic funnel):

  1. Looking at the product page for more details
  2. Booking process
  3. A long overdue vacation
  4. Repeat purchase:)

Looking back at the entire process we can determine the main points of interest where we can collect data and gain valuable insight.

  1. Initial search
    What was the users initial query – ideally we would need to track:

    1. Arrival – YYYYMM
    2. Destination or product
    3. Number of adults (good to have since we can easily use segments and push remarketing campaigns accordingly)
  2. Search refinements
    Each subsequent search performed during the session

    1. Add additional parameters to the search
    2. Completely new parameters
  3. Site Search monetization
    Did the search process end up with:

    1. Site exit
    2. Booking entrance
    3. Booking success

All main activities usually occur directly on search result pages. Depending on how the site was built we have many options on how to retrieve these desired values and send them to Google Analytics.

Before we get all technical lets look at what we can do with the data collected and hopefully answer why is it worthwhile to invest in tracking site search.


Why do it?


Aside from the default segments (built in) sessions with or without search you can explore user behavior based on their queries – destination, hotel category, arrival date. This will help assign value to segments – revenue based on desired destination, hotel, activity ….


So many options here – basically each query is a remarketing opportunity where you can choose to be more or less specific. Just think of a display ad containing Spain / Majorca, desired date of arrival, total price for 2 persons, image includes spa (which was additionally selected) and if you can afford give 2 tickets to a party (if the user selected dancing as a favorite activity) – the possibilities are endless.

Search behavior

Evaluate the efficiency of your search engine. There are some decent metrics available in the reports such as:

  1. Total Unique searches – evaluate between search terms and total demand
  2. % Search Exits – % of searches resulted in the user leaving the site
  3. % Search Refinement – % of searches resulted in a new search

The standard Behavior > Site Search > Usage report can help determine how sales friendly is your search engine in terms of purchase behavior of those who searched and those who did not.

Research tool

After collecting the data for a significant period you will have massive insight into some specific cases for example:

  1. When do people start searching for a specific query? (and when they actually buy it)
  2. When do people from Germany start searching for a vacation in Spain with children
  3. Which of the additional services are important to visitors from Italy and which selection did lead to a purchase?
  4. And much more …


Technical setup and options

Step 1.
Which parameters to track

Which values will you actually use in reporting, remarketing or segmentation tools and decision making.

Step 2.
Retrieve the values

This is the part where you may ask for some help from your developers. I said may as there are situation where you can do it without the help.

It is also important to know are you using a tag management system like Google Tag Manager or are all of your tracking codes implemented directly into site template structure.

Values in URL
If the values are exposed in the URL as query parameters (/?arrivalDate=20150522&…) or as anchor (/#arrivalDate=20150522&…) you can and should use Google Tag Manager where Macros / Variables are your best friend.

Values via a dataLayer.push (for Google Tag Manager)
But if the situation is not as simple a good way would be to ask your developers to render all required information inside a dataLayer on all pages related to search – just a simple piece of code inserted on your page which can look like this:

// Insert before GTM snippet or add a custom event if this is not possible
window.dataLayer = window.dataLayer || [];
‘searchArrival’ : ‘20150522’,
‘searchDestination’ : ‘Majorca’,
‘searchAdults’ : ‘2’

Step 3.
Format data and send

After we retrieve the raw value we may sometimes need to reformat data to conform it to reporting needs. In this simple example we would like to send this data in two basic ways.

Site search term
The values become available inside Behavior > Site Search reporting in Google Analytics – but as the query is complex we would need to combine these 3 values into one single entry where the end result would be ‘20150522,Majorca,2’

Technical needs
Option 1. Use a virtual page view method and override the default URL so that the URI reported in Google Analytics looks like this – ‘/searchresultpage/?mySearchTerm=20150522,Majorca,2

Option 2. Use view filters – Custom advanced filter where you would extract Custom Dimensions values and combine these into Search term.

Custom dimension
It would be wise to track all three of the values as separate dimensions as you could more easily report on trending and correlation of these dimensions – so CD1 would be searchArrivalMonth where we would put only the month part of the string, CD2 would be searchArrivalYear only the year part of the string …

Technical needs
Define the custom dimensions inside Google Analytics admin (property) as hit level dimensions. Use the indexes either in GA universal tracking code or via Google Tag Manager (preferred implementation) and assign the values to each custom dimension on each pageview hit (related to search of course).

Added bonus – read this fine article by Simo Ahava which explains the site search technical stuff – highly recommended –

Step 4.
Additional info to acquire (Opportunities)

Consider setting up additional tracking features:

  • Content grouping value as search result page entry.
  • Enhanced e commerce to see product performance based on search result lists.
  • Custom metric which will report on the number of offers found for a specific query where you will definitely keep your eye open for the dreaded ZERO search result – meaning no offer could be found in the search process.