Better Internal Campaign Tracking

Often times, more typically at transactional websites, the use of internal campaign tracking is required. By 'internal,' I mean inside the same website/domain or links between sites of a network we own or manage regardless cross-domain tracking is enabled or not for this last scenario.

Below is a classic example of hero banner at home page to drive visitors to a particular internal 'Laptops & Ultrabooks' page where we are having a promotion using the parameter 'icmp'.

Google Analytics Internal Campaign Tracking

OK, you have been using internal campaigns for years. Am I going to reinvent the wheel now? Not exactly. But there are two problems typically associated to internal campaign tracking that we want to avoid.

Duplicate content

This is an SEO issue (thanks Aaron Bradley for pointing that out) caused by analytics folks not having in mind that an incorrect implementation could have ugly consequences outside their realm. Not nice, my measurement amigos!

Google using 'inurl:' operator with some common internal campaign parameter name and you will see what I mean. Examples I've collected right away from search results:

Implementing Canonical URL Tags all over the site could be a solution. Instead of needing a Band Aid, I'm in favour of not creating a problem in the first place.

Ungrouping URLs in GA reports

If the parameter we use to tag internal campaigns makes its way to the reports we have a problem. Instead a single count for the page landing page, '' in this case, all page level level metrics are distributed along the different values of the parameter as seen in the next image.

Google Analytics Internal Campaign Tracking

Is this the easiest way we have to evaluate what every campaign yield? Definitely no. There are better ones than that I'll explain later. We're going to get to the meat of the matter in a sec but let's get the basics straight first.

What parameters should we use?

This is not another article explaining why it is not recommended to use the typical Google Analytics campaign tagging parameters (utm_campaign, utm_source, utm_medium, utm_content) for internal campaigns. Instead, suffice it to say that using these utm parameters represents high chance to mess badly your collected data, and can be even worse when the URL including those params spreads across social networks causing source and medium wrongly attributed.

So, it is advised to use a parameter such as 'intcmp', 'icmp' or the name you prefer. Parameter's name itself is not important as long as it is used consistently (pick one and use it for all your internal campaign) and it's easy to recognize later when you or your workmates are navigating GA reports.

Google Analytics campaign tagging requires at least 3 parameters but for internal purposes just one parameter is more than enough as concatenating pieces of text will do the trick to identify campaign name, area of the page where the link is located, date, version of the banner, copy of the text link, or any other information you want to include in the value of that parameter.

'SEO issue-free' Internal Campaign tagging

The idea is simple, we don't add the internal campaign parameter hardcoded to the URL of the link (that's exactly what causes the SEO problem). We add an attribute to the link handling the parameter value and a bit of JavaScript will do the rest.

What we need

jQuery is such a popular framework that it would be strange if is not already present across your site. I could not survive complex analytics technical implementations without jQuery! In any case make sure it has been added.

<script src="//"></script>

CMSs give content managers the ability to manage the html code in the page. Add an attribute 'intcmp' with the string that will become the value of the parameter, example:

<a href="" data-intcmp="spring-sale-10off">Spring...

That will become

JS code
This function does the following when you click in a link:

  • Looks for 'intcmp' attribute
  • If there is an intcmp attribute and it has a value, grabs that value
  • Grabs whatever is in the href of the link
  • Concatenates all conveniently using '?' or '&' if there are already some other parameters
  • Replaces the original href value with the new one including the internal campaign tag

Place the code inside the <head> section of the page and you are done here.

