Tutorial: Die TikTok Events API für Onlineshops implementieren

Inhalt
Ein TikTok-Pixel allein meldet weniger Käufe, als ein Shop tatsächlich abwickelt. Blocker, der Tracking-Schutz im Browser und Besucher, die den Tab schließen, bevor die Bestätigungsseite fertig gerendert ist, entfernen Events, die stattgefunden haben. Dieselben Käufe ein zweites Mal vom Server zu senden schließt diese Lücke – und erzeugt ein neues Problem, denn TikTok erhält nun zwei Meldungen über einen Kauf.
Aufgelöst wird das über eine gemeinsame event_id: ein Wert, je Kauf einmal erzeugt und unverändert auf beiden Wegen gesendet. Die folgende Anleitung baut diese Architektur vollständig für einen Shop auf – das Browser-Event, die Kennungen, die der Server von sich aus nicht sieht, die Server-Anfrage und die Prüfung, ob die Deduplizierung tatsächlich greift.

Schritt 1: Die Event-ID einmal erzeugen
Die event_id muss an einer Stelle erzeugt und wiederverwendet werden – sie unabhängig auf beiden Seiten zu erzeugen scheidet damit aus, denn zwei Zufallswerte beschreiben aus Sicht von TikTok zwei getrennte Conversions. Für einen Shop ist die Bestellnummer die naheliegende Quelle: Sie existiert im Moment des Kaufs bereits, ist stabil und steht sowohl der Bestätigungsseite als auch dem Backend zur Verfügung.
Ein Präfix hält Eventtypen auseinander, denn eine einzelne Bestellung kann mehr als ein getracktes Event erzeugen. Eine event_id purchase-10432 für den Kauf und checkout-10432 für den Checkout-Start hält jedes Paar bei seinem eigenen Gegenstück. Als Nebeneffekt erzeugt ein Besucher, der die Bestätigungsseite neu lädt, dieselbe event_id erneut und wird dedupliziert statt doppelt gezählt.
Schritt 2: Das Browser-Event
Im TikTok-Pixel reist die Kennung im dritten Argument von ttq.track, getrennt von den Event-Eigenschaften:
ttq.track('CompletePayment', {
contents: [
{ content_id: 'SKU-8891', content_type: 'product', quantity: 1, price: 149.00 }
],
value: 149.00,
currency: 'PLN'
}, {
event_id: 'purchase-10432'
});
Auch der Eventname muss auf beiden Seiten übereinstimmen. TikTok paart die beiden Meldungen über die Kombination aus Eventname und event_id; CompletePayment im Browser und Purchase auf dem Server sind also zwei verschiedene Events, die nie gegeneinander deduplizieren – gleich wie sorgfältig die Kennung abgeglichen wird.
Schritt 3: Die Kennungen erfassen, die der Server nicht sieht
Zwei Werte existieren nur im Browser. ttclid kommt als URL-Parameter an, wenn ein Besucher über eine TikTok-Anzeige landet, und _ttp ist das First-Party-Cookie, das das Pixel setzt. Beide verbessern die Zuordnung der Server-Anfrage, und beide müssen beim Landen gesichert werden – die Bestätigungsseite liegt meist mehrere Navigationen später, und der URL-Parameter ist dann längst weg:
// Beim Landen: Klick-ID fuer den restlichen Besuch sichern
const ttclid = new URLSearchParams(window.location.search).get('ttclid');
if (ttclid) {
document.cookie = 'shop_ttclid=' + encodeURIComponent(ttclid) +
';max-age=2592000;path=/;secure;samesite=Lax';
}
Im Checkout werden beide Werte aus den Cookies gelesen und am Bestelldatensatz gespeichert, damit das Backend sie beim Bau des Server-Events zur Hand hat. IP-Adresse und User Agent des Besuchers stammen aus der ursprünglichen HTTP-Anfrage und gehören in denselben Datensatz – eine später vom Server gesendete Anfrage hat weder das eine noch das andere von sich aus.
Schritt 4: Die Server-Anfrage
Die Events API nimmt einen POST an den event/track/-Endpunkt der TikTok Business API entgegen, authentifiziert über ein Access Token aus dem TikTok Events Manager und über event_source_id an ein Pixel adressiert. Identifizierende Felder werden normalisiert und dann per SHA-256 gehasht; nichts Identifizierendes verlässt den Server im Klartext:
{
"event_source": "web",
"event_source_id": "PIXEL_CODE",
"data": [{
"event": "CompletePayment",
"event_time": 1789000000,
"event_id": "purchase-10432",
"user": {
"email": "1f3a...",
"phone": "9c22...",
"external_id": "7b41...",
"ttclid": "E.C.P.xxxxx",
"ttp": "2ABCDe...",
"ip": "203.0.113.7",
"user_agent": "Mozilla/5.0 ..."
},
"properties": {
"contents": [
{ "content_id": "SKU-8891", "content_type": "product", "quantity": 1, "price": 149.00 }
],
"currency": "PLN",
"value": 149.00
},
"page": { "url": "https://shop.example.com/danke" }
}]
}
Die Normalisierung vor dem Hashen entscheidet, ob die Kennungen überhaupt etwas treffen: E-Mail getrimmt und kleingeschrieben, Telefonnummer auf Ziffern im internationalen E.164-Format reduziert. Derselbe Wert, einmal aus Anna@Example.com und einmal aus anna@example.com gehasht, ergibt zwei unabhängige Digests, von denen nur einer passen kann. event_time ist ein Unix-Zeitstempel in Sekunden, und die Anfrage gehört unmittelbar hinter die Bestellbestätigung statt in einen nächtlichen Stapel. TikTok weist zu spät eintreffende Events ab, und ein Batch-Job merkt das erst, wenn das Zeitfenster bereits zu ist.
Schritt 5: Prüfen, ob die Deduplizierung greift
Das Feld test_event_code aus dem Reiter für Testereignisse im Events Manager leitet eine Anfrage in die Testansicht, ohne das Reporting zu berühren – genug, um zu bestätigen, dass die Nutzlast angenommen und die gehashten Felder erkannt werden.
Die Deduplizierung selbst zeigt sich erst in Echtdaten. Im Events Manager weist ein Event, das beide Kanäle erhält, seine Browser- und Serverzahlen getrennt aus; die Differenz zwischen deren Summe und dem deduplizierten Gesamtwert ist der Beleg, dass die Paarung funktioniert. Ein Gesamtwert, der genau der Summe beider Kanäle entspricht, bedeutet, dass nichts zusammengeführt wird – meist ein abweichender Eventname oder eine je Seite getrennt erzeugte event_id. Der Abgleich der deduplizierten Zahl gegen die tatsächlichen Bestellungen im Shop-Backend ist die Prüfung, auf die es ankommt; TikToks eigene Zahlen können keinen Kauf zeigen, den kein Kanal gemeldet hat.
Innerhalb der Leitplanken bleiben
Beide Kanäle gehören hinter dasselbe Werbe-Consent-Signal. Eine serverseitige Anfrage ist nicht deshalb von der Einwilligung ausgenommen, weil sie aus einem Backend stammt: Sie trägt dieselben Kundendaten, und die Rechtsgrundlage dafür ist die im Browser eingeholte – der Consent-Status muss also am Auftrag gespeichert und vor dem Bau der Anfrage geprüft werden. Rohe E-Mail-Adressen und Telefonnummern existieren nur so lange, bis sie normalisiert und gehasht sind, und das Access Token gehört in einen Secrets-Speicher statt in den Anwendungscode, denn es berechtigt zum Schreiben von Conversions in das Werbekonto.