In meinem ersten Proof-of-Concept der Google Analytics 4 Recipes Artikelserie widme ich mich einem altbekannten Problem: dem Vermeiden doppelt gesendeter Transaktion zu Google Analytics. Es gibt bereits viele gute Ansätze zu diesem Problem aber ich möchte hier die Möglichkeiten von Google Analytics 4 im Streaming Export nach BigQuery darstellen. Die bisherigen Ansätze basieren meist auf dem Schreiben von Cookies oder Local Storage Einträgen aber immer mehr Browser löschen diese Informationen nach einiger Zeit. Ich möchte eine Lösung aufzeigen wie direkt mit Google Analytics 4 gesammelte Daten zur Vermeidung von Duplicate Transactions dienen können, ohne Cookies oder Local Storage Informationen schreiben zu müssen.
Das Problem und bisherige Lösungen
Duplicate Transactions, also das mehrfache Senden der gleichen Transaktionen an Google Analytics, kann mehrere Ursachen haben. Häufig ist es einfach ein Page Reload der Bestellbestätigungsseite, bei dem die Informationen zur Transaktion erneut in den dataLayer gepusht und an Google Analytics gesendet werden. Oftmals fällt dies nicht direkt im Interface in Google Analytics auf, da bei gleicher Transaction ID die Daten aggregiert dargestellt werden, das heißt ich sehe nur eine Transaction ID aber Revenue und Produktinformationen sind mehrfach vorhanden.
Schaut man sich das jedoch nach Transaktionszeit an werden doppelte Transaktionen sichtbar.
Um dieses Verhalten zu unterbinden, wurde häufig die Transaction ID in einem Local Storage Eintrag oder in einem Cookie gespeichert, vor dem Absenden des E-Commerce Hits abgeglichen und damit bereits getätigte Transaktionen nicht noch mal gesendet. Diese Lösung funktioniert sehr gut sofern die Information nicht durch den Browser gelöscht wurde (ITP und so ;)).
Der Workflow
Mit dem Google Analytics 4 BigQuery Streaming Export ist es aber auch möglich, ohne diese clientseitige Information eine Prüfung auf die Transaction ID durchzuführen. Hierfür verwende ich folgenden Workflow:
Wird im Online-Shop eine Transaktion ausgelöst, erfasst der Google Tag Manager die Transaktions ID und sendet diese an eine Cloud Function. Die Cloud Function durchsucht den Google Analytics Export auf diese Order ID, sowohl für den aktuellen Tag als auch für die Vergangenheit (in meinem Beispiel 30 Tage). Das Ergebnis der Suche pusht die Cloud Function dann in den dataLayer. Falls die Transaction ID eindeutig ist, das heißt bisher nicht verwendet wurde, sendet mit Google Tag Manager den Hit an Google Analytics.
Schritt 1: Das BigQuery SQL Statement
Fangen wir bei der Umsetzung mit dem SQL Statement an, das die OrderID im Google Analytics 4 Export sucht. Den BigQuery Export von Google Analytics 4 habe ich bereits in meinem Artikel “Google Analytics 4 Recipes: BigQuery Export” beschrieben.
Die Transaction ID befindet sich bei einem purchase Event als Event Parameter mit Key “transaction_id” in der passenden Value Spalte, in meinem Fall in der Spalte int_value, da ich nur Zahlen verwende. Das heißt, das SQL Statement muss nur ein „purchase“ Event in dem Zeitraum der letzten 30 Tage finden, das die gleiche Transaction ID hat, wie die zu prüfende Transaction ID. Falls es ein Event gibt, handelt es sich um eine Duplicate Transaction. Das SQL Statement sieht dann folgendermaßen aus:
SELECT SUM(A) FROM
(
(SELECT COUNT(event_name) as A FROM `<Projekt.Dataset>.events_*`, UNNEST(event_params) as e
WHERE event_name="purchase" and e.key="transaction_id" and e.value.int_value=3533 and
_TABLE_SUFFIX BETWEEN
FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)) AND
FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
LIMIT 1)
UNION ALL
(SELECT COUNT(event_name) FROM `<Projekt.Dataset>.events_intraday_20201021`, UNNEST(event_params) as e WHERE event_name="purchase" and e.key="transaction_id" and e.value.int_value=3533 LIMIT 1)
)
Brechen wir das Statement etwas auf:
(SELECT COUNT(event_name) as A FROM `<Projekt.Dataset>.events_*`, UNNEST(event_params) as e
WHERE event_name="purchase" and e.key="transaction_id" and e.value.int_value=3533 and _TABLE_SUFFIX BETWEEN
FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)) AND
FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
LIMIT 1)
Mit diesem Statement wird der Export auf Tagesbasis durchsucht, daher ist der Table events_* wobei das * den Zeitraum setzt, indem _TABLE_SUFFIX mit dem aktuellen Datum -30 Tagen als Startdatum und dem gestrigen Tag als Enddatum festgelegt wird. Die WHERE Clause definiert, das nur Events mit den Namen “purchase” und der passenden Transaction ID gesucht werden. Die Events werden dann gezählt und zurück geliefert. Da bereits bei einem Event mit der Transaction ID eine Duplicate Transaction vorliegt, kann durch “LIMIT 1” nach einer Fundstelle die Ausführung abgebrochen werden.
(SELECT COUNT(event_name) FROM `<Projekt.Dataset>.events_intraday_20201021`, UNNEST(event_params) as e WHERE event_name="purchase" and e.key="transaction_id" and e.value.int_value=3533 LIMIT 1)
Die Intraday-Events sind nicht in partitionierten Tabellen vorhanden, daher benötigen wir kein _TABLE_SUFFIX, dafür muss der Tabellenname angepasst werden, da dieser immer das Datum enthält.
Mit dem SELECT SUM(A) … UNION ALL Statement werden die Ergebnisse beider Tables kombiniert. Das Ergebnis wird über eine Cloud Function zurückgegeben.
Schritt 2: Die Cloud Function
Die Cloud-Function ist recht einfach in Python programmiert. Sie nimmt den TID Parameter, validiert diesen durch einen Regulären Ausdruck (in diesem Fall nur Zahlen), fragt die Datenbank ab und sendet das Ergebnis in den dataLayer.
Der (rohe) Code sieht dann wie folgt aus:
Die Cloud Function liefert dann entweder „Unique“, „Duplicate“ oder „invalid“ zurück.
Schritt3 : Der Google Tag Manager
Um auf die Cloud Function im Google Tag Manager zuzugreifen, wird ein Tag ausgespielt, das die Transaction ID als GET Parameter übergibt. Diese wird als dataLayer Variable
ecommerce.purchase.actionField.id
ausgelesen. Das Ergebnis der Funktion ist entweder “Unique”, das keiner Duplicate Transaction entspricht , “Duplicate”, bei dem die Transaktion nicht an Google Analytics gesendet wird, oder „invalid“ wenn die Transaction ID nicht dem Schema entspricht. Das Ergebnis wird dann in den dataLayer gepusht. Das Tag sieht dann so aus:
Das Tag wird im Google Tag Manager bei E-Commerce Event Purchase (in meinem Fall „EEC – orderCompletedEEC“) ausgelöst und sendet ein neues Event “Unique” bzw ”Duplicate” zurück, auf dem dann das E-Commerce Tag ausgelöst werden kann:
Handelt es sich um keine Duplicate Transaction, wird Unique in den dataLayer gepusht und der Hit geht raus:
und im Google Tag Manager Debugger:
Jetzt wird ein erneutes Purchase Event in den dataLayer gepusht:
Da durch das Abfragen der Daten der E-Commerce Hit etwas später gesendet wird, kann das Laden der Bestellbestätigungsseite per GTM etwas hinausgezögert werden, beispielsweise durch Einblendung einer Animation.
Fazit:
Mit dem Streaming Export in Google Analytics 4, der nun allen Nutzern, nicht nur Google Analytics 360 Kunden zur Verfügung steht, und nur noch wenige Sekunden statt Minuten benötigt um Daten zu exportieren, eröffnen sich neue Anwendungsfälle. Im nächsten Teil der Google Analytics 4 Recipes steht die User Journey im Mittelpunkt.
1 thought on “Google Analytics 4 Recipes: Duplicate Transactions vermeiden”