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 Knewledge.com – http://goo.gl/r8qJED – 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 – http://goo.gl/fRV4nB

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 domainA.com (parent domain) and domainB.com (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 http://goo.gl/HA9O9o.

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

Triggers

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

1. all pages parent domainA.com (parent domain)
A tag using this trigger will activate only on pages with hostname domainA.com (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) > domainA.com

all pages parent trigger

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

all pages child trigger

3. event on child domainB.com 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 domainB.com (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) > domainB.com (optional)

event child domain trigger

Variables

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: http://www.domainB.com,https://www.domainB.com (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: http://www.domainA.com (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)

Tags

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 http://example.com
var topOrigin = {{gtm topOrigin}}; 
function xDomainHandler(event) {
  event = event || window.event;
  var origin = event.origin;
  if (topOrigin != '*' && topOrigin != event.origin) {
    return;
  }
  try {
    var data = JSON.parse(event.data);
  } catch (e) {
    // SyntaxError or JSON is undefined.
    return;
  }
  if (data.cid) {
    sendHit(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.
  sendHit();
} 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;
      break;
    }
  }
  if (!found) return;
  if (event.data != 'send_client_id') return;

// Get the clientId and send the message.
  var tracker = ga.getAll()[0];
    tracker.get('clientId');
    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!

Author bio

Zorin Radovančević

July 2, 2015 Google Analytics, Google Tag Manager

Senior Web Analytics implementation and planning specialist - all things related to Google Analytics, Google Tag Manager and Yandex Metrica.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *