Single Page Applicaties (SPA’s) zoals veel React en VueJs apps kunnen voor problemen zorgen in Google Ads conversie tracking via GTM.
SPA’s zijn geweldige websites waarbij na het eenmalig laden van de website er geen pageviews meer plaatsvinden. In plaats daarvan zal javascript een deel van de pagina verwijderen en vervangen voor nieuwe content. Voor conversietracking en dan met name in Google Ads zorgt dit echter voor een uitdaging.

Google Ads geeft aan de website het GCLID mee en relateert daarmee de gebruiker aan de campagne en klik uit Google Ads. Dit gebeurd via cookies en trackers die ook voor Google Analytics worden gebruikt. Deze gegevens worden vervolgens in een hidden state bewaard als de bezoeker doorklikt naar nieuwe pagina’s via een nieuw pageview request. De gtag die GTM gebruikt voor zowel Google Analytics en Google Ads kijkt naar de Document Location en stelt de hidden state vervolgens opnieuw in. Bij Single Page Apps zoals React apps is er echter geen pageview meer na het initieel laden van de pagina en om dit meetbaar te maken sturen we in GTM een pageview request op basis van een virtuele pageview. Dit betekend effectief dat de Document Location hetzelfde blijft. Echter door de manier waarop GTM werkt wordt de Document Location bij ieder request aangepast waardoor we een lege hidden state overhouden en de link met de GCLID verloren gaat. Hierdoor verliest de Google Analytics tag die ook voor de Google Ads conversietracking zorgt uit het oog van welke bron deze gebruiker afkomt en zal de conversie in Google Ads niet worden toegewezen.

Wat je vervolgens bij SPA’s ziet is dat er geen of bijna geen conversies worden toegewezen in Google Ads terwijl als je GTM test wel de tag wordt afgevuurd dus in eerste instantie zul je wellicht verwachten dat de campagnes gewoon slecht presteren. Hier ligt echter niet het probleem.

Hoe lossen we dit op?

Voortbouwend op een artikel van Simo Ahava hierover is het de bedoeling dat we de hidden state handmatig aan de virtuele pageviews mee gaan geven.

Wat we hier doen is de GCLID meegeven aan alle virtuele pageviews. Hiervoor maken we een tag die de URL inclusief de gclid maar zonder fragment opslaat in een dataLayer variabele. (meer over wat de dataLayer is in GTM)
Hiervoor maken we een HTML tag die we afvuren op de pageview. Dit is dus het initiële request en niet de virtuele pageview.

<script>
var origLocation = 

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
origLocation:
document.location.protocol + '//' +
document.location.hostname +
document.location.pathname +
document.location.search
});
</script>

Wat we hier doen is een dataLayer variabele maken genaamd origLocation en vuren deze tag af bij ieder pageview request. Dit is dus in principe alleen bij het initiële laden van de pagina.
Om deze variabele uit te lezen maken we vervolgens een dataLayer variabele aan.

In de GA4 setup tag geven we deze waarde als een parameter mee met veldnaam location.

 

Als je nu via de debugmodus het conversieproces  doorloopt en bijvoorbeeld op een bedanktpagina komt zou er zoiets als dit in de dataLayer moeten staan.

Problemen bij o.a. iDeal betalingen

Zoals we het hiervoor hebben gedaan werkt prima tenzij de pagina herladen wordt. Op de oorspronkelijke bestemmingspagina is dit geen probleem omdat de gclid daar nog in de url staat maar zodra bezoekers doorklikken naar andere pagina’s dan het de dataLayer leeg zijn, de gclid niet in de url staan en dan wordt de HTML tag opnieuw afgevuurd om de origLocation in te stellen die dan niet meer bekend is. Dit proces gebeurd bijvoorbeeld bij een betaling met iDeal. Als er een checkout is met bijvoorbeeld een ideal betaling dan wordt je geredirect naar de website van een bank en vervolgens weer terug gelinkt naar de bedanktpagina van de website. Als gevolg de origLocation is verloren gegaan.

Als er een dergelijke stap is in de salesfunnel dan is het handig om in plaats van te werken met een dataLayer variabele, te werken met een directe cookie. Wat we hier doen is bij iedere pageview (dus echte pageviews en geen virtuele) kijken of er een cookie is met een origLocation en dan die gebruiken of deze instellen. In dit voorbeeld zal ik met een cookie werken die een geldigheid van 30 minuten heeft. Dit is gelijk aan de standaard sessieduur van de Analytics cookie maar je bent vrij om een andere liefst kortere tijd in te stellen. Het zou namelijk kunnen zijn dat bezoekers de website verlaten en binnen die 30 minuten weer terugkeren via een andere bron dan Google Ads en dan te converteren. In dat geval is de cookie nog geldig en zullen we de origLocation met de gclid toevoegen waardoor de conversie aan Google Ads wordt toegewezen.

Nu passen we de HTML tag aan. Echter omdat ik in de HTML tag verwijs naar een variabele moeten we eerst een variabele aanmaken voor een directie cookie met waarde originalLocation.

Hierna passen we de HTML tag aan:

<script>
var cookieOriginalLocation = {{cookie originalLocation}};
var origLocation = document.location.protocol + '//' +
document.location.hostname +
document.location.pathname +
document.location.search;

if(cookieOriginalLocation === undefined || origLocation.includes('gclid')) {
console.log('set cookie origal location: '+origLocation);
var date = new Date();
date.setTime(date.getTime()+(30*60*1000));
expires = "; expires=" + date.toUTCString();
document.cookie = 'originalLocation' + "=" + (origLocation || "") + expires + "; path=/";
}

</script>

In plaats van een dataLayer variabele gebruiken we nu dus een cookie variabele welke we ook kunnen toevoegen aan de Google Analytics tag.
Hierin moeten we echter nog een ding aanpassen. We moeten nu bij iedere keer dat die tag afgevuurd wordt eerst de HTML afvuren. Pas hiervoor in de GA4 setup tag bij tagvolgorde aan dat de HTML tag eerst wordt afgevuurd. Dit zorgt ervoor dat er gecontroleerd wordt of de cookie bestaat.