Easy fix for wrong Google Adwords attribution in Google Analytics (Rogue referral problem)
So, your development team just rolled out a shiny new webpage built as a Single Page App (SPA), promising quick loading times, no reloads and improved user experience. Everything looked like a fairy tale until your marketing manager came up and spoils the fun:
I don’t see Google AdWords acquisitions in Google Analytics anymore! Suddenly everything gets attributed to google/organic.
The problem
This problem has been widely identified back in 2016 and named as a “Rogue referral problem”. There’s a great blog post by Simo Ahava about it.
The most commonly known fix for this problem is saving the campaign data in the cookie and dragging it along throughout the whole session, which does solve the problem. However, it is cumbersome to setup, prone to errors and adds even more clutter to the Google Tag Manager (GTM) container.
I’d like to share an alternative solution to the problem which goes in the opposite direction than the current proposition, but to better understand the solution, let’s take a step back and start with the root cause and understand why it’s happening in the first place.
Let’s start with how Single Page Apps work
Unlike regular web pages which reload at every new page, Single Page Apps (also called Single Page Websites) load only a single time and then change its state to dynamically display different pages/content for the user to see, which provides a better and faster user experience (when done properly). All popular SPA frameworks work the same way (React, Angular, Vue JS)
To track user interactions in SPAs, Google Analytics (GA) use so called “virtual page views” triggered by state changes (usually by using History Change Trigger in GTM), as oppose to regular page views which happen every time a new page is loaded and triggered by the page view itself.
And this is where the problem is happening — since Single Page Apps do not reload, they’re keeping the same referrer for all page views within session until a page is fully reloaded once again.
Let’s look at this scheme to better understand what’s happening:
- Let’s say a user was looking for your page on google.com and decided to click on your Ad.
- After landing on your page, Google tracked a Page view with Adwords parameters (GCLID and other UTMs) and a referrer google.com.
- But when a user goes to the second page, the page is not reloaded, so the referrer is still google.com, but the AdWords parameters are empty because the URL changed. Since this is a typical parameter of a user clicking an organic link on google.com, Google Analytics attributes this traffic to google/organic.
Why does this not happen with regular web pages? Because the second page is reloaded, both referrer and UTM parameters are cleared, making this traffic unattributed, which then follows the GA’s logic to attribute the acquisition to the last known non-direct source (which in our case is AdWords, a.k.a google/cpc).
The Fix
Since the root cause of the problem is clear and the existing solution of saving data in cookies seemed cumbersome, I thought of a more simple and elegant solution which is the opposite of the existing one:
Instead of dragging the attribution data all over the place, we can remove the part which is causing the problem — the referrer.
There is a simple JavaScript command which can clear the referrer, making the next pageview referrer empty… which is basically what happens in non-SPA pages. Since there’s no referrer and no UTM parameters, based on GA’s logic, such page view is attributed to the last non-direct source, which in our case is Adwords, thus solving the problem. Here’s how it looks in GTM:
To create it, create a new Custom HTML Tag and copy this code:
<script>
function removeReferrer() {
console.log(‘Before removing referrer was:’, document.referrer);
Object.defineProperty(document, ‘referrer’, {
value: null,
});
console.log(‘After removing referrer:’, document.referrer);
}
setTimeout(removeReferrer, 300);
</script>
This code clears the referrer after a specified delay of 300 milliseconds, which was added as an additional safeguard (more on that later). Additionally, it also shows an end result in a Console log, making it easier to debug (you can remove console logging after you’re done).
The catch
There’s always one. The main battleground of this fix is choosing the correct trigger — when to execute this Tag to avoid race conditions, resulting in lost referrer parameter before the initial page view was sent to GA (not completely sure how GA would react to AdWords parameters present in URL but missing the referrer).
Setting the right trigger depends on your page configuration, but you can observe via GTM debugger when the page view is sent to GA and trigger this script after that.
My trigger of choice is DOM Ready and just to be sure I added a slight delay in the script execution to avoid some slow-connectivity users to be cleared too early (it’s included in the example script). Having in mind overall initial page load time, it’s unlikely that the user will navigate further into the page before the script could do its job.
But I’m sure the trigger part has some room for improvement in terms of reliability, but we’ve been running this approach in a production environment for over a month now and have been happy with it so far.
Let me know in the comments if you have any questions or suggestions for improvements and I hope I managed to save at least some time for you solving this problem!