All posts by Zorin Radovančević

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

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.