Here’s how it looks:
- Old: https://www.mywebsite.com/cool-page/?utm_source=newsletter&utm_medium=email&utm_campaign=summer-sale
- New: https://www.mywebsite.com/cool-page/#1
Instead of parameters (which are sent as part of the HTTP request), we’re using hash fragments (#). These are commonly used to jump to a particular position in a document, or – in single page apps – to dynamically manipulate the page without additional requests to the server. They’re also ignored by Google Analytics by default.
At a high-level, here’s how a hash fragment is translated to campaign data which can be understood by Google Analytics, as part of a single pageview:
- GTM picks up the value of the hash fragment in the URL
- This is referenced against one or more Lookup Tables which return human-readable strings
- Our modified pageview tag fires, using the value(s) returned by the tables as our campaignContent, campaignName, and so on.
This approach needs to be tailored to your exact setup, and if you’re already using UTM parameters, you’ll need to think carefully about how to transition. To help demonstrate the process of implementation, we’ll run through the necessary steps to get up-and-running in a typical scenario.
Step by step
As with standard UTM tracking parameters, the first step is to decide on a naming convention for your campaigns. Unless you want your Analytics reports to descend into wretched pits of mystery and confusion, pick a system and stick with it.
Heading into GTM, you’ll need to assign a number to each of your current campaigns. It doesn’t necessarily have to be a number – you can use a whole word, if you like, but given that the hash value is translated into something human-readable later, I like to shoot for brevity.
Next, we need to configure GTM to translate the hash fragment. Under Variables, hit New under User Defined Variables, and select the variable type URL. For component type, select Fragment. Give it a sensible name, and hit Save.
Create another User Defined Variable, this time a Lookup Table. For the Input Variable, select the URL Fragment variable you just created. Add a couple of rows. For the input column, enter the numbers you’ve decided to use for your campaigns, and for output, enter the campaign names, exactly as you would for
utm_campaign. We’ll call this table ‘Fragment Lookup – Campaign Name’.
Next, you need to alter your pageview triggers to detect a tracking fragment. The way I prefer to do this is to split your pageview tag into two: one triggered when the URL includes a hash fragment comprising a single number (i.e. one of our referrer fragments), and one triggered by the inverse condition (i.e. every normal pageview).
To do this, we’ll configure 2 triggers and use regex to define the firing condition. The expression
^[1-9]\d*$ corresponds to a string of numerical digits, and will return false on anything else. The first trigger we’ll call ‘Pageview – Tracking Fragment’, and configure it as follows:
The second trigger we’ll call ‘Pageview – No Tracking Fragment’, and simply invert the condition to ‘Does not match regex’.
Next, we’ll modify our GA tags to fire this data to the appropriate campaign fields. This process will obviously vary depending on your existing GA configuration, but if we assume a basic setup, it’s a simple case of (a) modifying your existing GA pageview tag to be fired by the ‘Pageview – No Tracking Fragment’ trigger, and (b) creating a copy of this tag and switching its trigger to ‘Pageview – Tracking Fragment’.
For this new pageview tag – the one now triggered when a tracking fragment appears in the URL – we’ll also configure the following Field under More Settings:
We’re simply telling Analytics to set the campaign name by looking up the value of the hash fragment in our lookup table, and returning the human-readable string.
I suggest you run some extremely thorough checks using the Preview tool, and use the Google Tag Assistant Chrome plugin to check the actual campaign data being fired to Analytics when a tracking fragment is added to the URL.
Once this is working, the hard work is done. Assuming you wish to set other fields like
campaignContent in addition to
campaignName, you’ll need to create additional Lookup Tables. The input on these will be the same as the first – your tracking numbers – and for the output columns, simply enter the corresponding information for that campaign. Set these fields in the appropriate pageview tag, and you’re good to go:
Preview, test, publish, done.
Adding a new campaign is a simple case of adding a new row to each of your lookup tables. Enter the details of your campaign, publish, and off you go.
While I’m yet to deploy at scale, I believe that this approach eliminates some of the risk of messy unsanctioned campaigns. If no-one in your team is using UTM parameters, the only way campaigns can be tagged is with an amendment to your GTM container. If you have a process in place to approve changes to your GTM container (which you should!), poorly-tagged campaigns should be a thing of the past.
It’s also easier for non-technical people to tag URLs for sharing. They needn’t rely on Google’s URL builder or similar tools, instead they simply add the agreed-upon two digits (e.g. #4) to the normal URL.
Q: But I run lots of short-lived campaigns, won’t I end up with a ludicrously long number at the end of my URL?
A: Potentially yes, although you’d need to run tresexagintillion (1 with 63 zeros) campaigns before you got to the length of the UTM parameter string I used as an example earlier.
But more to the point, if you’re bothered by large numbers, you can reuse slots. Once you’re confident a particular campaign number is unlikely to see a resurgence, you can simply change the output variables which are tied to that number in your lookup tables. Add new campaign data to slot 4, for example, then start sharing new URLs tagged with #4, and your new campaign will appear in Analytics.
Q: Will this interfere with my existing use of hash fragments?
A: If you frequently tag URLs which contain hash fragments (i.e. anchors) already in them, then yes – this approach probably isn’t for you.
If you’re just using hash fragments to jump around within posts (i.e. not using hash URLs for your campaigns), then you’ll probably be fine. Note that the regex I provide above will ensure that your fragment-based pageview tag will only fire when the fragment contains a number, which will prevent nonsense campaign data being fired to Analytics in most other scenarios.
Q: I don’t like attaching stuff to my URLs. I think it affects UX.
A: While a hash fragment is nicer than a big ugly string of UTM parameters, it’s still suboptimal. There’s also the possibility that a URL will get re-shared with the same hash fragment somewhere else, clouding insight. If this really bothers you, you can use the HTML5 history API to rewrite the URL that appears in the address bar to remove the hash fragment after data has been sent to Analytics. This is the same principle as Wistia’s Fresh URL script for UTM parameters, but I won’t go into it here.
Q: Did you invent this technique?
A: Apparently not – a quick Google search reveals I’m not the first person to think of this idea. Back in 2014, LunaMetrics did a cool test using hash fragments to fire data to a custom dimension to track the effectiveness of individual support team members on a forum. GTM has changed considerably since that post was written (farewell macros), but it’s an excellent article and well worth reading.
Q: This is rubbish I’m sticking with UTM parameters.
A: Cool. It’s a bit of a kludge but so are UTM parameters – they’re just a very old kludge. Hopefully this technique is useful to someone, even if it’s just a neat way to track referrals from a single valuable source which is stripping out HTTP referrer data, without resorting to UTM parameters.
That’s an interesting method.
My solution was to let Analytics process the parameters, then remove them.
You can also use hash based utm parameters by default, which I prefer as it solves half the problem for you:
Thanks Tony, that’s also a cool approach. I agree that removing UTM params with a script (using the HTML5 history API) can be a great idea, especially to prevent copy-paste reshares being misattributed. You’ll still need a robust approach to dealing with Direct sessions of course – look out for my upcoming Moz post on analysing Direct traffic :-)