Start » Blog » Serverside Tracking
04.09.2021
Deduplizieren von Facebook Pixel- und CAPI Tracking
Wer einen serverseitigen Google Tag Manager (oder einen beliebigen anderen Weg) einsetzt, um via FB Conversions API ("CAPI") Daten an Facebook zu senden, steht früher oder später vor der Aufgabe, eine Deduplizierung über eine einheitliche Event ID für das gleiche Event zu unterstützen, wenn dieses parallel aus dem Browser und vom Server vermessen wird. Dieser Beitrag zeigt die Optionen dazu auf.
Optionen bei gleichzeitiger Verwendung von Pixel und CAPI
Grundsätzlich ist ein paralleler Betrieb im Browser und via Server ein Weg, der Facebook durchaus reicht ist. Und in einem gewissen Umfang kann auch jedes Event auf beiden Wegen gesendet werden, ohne dass es zu großen Problemen führen muss. Dennoch: Auf die Dauer - und in einem größeren Umfang - wird nicht nur der FB Events Manager meckern und eine Deduplizierung (oder Deduplikation? Egal) einfordern.
In diesem Fall ist eine Entscheidung zu treffen, wie das Tracking eigentlich genau aussehen soll. Je nachdem, was die Motivation für den Einsatz der CAPI ist, mag diese unterschiedlich ausfallen. Zur Auswahl stehen:
- Mischbetrieb mit eindeutigen Events. Das kann z. B. bedeuten, dass alle Seitenaufrufe nur aus dem Browser via Pixel gesendet werden, wichtige Events wie ein Purchase oder andere Conversions; E-Commerce-Events für die Bildung von Zielgruppen oder zu Remarketingzwecken o. A. sendet man nur vom Server. Auf diese Weise ist a) das Thema der Identifizierung geregelt, da im Browser bei jedem Seitenaufruf ein clientseitiges Tracking stattfindet und so die benötigten Cookies entstehen und man erhält b) die vermutlich beabsichtigte höhere Abdeckung bei den Events, die für die Kampagnensteuerung wesentlich sind.
- Raus aus dem Client. Aus Sicht der Reduktion von JavaScript im Browser ist dies eigentlich die beste Option. Landet alles, was man für die Vermessung in FB benötigt, in einem passenden Format am eigenen Server (das kann GA4, aber auch UA oder ein anderes Format sein, wenn man das serverseitige Tag patcht oder ein eigenes einsetzt), besteht eigentlich kein Grund, im Browser den ganzen Zauber nochmal zu veranstalten. Makel an dieser Option: Irgendwie muss man sich um die Identifizierbarkeit kümmern. Da auf die (ungekürzte) IP und den User Agent allein zu setzen, ist aus mehr als einem Grund problematisch. Eine E-Mail-Adresse und die erweiterten Matching-Optionen sowieso. Also muss (freilich - wie im Browser auch - nur bei Consent) ein Cookie her. Aus einem fbclid-Parameter beim Eintritt auf der Website kann ein _fbc-Cookie erstellt werden. Dazu muss nicht einmal eine Zeile Code am Server geschrieben werden. Die ID kann per Variable aus dem Request entnommen werden, auch für den Timestamp ist eine Variable verfügbar und das Cookie Monster Template besorgt den Rest der Aufgabe. Auch wenn FB auf einen Einsatz im Browser drängt: Das ist eine vollkommen valide und praxistaugliche Option.
- Maximale Deduplizierung: In dieser Variante feuert alles; jeweils aus Client und Server. Damit FB es möglichst einfach und zuverlässig schafft, die jeweils gleichen Hits aus unterschiedlichen Quellen miteinander in Deckung zu bringen, dient eine eindeutige Event ID. Dieser Beitrag hätte die falsche Überschrift, wenn es hier nicht primär um die Deduplizierung mittels Event ID gehen würde. Also los.
Wie kommt man zur Event ID?
Prinzipiell klingt die Anforderung relativ simpel. Warum nicht einfach eine Zufallszahl generieren und diese für den Seitenaufruf verwenden? Würde man nur Seitenaufrufe vermessen, würde das vermutlich ausreichen. Zumindest in einer "klassischen" Website, bei der eine neue Seite auch einen neuen Seitenladevorgang und eine neue Zufallszahl bedeutet. In einer Single Page Application wäre aber auch das schon nicht mehr ausreichend. Viel wesentlicher: Eine Tracking-Implementierung beinhaltet normalerweise mehr als nur Seitenaufrufe.
Produktdetailseiten senden neben dem Pageview auch ein ViewContent... und danach ggf. auch ein AddToCart Event. All diese Events benötigen eine eindeutige ID, wenn diese von Pixel und CAPI gesendet werden sollen. OK, streng genommen ist die Event ID und der Eventname als Kombination (zumindest, wenn es nur ein AddToCart Event gibt) in diesem Szenario immer noch eindeutig genug zur Deduplizierung; als Ausweg kann zudem für die ID die Zufallszahl mit dem Event-Namen kombiniert werden. Die Anforderung ist sicher dennoch klar: Ein Event, eine eindeutige Event ID.
Im Google Tag Manager kommt dabei das Konzept der Trigger in´s Spiel, die sich in den allermeisten Fällen in Form eines Events im dataLayer wiederfinden. Diese Events haben sogar eine eigene laufende ID, die man mit in seine Event ID einbauen kann.
Eine Event ID für jedes dataLayer Event
Genau hier setzt das Template Unique Event ID für den clientseitigen Google Tag Manager an. Hier wird aus einem Zeitstempel, der laufenden ID des Events und dessen Name eine ID gebildet, die man sowohl im Facebook Tag (Community Template) als Event-ID eingeben (bzw. bei Verwendung von Benutzerdefiniertem HTML als eventID an die Nutzlast des Trackinghits anhängen) als auch als Event-Parameter event_id beim GA4 Tag über den eigenen Server und die CAPI mit dem Event weitergeben kann.
Ich habe dieses Template in einigen Setups verwendet. Es hat allerdings einen kleinen Schönheitsfehler, der aber nicht unbedingt relevant sein muss: Der Zeitstempel, der hier verwendet wird, wird aus gtm.start übernommen. Das bedeutet allerdings, dass alle Events, die vor diesem Event im dataLayer landen (Initialisierung, frühe Pushes in den dataLayer etc.), hier eine Lücke aufweisen und daher nicht mehr zwingend eindeutig sind. Ich habe daher ein alternatives Variablen-Template für eine Event ID erstellt, welches ich zumindest dann empfehle / bevorzuge, wenn etwas vor gtm.start das Haus verlassen soll.
Solange die Tags für Facebook und GA4 (gehen wir davon aus, dass im GA4 Format gearbeitet wird, um Daten an den serverseitigen Tag Manager zu senden) zum gleichen Zeitpunkt ausgelöst werden (also beim gleichen Event), ist dies der beste Weg, um eine Event ID zu erstellen und zu übergeben. Meint: FB Pageview und GA4 Pageview feuern auf dem gleichen Trigger. Ebenso FB ViewContent und GA4 view_item sowie alle anderen E-Commerce- und sonstigen Events, die parallel aus Browser und vom Server an FB gesendet werden sollen.
Event ID für "asynchrone" Auslösung der Tags
Was wie eine Selbstverständlichkeit klingt, ist leider nicht immer gegeben. Speziell bei Einsatz bestimmter Consent Manager (z. B. Borlabs Cookie) ist es üblich, dass für einzelne Vendoren oder Consent-Gruppen zu unterschiedlichen Zeiten Trigger bzw. Trigger-Gruppen im dataLayer auftauchen, die zum Auslösen von Tags gemäß Consent genutzt werden. Auf diese Weise werden GA4 und FB nur in Ausnahmefällen gleichzeitig feuern - zumindest im Fall von Events, die "beim Aufruf" einer Seite stattfinden (PageView, ViewContent, InitiateCheckout, Purchase, CompleteRegistration, Lead... also eine ganze Menge) und nicht auf eine Aktion wie einen Klick zurückzuführen sind, bei dem die Consent-Lage i. d. R. bereits geklärt ist (wie ein AddToCart).
Will man dennoch auch in diesem Fall eine eindeutige und gleiche Event ID bei beiden zeitlich versetzten Hits verwenden, muss diese beim ersten Event erstellt und beim zweiten noch immer abrufbar sein. Dazu gibt es ebenfalls verschiedene Ansätze. Einer davon, den ich selbst einsetze und auf GitHub zur Verfügung stelle, basiert auf kurzlebigem Caching von IDs in einer JavaScript Variable mit definierbarem Ablauf-Zeitstempel; getrennt für verschiedene Event-Typen. So kann z. B. innerhalb einer Sekunde bei zwei dataLayer Events die gleiche ID für einen Seitenaufruf verwendet werden, aber eine andere, ebenso bei beiden Hits übereinstimmende ID für das ebenso unmittelbar auftretende ViewContent / view_item Event. Die Konfiguration und der Einsatz sind hier im Folgenden beschrieben und werden in auch in einem Video demonstriert.
Event ID im Google Tag Manager konfigurieren
Je nachdem, ob Events an FB aus dem Browser und GA4 an den Server synchron oder asynchron getriggert werden, kann mit einer der o. a. Lösungen eine Variable angelegt werden, die die Event ID enthält. Für den asynchronen Fall kommt man dabei allerdings nicht mit einer einzigen Variable aus, sondern es muss für jeden Event-Typen eine eigene Variable angelegt werden. Das Prinzip der Verwendung ist aber generell das Gleiche. Davon ausgehend, dass es getrennte Tags für die jeweiligen Events gibt, ist die Angabe der Event-ID bei den FB und GA4-Tags mehrfach durchzuführen. Entweder mit der stets gleichen Variable (synchron) oder der zum Event passenden ID Variable (asynchron). Hier im Beispiel verwenden wir unterschiedliche Event ID Variablen (-> asynchrone Trigger ) und konfigurieren damit den FB / GA4 Seitenaufruf und das exemplarisch für alle anderen Events stehende "ViewContent" beim Aufruf einer Produktdetailseite in einem Shop.
Event ID Variable(n) anlegen
Variante 1 für synchrones Triggern: Für übereinstimmende Trigger (synchrones Auslösen der Tags) kann im GTM bei der Neuanlage der einzigen erforderlichen ID Variable das o. a. Template aus der Community Gallery ausgewählt werden. Hinweis: Nach dem Import ist der GTM gern zickig, wenn die neue Variable gespeichert werden soll. Vorgang abbrechen, erneute Neuanlage und Auswahl der dann importierten Vorlage sollte aber einwandfrei funktionieren.
Variante 2 für zeitversetzte Trigger: Für den asynchronen Fall werden mehrere Variablen benötigt. Bevor die Variablen für die Event IDs für PageViews etc. angelegt werden können, wird eine "Helper"-Variable als Benutzerdefiniertes JavaScript erzeugt, welche die Funktion zur Generierung und Abruf aus dem Cache bereitstellt. Das ist eine auf den ersten Blick recht umständliche, aber effiziente und codesparende Methode, da die Funktion sonst in jeder der Event-ID-Variablen für alle zu deduplizierenden Eventtypen immer wieder neu definiert werden müsste.
Der Code kann hier aus der Rohansicht bei Github direkt kopiert und in einer neuen JS-Variable eingefügt werden. In diesem Beispiel wird sie "Helper | GetEventId" benannt und so auch im Code der anderen Variablen referenziert.
In einer weiteren JS-Variablen (hier: "Event ID | Pageview") wird diese Funktion nun aufgerufen, um eine Event ID für Seitenaufrufe zu erzeugen. Als Parameter wird der Typ des Events angegeben ("page_view"), um mehrere IDs für unterschiedliche Eventtypen erstellen und unterscheiden zu können. Der Code ist überschaubar:
return {{Helper | GetEventId}}('page_view');
}
Da im Beispiel auch die Produktdetail-Seitenaufrufe mit einer Event ID versehen werden sollen, wird der Vorgang für eine weitere Variable "Event ID | View Item" wiederholt - genau wie für alle anderen Event-Typen, die so dedupliziert werden sollen.
Hinweis: Der zusätzliche Parameter "2" in diesem Fall verlängert das Leben der ID auf zwei Sekunden (Standard ist eine Sekunde). Grund: Wenn man im Debugger des Tag Managers unterschiedliche Ids für die jeweiligen Events sieht, die eigentlich die gleiche ID haben sollten, kann man dem mit einer Verlängerung entgegen wirken. Das ist aber in der Praxis kaum erforderlich, zumal im Live-Betrieb im Gegensatz zur Vorschau nicht alle Variablen bei jedem (auch den frühen) Ereignis ausgewertet werden und daher auch ein schnellerer Ablauf droht.
Ids in Tags eintragen
Mit diesen ID-Variablen können nun die FB- und GA4-Tags ergänzt werden, um gleiche Event IDs für gleichartige Messpunkte zu übergeben. Im Fall eines FB Tags auf Basis der Community Vorlage geschieht dies unter "More Settings". Hier für den Seitenaufruf; analog dazu muss dann auch das ViewContent-Tag mit der passenden Event ID-Variable ausgestattet werden.
Wird HTML-Code genutzt, ist der Variablenwert als eventID Parameter anzuhängen. Z. B. bei einem ViewContent Event:
fbq('track', 'ViewContent', {...}, {eventID: {{Event ID | View Item}} });
Damit die GA4 Tags die gleichen IDs an den Server übergeben, so dass das dortige FB Tag diese finden und nutzen kann, muss die Id im jeweiligen Tag als Event-Property mit dem Schlüssel event_id angegeben werden.
Das Gleiche ist nun auch für das GA4 "view_item" Event-Tag mit der passenden Variable zu wiederholen.
Hinweis: Speziell bei GA4 ist es im synchronen Fall freilich einfacher, denn da kann stets die gleiche Variable genutzt werden und bei allen Events vom GA4-Konfigurations-Tag übernommen werden.
Gibt man im serverseitigen FB Tag einen Test Event Code an, der auf der Seite "Events testen" des FB Events Managers zu finden ist, ...
... startet die Vorschau und ruft eine Produktdetailseite auf, sollten sich im FB Events Manager sowohl der Seitenaufruf als auch das ViewContent Event sowohl vom Browser als auch vom Server sehen, korrekt gruppiert und mit jeweils übereinstimmenden Event-Ids.
Ist diese Bestätigung erfolgt, können auch die weiteren Event-Typen auf gleiche Weise dedupliziert werden. Wie schon gesagt: Kann man FB und GA4-Tags jeweils beim gleichen Event feuern, ist der Vorgang natürlich einfacher. Aber auch bei Notwendigkeit von Caching und damit getrennter Variablen für jedes Event ist die Einrichtung zwar aufwändiger, aber führt zu ebenso verlässlichen Ergebnissen. Der Events Manager - und die Kampagnen - werden es dankend zur Kenntnis nehmen. Damit: Happy Tagging!
Serverside Tracking Siehe auch: capi, serverside tracking