Tutorial: Wdrożenie TikTok Events API w sklepach internetowych

Spis treści
Sam piksel TikTok raportuje mniej zakupów, niż sklep faktycznie realizuje. Blokery, ochrona przed śledzeniem w przeglądarce oraz osoby zamykające kartę, zanim strona potwierdzenia skończy się renderować, usuwają zdarzenia, które naprawdę wystąpiły. Wysłanie tych samych zakupów po raz drugi z serwera zamyka tę lukę — i tworzy nowy problem, ponieważ TikTok otrzymuje teraz dwa zgłoszenia jednego zakupu.
Rozwiązuje to wspólne event_id: jedna wartość generowana na zakup i wysyłana bez zmian obiema drogami. Poniższy przewodnik buduje tę architekturę od początku do końca dla sklepu — zdarzenie w przeglądarce, identyfikatory, których serwer sam z siebie nie widzi, żądanie serwerowe oraz weryfikację, czy deduplikacja faktycznie działa.

Krok 1: Wygenerowanie event_id jeden raz
event_id musi powstać w jednym miejscu i zostać użyte ponownie, co wyklucza generowanie go niezależnie po obu stronach — dwie losowe wartości opisują z punktu widzenia TikToka dwie odrębne konwersje. Dla sklepu naturalnym źródłem jest numer zamówienia: istnieje już w momencie zakupu, jest stabilny i dostępny zarówno dla strony potwierdzenia, jak i dla backendu.
Prefiks rozdziela typy zdarzeń, bo jedno zamówienie potrafi wygenerować więcej niż jedno śledzone zdarzenie. event_id w postaci purchase-10432 dla zakupu i checkout-10432 dla rozpoczęcia checkoutu utrzymuje każdą parę przy własnym odpowiedniku. Skutkiem ubocznym jest to, że odświeżenie strony potwierdzenia generuje to samo event_id ponownie i zostaje zdeduplikowane zamiast policzone dwa razy.
Krok 2: Zdarzenie w przeglądarce
W pikselu TikTok identyfikator podróżuje w trzecim argumencie ttq.track, oddzielnie od właściwości zdarzenia:
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'
});
Nazwa zdarzenia również musi być zgodna po obu stronach. TikTok paruje oba zgłoszenia po kombinacji nazwy zdarzenia i event_id, więc CompletePayment w przeglądarce i Purchase na serwerze to dwa różne zdarzenia, które nigdy się wzajemnie nie zdeduplikują — niezależnie od tego, jak starannie dopasowano identyfikator.
Krok 3: Przechwycenie identyfikatorów, których serwer nie widzi
Dwie wartości istnieją wyłącznie w przeglądarce. ttclid pojawia się jako parametr URL, gdy odwiedzający trafia z reklamy TikTok, a _ttp to plik cookie pierwszej strony ustawiany przez piksel. Obie poprawiają dopasowanie żądania serwerowego i obie trzeba utrwalić już przy wejściu — strona potwierdzenia znajduje się zwykle kilka przejść dalej, a parametru URL dawno tam nie ma:
// Przy wejsciu: utrwalenie click id na resztę wizyty
const ttclid = new URLSearchParams(window.location.search).get('ttclid');
if (ttclid) {
document.cookie = 'shop_ttclid=' + encodeURIComponent(ttclid) +
';max-age=2592000;path=/;secure;samesite=Lax';
}
W checkoucie obie wartości są odczytywane z plików cookie i zapisywane przy rekordzie zamówienia, żeby backend miał je pod ręką przy budowaniu zdarzenia serwerowego. Adres IP i user agent odwiedzającego pochodzą z pierwotnego żądania HTTP i należą do tego samego rekordu — żądanie wysłane później z serwera nie ma ani jednego, ani drugiego z własnych źródeł.
Krok 4: Żądanie serwerowe
Events API przyjmuje POST na endpoint event/track/ w TikTok Business API, uwierzytelniony tokenem dostępu z TikTok Events Managera i zaadresowany do piksela przez event_source_id. Pola identyfikujące są normalizowane, a następnie haszowane SHA-256; nic identyfikującego nie opuszcza serwera jawnie:
{
"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://sklep.example.com/dziekujemy" }
}]
}
Normalizacja przed haszowaniem rozstrzyga, czy identyfikatory w ogóle coś trafią: e-mail przycięty i zamieniony na małe litery, numer telefonu sprowadzony do cyfr w międzynarodowym formacie E.164. Ta sama wartość zahaszowana raz z Anna@Example.com , a raz z anna@example.com daje dwa niepowiązane skróty, z których tylko jeden może pasować. event_time to znacznik czasu uniksowego w sekundach, a żądanie należy tuż za potwierdzeniem zamówienia, a nie do nocnej paczki. TikTok odrzuca zdarzenia docierające zbyt późno, a zadanie wsadowe dowiaduje się o tym dopiero, gdy okno już się zamknęło.
Krok 5: Weryfikacja, czy deduplikacja działa
Pole test_event_code, pobrane z zakładki zdarzeń testowych w Events Managerze, kieruje żądanie do widoku testowego bez naruszania raportowania — tyle wystarczy, by potwierdzić, że ładunek jest przyjmowany, a pola zahaszowane rozpoznawane.
Sama deduplikacja ujawnia się dopiero na danych produkcyjnych. W Events Managerze zdarzenie zasilane z obu kanałów wykazuje liczby przeglądarkowe i serwerowe osobno, a różnica między ich sumą a zdeduplikowaną wartością całkowitą jest dowodem, że parowanie działa. Wartość całkowita równa dokładnie sumie obu kanałów oznacza, że nic nie jest łączone — zwykle wskutek rozbieżnej nazwy zdarzenia albo event_id generowanego osobno po każdej ze stron. Zestawienie zdeduplikowanej liczby z faktycznymi zamówieniami w backendzie sklepu to sprawdzenie, które ma znaczenie; własne liczby TikToka nie pokażą zakupu, którego nie zgłosił żaden kanał.
Pozostając w granicach
Oba kanały należą za ten sam sygnał zgody reklamowej. Żądanie serwerowe nie jest zwolnione ze zgody dlatego, że pochodzi z backendu: niesie te same dane klienta, a podstawą jego wysłania jest zgoda zebrana w przeglądarce — stan zgody trzeba więc zapisać przy zamówieniu i sprawdzić przed zbudowaniem żądania. Surowe adresy e-mail i numery telefonów istnieją tylko do momentu normalizacji i zahaszowania, a token dostępu należy do magazynu sekretów, a nie do kodu aplikacji, ponieważ uprawnia do zapisywania konwersji na koncie reklamowym.