<script type="text/javascript">
$(document).ready(function() {
var $target = $(this);
var Url = $target.attr('href');
var sign = (Url.indexOf('?') > -1) ? '&' : '?';
var campaign = $target.attr('data-intcmp');
$target.attr('href', Url + sign + 'intcmp=' + campaign);

Workmate Heather Anderson (Front End Developer & Software Engineer) pointed that HTML5 has the ability to embed custom data attributes on all HTML elements and there is a naming convention for them so instead intcmp="spring-sale-10off" we should use data-intcmp="spring-sale-10off". I've updated the code to be compliant. Who can't love workmates as her? 

If you don't like 'intcmp' to name the campaign parameter feel free to use the one you want, just carefully replace it in the JS code and in attributes' name.

Getting ready for the landing

Using the properly tagged link, the visitor will reach the landing page. Problem solved? Not quite yet. We need to be able to differentiate between the different parameters while still having a way to roll up the information about the content. This is where we have to solve the second problem described before, Ungrouping URLs in GA reports, those are the two steps to take.

Exclude URL Query Parameter

Go to the view settings in Google Analytics and add intcmp in the box for that purpose

Google Analytics Internal Campaign Tracking

Capture the internal campaign parameter in a Custom Variable or Dimension

Because we are filtering out the parameter and it is not going to appear at any URL in the content reports, we have to get it somewhere else.

I've seen posts recommending to configure GA's Site Search to handle that, and other posts prescribing events. None of them convinced me enough, still nothing better than Custom Variables (if still using old GA) or Custom Dimensions (if the new Universal Analytics is used), scoped to session for better analysis.

Two ways to achieve that.

Using a Tag Management System like Google GTM, Tealium, or such. They offer the option to detect when a particular parameter is present in the query string and map the value to a Custom Dimension without having to write a single line of JavaScript. That's the beauty of a TMS.

No TMS. If you are a real macho analytics implementer I have another piece of JS (jQuery required) for you.

(function($) {
  $.qsp = (function(a) {
    if (a == "") return {};
    var b = {};
    for (var i = 0; i < a.length; ++i){
      var p=a[i].split('=');
      if (p.length != 2) continue;
      b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
    return b;

if($.qsp["intcmp"] != undefined){
  // Setting Custom Dimension in new Universal Analytics
ga('set', 'dimension5', $.qsp["intcmp"]);

// Setting Custom Variable with old Google Analytics
_gaq.push(['_setCustomVar', 1, 'intcmp', $.qsp["intcmp"], 2]);

Tweak the code to use one or the other way to set the custom Variable / Dimension and configure it properly. This change must be set before the pageview is fired but you probably already know that.

This is a snapshot of how Google Analytics reports can look like once everything is up and running.

Google Analytics Internal Campaign Tracking

Measuring Promotions in the new Enhanced Ecommerce

True that GA came recently with a way to measure Internal Promotions as part of the new Enhanced Ecommerce. That offers impressions and click tracking for promotions as they call internal campaings.

To be honest I haven't had the chance yet to test that and see how the data becomes available via the regular GA interface, the Core Reporting API or how the rest of the data can be segmented using those new options available.

Although it seems a powerful option it requires more coding to be implemented correctly. Even in the case your CMS is easily 'tweakable', it represents for sure more work than the option proposed here, a solution that for most cases is perfectly valid to cover the necessities of a non intrusive internal campaign tracking besides that fact that it does not work when 'internal' means a network of sites you own or manage. 

With a little help of a super-mom in training

This article is brought to you also by Rachael Gerson, brilliant analyst who kindly offered her scarce time (she had a baby princess recently!) to review my broken English, restructure sections to make the whole thing more comprehensive, and ensure there is value on the proposal from an analyst standpoint. Make sure you follow her on Twitter.

Your constructive criticism is always welcome.

Aug 13, 2014
Written by:
Filed under: Technical Analytics

Aug 13, 2014
Posted by:
Yehoshua Coren #1

Very nice article re: internal campaign tracking.

Question > is their a particular reason why you prefer appending parameters to instead of just advising folks to move their internal campaign tracking to location.hash?

When dealing with the URL fragment, there is no need to update GA's backend, it is SEO friendly, and non tech savvy folks can implement tracking with out needing to get IT involved in adding additional attributes to to hrefs.

The Best Buy example ends up changing the URL to a hashbang, but still easy enough to read the parameters for custom dimensions purposes.

While people need to test this, of course, as some servers puke when a url fragment is present, it seems to be a safer SEO move than allowing javascript to modify the of an href onclick.

Aug 14, 2014
Posted by:
Jason Packer #2

Weird, first comment cut off after I used an ampersand..
Trying again:

Thanks, great article and a smart method I think!

I agree with Yehoshua though that using a hash instead of another query parameter is a much safer bet. Even though putting the query parameters into an onclick event makes it cleaner for SEO for sure, Googlebot could still fire that event and end up crawling and indexing the version with the extra query strings.

Hashbang would be bad as it could be indexed since it'd look like AJAX, but just hash should work well and also cut out the step of adding the GA exclude parameter.

Aug 14, 2014
Posted by:
Ani Lopez #3

Thanks both, (sorry Jason for the issue while commenting, I'm taking a look at that)

It could work either way using fragments instead the typical parameters but the reasons why I don't like it are:

1) I like to stick to the basics, it usually makes things simpler in the long run. Fragments were not created with that use in mind but parameters did so when in doubt I lean towards how things were meant to be.

2) Either way you don't need to get IT involved in adding additional attributes to hrefs. Content managers or campaign managers can do it directly using their text/html editor in their CMS. Specially in large companies everything tends to get messy and it would take me less time to write an addon for a CMS listing all internal campaign parameters in attributes in a page for fast cleaning than if they were hard-coded in hrefs.

3) JS application frameworks like AngularJS are becoming more popular to create websites (complete different discussion that will be commented in a next post by the way) thus fragments in URLs what adds an extra layer of unnecessary complexity to the campaign tracking issue.

4) The tests I've done asking Google to index pages where params were added onclick were satisfactory and URLs were kept clean. Who knows if they will change that behavior but in the meantime it looks good.

Yes of course, everything has to be tested. What works for me could not be so fine for you.

Interesting that when I go to BestBuy and click on the hero banner it does not change to hash for me. Does it still do it for you?

Aug 14, 2014
Posted by:
Jason Packer #4

Hi Ani,
I definitely agree with keeping it simple and agree with your point that query string parameters are closer to your intent here than fragments.

For me the question hinges on #4, I agree in general I haven't seen Google get an URL indexed directly from an onclick like that (yet), but since that query parameter is what the end-user gets in their URL bar it could get used it in an external link or it could get reported as a new URL to be discovered via some other way (like if you use adsense). Which in that case it could still end up getting indexed. The distinction between #! and # where we'd be relying on Google's interpretation of # is admittedly problematic.

So I guess I could see myself doing it either way depending on the site and of course as you say subject to testing. Anyway, thanks for the method and discussion!

Aug 14, 2014
Posted by:
Ani Lopez #5

Total valid point, Jason, regarding the chances of Google ending up getting into their index the version including parameters but it also applies to URLs including fragments.

Although no method is going to reduce the SEO problem to zero my point is a decent balance between low risk, make it easy for campaign managers and lay the ground to keep the house clean in the long run and that's where attributes come to play better than hard-coded URLs.

Last one. Tag Management systems make quite simple, for non-programmers, to grab parameters from query string with two clicks. Fragments are always more complicated.

Aug 14, 2014
Posted by:
Yehoshua Coren #6

I disagree. Google treats query parameters and hashes differently. That's why they have a whole section of their WT help section to assist webmasters with AJAX. I think that it is better SEO practice to stick to hashes, instead of propagating a bunch of query parameters.

There has been much written about this. Here's something from Jim in 2009:

Aug 14, 2014
Posted by:
Ani Lopez #7

I've tested that in small sites so I'll get that implemented at some large ones and we'll see how this goes to put minds at ease.

Nov 17, 2016

bagus sekali penjelasanya pak

Nov 17, 2016

bagus sekali penjelasanya pak

Have your say
twitter @anilopez

Articles I write for other sites

Analytics Tribulations Of An SEO

The art of measure is never easy but when it comes to SEO it's even worst

Challenges of Spanish Language on Search Marketing @ Multilingual Search

'Standard Spanish' is something that I don’t buy into when it comes to international scenarios. I'll explain to you why and some tips to start facing correctly your Spanish strategy.

Handling Multilingual Sites for Humans & Search Engines @ Bruce Clay Blog

The logic behind the scenes to show all content to bots and the right language to users

Mobile detection issues & Google Instant Previews @ Cardinal Path blog

Mobile web represents the bigger headache ever for those wanting to target the small but growing audience they represent nowadays. check your Instant Previews for possible indexation issues.