10 min czytaniaFunkcje

Serwerowe śledzenie konwersji przez skrócone linki

Architektura przekazywania konwersji do Meta CAPI, GA4 Measurement Protocol i TikTok Events po stronie serwera - propagacja click_id, deduplikacja, hashowanie i semantyka ponownych prób

Ana Kowalska
Marketing solutions engineering
Server-side conversion forwarding diagram: short link captures click_id, order webhook triggers fan-out to Meta CAPI / GA4 MP / TikTok Events with SHA-256 hashed identifiers and dedup event_id

Piksel w przeglądarce to element atrybucji, który jako pierwszy przestaje działać. Inteligentna ochrona przed śledzeniem Apple ogranicza ciasteczka stron trzecich i degraduje referrer; blokery reklam usuwają wywołanie sieciowe piksela zanim opuści stronę; App Tracking Transparency iOS 14.5 na tyle obniżyła jakość sygnałów Meta na ruchu iPhone, że sama Meta traktuje teraz piksel przeglądarkowy jako zapasowy.

Serwerowe śledzenie konwersji to odpowiedź, co do której wszyscy się zgadzają. Implementacja to to, gdzie ludzie popełniają błędy. Ten wpis omawia architekturę w momencie, gdy skrócony URL posiada click_id - co robi skrócarka, co robi twój back-end, czego oczekują platformy reklamowe po swojej stronie, i kształt deduplikacji, który chroni przed podwójnym liczeniem, gdy zdarzenia zarówno z przeglądarki, jak i serwera są wysyłane.

Trzy platformy, do których większość zespołów przekazuje dane: Meta CAPI, GA4 Measurement Protocol, TikTok Events API. Mixpanel, Klaviyo i Pinterest przyjmują ten sam kształt z nazwami pól specyficznymi dla dostawcy. Będę konkretny co do Meta i GA4, bo to one napędzają większość budżetów; pozostałe podążają tym samym szablonem.

Dlaczego po stronie serwera#

Krótka wersja: przeglądarka nie jest już wiarygodnym źródłem sygnałów. Dłuższa wersja warta jest zrozumienia, bo kształtuje sposób konfiguracji deduplikacji.

Trzy rzeczy degradują konwersje po stronie przeglądarki:

Partycjonowanie ciasteczek i limity czasu życia. ITP Safari partycjonuje ciasteczka według witryny najwyższego poziomu i ogranicza ciasteczka first-party ustawiane przez skrypty do 7 dni (24 godzin po wykryciu známego trackera cross-site). Pełna ochrona ciasteczek Firefoksa robi podobne partycjonowanie. Brave i kohorta rozszerzeń prywatności idą dalej. Przepływ atrybucji z ciasteczkami first-party, który działał w 2018 roku, nie działa w 2026.

Blokery reklam. uBlock Origin, AdBlock Plus, Pi-hole, NextDNS i blokery na poziomie sieci dostarczają domyślne reguły dla connect.facebook.net, googletagmanager.com, analytics.tiktok.com i reszty powierzchni tagów marketingowych. Piksel nigdy nie odpala; konwersja nigdy nie jest rejestrowana.

iOS App Tracking Transparency i zmiany śledzenia linków w iOS 17. ATT obniżyła jakość sygnałów Meta. Ochrona śledzenia linków iOS 17 rozszerzyła to na parametry zapytań w trybie przeglądania prywatnego i Mail, usuwając fbclid, gclid i inne zanim link zostanie otwarty.

Skumulowany efekt na typowym sklepie Shopify z ruchem zdominowanym przez iOS: 25–40% konwersji jest pomijanych przez piksele po stronie przeglądarki. Dokładna liczba zależy od struktury ruchu; marki modowe i kosmetyczne z dominacją iOS są na wyższym końcu. Arytmetyka odzyskanego przychodu uzasadnia pracę inżynieryjną - dla sklepu robiącego 10 milionów euro rocznie z 30% luką w atrybucji piksela, odzyskanie nawet połowy tej luki to 1,5 miliona euro atrybucyjnego przychodu kierowanego z powrotem do platform, które go napędziły.

Serwerowe przekazywanie konwersji zamyka większość luki. Nie zamyka jej całkowicie - są konwersje, gdzie click_id nigdy nie był przechwycony (organiczne, bezpośrednie, search markowy), których żadna ilość CAPI nie odzyska - ale zamyka lukę wynikającą z blokowania po stronie przeglądarki.

Architektura#

Przepływ danych to cztery przeskoki: reklama → skrócony link → strona → przekazanie serwerowe.

Platforma reklamowa → skrócony link. Miejsce docelowe kreacji Meta lub Google Ads to skrócony link. Użytkownik klika; handler edge skracarki przechwytuje zdarzenie kliknięcia i przekierowuje do docelowego URL z dołączonym click_id.

Skrócony link → strona. Docelowy URL ma dołączone ?elido_click=<id> (konfigurowalne per-workspace). Menedżer tagów lub kod motywu na stronie odczytuje go i zapisuje do ciasteczka first-party lub, co ważniejsze, do niestandardowego atrybutu koszyka lub zamówienia.

Strona → zamówienie. Gdy użytkownik finalizuje zamówienie (koszyk Shopify złożony, zamówienie WooCommerce utworzone, koszyk headless skonwertowany), click_id jest w atrybutach/metadanych rekordu zamówienia. To jest trwały punkt przekazania - gdy click_id jest w zamówieniu, nie podlega wygaśnięciu ciasteczek ani czasowi życia sesji przeglądarki.

Zamówienie → przekazanie serwerowe. Webhook płatności zamówienia odpala z twojej platformy e-commerce. Twój back-end (lub Elido, jeśli mu to delegowałeś) odczytuje click_id, wyszukuje dane uwierzytelniające do przekazywania konwersji i wysyła POST konwersji do każdej połączonej platformy reklamowej. Platformy otrzymują konwersję i uznają powiązaną kampanię.

Rola skracarki to click_id w przeskoku 2 plus orkiestracja w przeskoku 4. Pierwsze jest proste; drugie to gdzie integracja zarabia na siebie.

Potok czterech przeskoków: kliknięcie z platformy reklamowej trafia do skróconego linku przechwytującego click_id, następnie do strony, rekordu zamówienia, a webhook opłacenia zamówienia wyzwala serwerowy fan-out do Meta CAPI, GA4 MP i TikTok Events

Deduplikacja: rzecz, której nikt nie wspomina przed produkcją#

Najczęstszy incydent produkcyjny, który widzę, to podwójne liczenie. Piksel po stronie przeglądarki jest nadal na stronie (zespół go nie wyłączył, bo chciał fallback dla ruchu non-Safari), a serwerowe przekazanie też się odpala. Meta pobiera obydwa zdarzenia. Konwersja jest liczona podwójnie, alokator budżetu nadmiernie ściąga, następny przegląd budżetu kampanii zauważa „zaraz, dlaczego nasz raportowany ROAS to 3× przychód?".

Naprawą jest identyfikator deduplikacji. Meta CAPI przyjmuje event_id. GA4 Measurement Protocol przyjmuje client_id i transaction_id. TikTok Events przyjmuje event_id. Jeśli zarówno przeglądarka, jak i serwer wysyłają to samo zdarzenie z tym samym ID deduplikacji, platforma kredytuje jedno i ignoruje drugie.

ID deduplikacji musi być tą samą wartością po obu stronach. ID zamówienia działa dla zdarzeń zakupu - zarówno piksel po stronie przeglądarki, jak i przekazanie serwerowe go widzą. Click_id działa dla zdarzeń upstream (lead, dodanie do koszyka, wyświetlenie treści), gdzie zamówienie jeszcze nie istnieje.

Dokumentacja deduplikacji Meta opisuje okno dopasowania: zdarzenia otrzymane w ciągu 48 godzin od siebie z tym samym event_id są traktowane jako duplikaty. Deduplikacja GA4 oparta na client_id jest podobna w zasadzie, choć skromniejsza w dokumentacji.

Zasada operacyjna: każda serwerowa konwersja musi zawierać ID deduplikacji, i musi to być ten sam ID, który emitował piksel po stronie przeglądarki. Pomijanie tego to różnica między działającą integracją CAPI a taką, która po cichu zawyża raportowane liczby przez trzy miesiące, dopóki ktoś nie zauważy.

Przepływ deduplikacji, gdzie piksel przeglądarkowy i przekazanie serwerowe wysyłają event_id order-001847; dopasowywacz platformy kredytuje jedno zdarzenie w oknie 48 godzin i odrzuca duplikat, podczas gdy niezgodne ID powodują podwójne liczenie

Wymagania dotyczące hashowania#

Zarówno Meta CAPI, jak i TikTok Events wymagają, aby identyfikatory e-mail i telefon były zahashowane SHA-256 przed transmisją. GA4 ściśle tego nie wymaga, ale akceptuje. Hashowanie dotyczy identyfikatorów klientów - em (email), ph (telefon), fn (imię), ln (nazwisko), ge (płeć), db (data urodzenia), ct (miasto), st (stan), zp (kod pocztowy), country (kraj) - nie metadanych zdarzenia.

Dwie pułapki. Po pierwsze, format musi być znormalizowany przed hashowaniem - małe litery, bez spacji, bez kodu kraju w telefonie, bez myślników. Hashowanie [email protected] daje inną wartość niż hashowanie [email protected]; platformy oczekują tego drugiego. Strona wymagań parametrów Meta wymienia reguły normalizacji per pole.

Po drugie, hash musi być małoliterowym hexem bez spacji. SHA256("[email protected]") daje a3b6...; API oczekuje a3b6..., a nie A3B6... i nie \xa3\xb6.... Większość SDK językowych domyślnie zwraca wielkie litery hex; musisz wynik zamienić na małe.

Jeśli routujesz przez endpoint Elido POST /v1/conversions, hashowanie jest obsługiwane po stronie platformy - wysyłasz POST z surowym email/telefonem, Elido wykonuje normalizację i hashowanie zgodnie z wymaganiami platformy i przekazuje dalej. Korzyść to jeden zestaw reguł normalizacji do utrzymania przez twój back-end zamiast trzech. Kosztem jest to, że ufasz Elido surowymi danymi osobowymi w momencie przekazania; żądanie jest szyfrowane podczas przesyłania i nie jest utrwalane po stronie serwera, ale model zaufania warto rozumieć przed podłączeniem.

Przykładowy POST do Meta CAPI#

Czego faktycznie chce platforma. Endpoint to POST https://graph.facebook.com/v21.0/{pixel_id}/events. Ciało to JSON.

{
  "data": [
    {
      "event_name": "Purchase",
      "event_time": 1716480000,
      "event_id": "order-acme-2026-05-23-001847",
      "action_source": "website",
      "event_source_url": "https://acme.example/checkout/thanks?order=001847",
      "user_data": {
        "em": ["a3b6...sha256 of email"],
        "ph": ["c4d7...sha256 of phone"],
        "client_user_agent": "Mozilla/5.0 ...",
        "client_ip_address": "203.0.113.42",
        "fbc": "fb.1.1716470000.AbCdEf",
        "fbp": "fb.1.1716470000.987654321"
      },
      "custom_data": {
        "currency": "EUR",
        "value": 89.5,
        "content_ids": ["sku-spring-jeans-32-blue"],
        "content_type": "product",
        "num_items": 1
      }
    }
  ],
  "test_event_code": "TEST12345",
  "access_token": "EAAxxxxxxx"
}

Trzy rzeczy warte uwagi:

event_id to klucz deduplikacji. Ustaw go na swój ID zamówienia; piksel Purchase po stronie przeglądarki ustawia tę samą wartość. Meta deduplikuje w oknie dopasowania 48 godzin.

fbc i fbp to identyfikatory ciasteczek Meta. fbc to identyfikator kliknięcia (fbclid z adresu URL strony docelowej, z przedrostkiem); fbp to identyfikator przeglądarki z ciasteczka _fbp. Obydwa są first-party z perspektywy twojej domeny i możliwe do przechwycenia serwerowego po zapisaniu ich ze strony docelowej. Bez nich wskaźnik dopasowania Meta spada; z nimi wskaźnik dopasowania jest doskonały.

test_event_code pozwala uruchamiać zdarzenia testowe, które nie wliczają się do raportowania produkcyjnego. Zawsze najpierw to podłącz; zweryfikuj w Test Events Menedżera Zdarzeń przed przełączeniem ruchu produkcyjnego.

Odpowiednik w API Elido: POST /v1/conversions z {click_id, event_name: "Purchase", value, currency, order_id, customer: {email, phone}}. Elido normalizuje i hashuje zgodnie ze specyfikacją Meta, wyszukuje fbc/fbp obszaru roboczego ze zdarzenia kliknięcia i konstruuje ładunek CAPI.

Przykładowy POST do GA4 Measurement Protocol#

Format wire GA4 jest podobny w kształcie, ale nazwy pól różnią się. Endpoint: POST https://www.google-analytics.com/mp/collect?measurement_id=G-XXX&api_secret=xxx.

{
  "client_id": "click-id-as-fallback-if-no-ga4-cookie",
  "user_id": "user-acme-12847",
  "events": [
    {
      "name": "purchase",
      "params": {
        "transaction_id": "order-acme-2026-05-23-001847",
        "value": 89.5,
        "currency": "EUR",
        "items": [
          {
            "item_id": "sku-spring-jeans-32-blue",
            "item_name": "Spring Jeans 32 Blue",
            "quantity": 1,
            "price": 89.5
          }
        ],
        "engagement_time_msec": 1
      }
    }
  ]
}

Uwagi:

client_id to wartość _ga ciasteczka GA4, jeśli jest dostępna; jeśli nie, click_id jest użytecznym fallbackiem (bo GA4 stworzy sesję z nim powiązaną).

transaction_id to klucz deduplikacji - ustaw go na ID zamówienia, ta sama wartość co zdarzenie purchase gtag po stronie przeglądarki; GA4 deduplikuje w oknie sesji.

engagement_time_msec musi być obecne i pozytywne, aby zdarzenie liczyło się do atrybucji; ustawienie go na 1 spełnia ten wymóg.

api_secret jest na poziomie obszaru roboczego. Dokumentacja GA4 MP opisuje konfigurację danych uwierzytelniających.

Semantyka ponownych prób#

Platformy akceptują ponowne próby; czego nie możesz robić, to ślepo je ponawiać. Trzy wzorce sprawdzają się w praktyce.

Idempotentność na ID deduplikacji. Jeśli event_id / transaction_id platformy to ID zamówienia i ponawiasz ten sam ładunek, platforma deduplikuje - drugie wysłanie jest cicho ignorowane. Bezpieczne.

Wykładnicze wycofanie przy 5xx. Zarówno Meta, jak i GA4 czasami zwracają 5xx. Ponawiaj z wycofaniem (1s, 2s, 4s, 8s do 60s, potem zrezygnuj). Ponowne próby powinny zachowywać ten sam event_id, żeby platforma deduplikowała wszelkie przypadki częściowego sukcesu.

Nie ponawiaj przy 4xx. Odpowiedź 4xx oznacza, że ładunek jest źle uformowany lub dane uwierzytelniające są błędne. Ponowna próba tego nie naprawi; zużywa tylko budżet rate-limit. Zaloguj, zaalarmuję, napraw problem upstream.

Jeśli routujesz przez Elido, obsługa ponowień/wycofania jest wbudowana - POST /v1/conversions zwraca natychmiast, a fan-out do platform odbywa się w tle, ze stanem ponowień obserwowalnym przez GET /v1/conversions/{id}. Jeśli robisz to własnoręcznie, warstwa kolejkowania (RabbitMQ, Kafka, AWS SQS) to miejsce, gdzie żyje kształt ponowień.

Diagram decyzji o ponownych próbach: POST konwersji oparty na ID zamówienia rozgałęzia się według klasy odpowiedzi, 2xx oznacza wykonano, 5xx wyzwala wykładnicze wycofanie i ponowny POST z tym samym event_id, a 4xx zatrzymuje się z logiem i alertem

Tryb testowy i dry-run#

Największy błąd, który popełniają zespoły, to pomijanie dry-run.

Meta ma Test Events. Ustawiasz test_event_code na ładunku, zdarzenia pojawiają się w panelu Test Events w ciągu sekund, weryfikujesz kształt i deduplikację. Zdarzenia produkcyjne przychodzą przez ten sam endpoint, ale bez test_event_code.

GA4 ma DebugView. Ustawiasz debug_mode: 1 w parametrach zdarzenia, zdarzenia pojawiają się w DebugView, weryfikujesz przed przełączeniem ruchu produkcyjnego.

TikTok ma podobny tryb testowy w interfejsie Menedżera Zdarzeń.

Lista kontrolna weryfikacji jest krótka. Złóż testowe zamówienie, zaobserwuj webhook płatności zamówienia, zaobserwuj uruchomienie przekazania konwersji, zaobserwuj jego dotarcie do panelu testowego platformy. Potwierdź, że event_id odpowiada wartości piksela po stronie przeglądarki. Potwierdź, że wartość, waluta i content_ids wyglądają poprawnie. Następnie wyłącz tryb testowy i obserwuj pierwsze dziesięć zamówień produkcyjnych.

Jeśli pominiesz ten krok, dowiesz się, że integracja jest uszkodzona trzy dni później, gdy raporty są płaskie. Pomijanie dry-run to najczęstszy pojedynczy tryb awarii, który widzę.

Typowe tryby awarii#

Brakujący click_id w zamówieniu. Najczęstszy. Opisany już w cornerstone e-commerce; naprawa polega na przeprowadzeniu click_id przez koszyk do zamówienia.

Niezgodność hashy. [email protected] zahashowany bez normalizacji daje inną wartość niż [email protected]. Platformy odrzucają dopasowanie, konwersja trafia bez dopasowania identyfikatora, a raportowanie Meta przypisuje ją do „niedopasowanych". Naprawa to reguły normalizacji z dokumentu parametrów Meta CAPI; czystszą odpowiedzią jest delegowanie hashowania do skracarki, żeby reguły żyły w jednym miejscu.

Nieprzechwycony fbc. Gdy użytkownik trafia z reklamy Meta, URL zawiera fbclid; strona musi go przechwycić i utrwalić (zazwyczaj w ciasteczku first-party lub atrybucie koszyka). Bez fbc wskaźnik dopasowania Meta spada znacznie. Naprawą jest krok menedżera tagów na stronie docelowej, który zapisuje fbc do ciasteczka first-party lub atrybutu koszyka.

Niespójny ID deduplikacji. Piksel po stronie przeglądarki używa ID zamówienia; serwer używa UUID generowanego w czasie przekazania. Obydwa zdarzenia są pobrane, żadne nie jest deduplikowane. Naprawą jest upewnienie się, że serwerowe przekazanie używa tej samej wartości event_id, jaką emitował piksel po stronie przeglądarki - ID zamówienia dla zakupów to standardowa odpowiedź.

Niezgodność waluty. Przeglądarka wysyła USD (bo konfiguracja gtag domyślnie to USD); serwer wysyła EUR (bo zamówienie jest w EUR). GA4 i Meta traktują walutę jako część sygnatury zdarzenia w niektórych kontekstach dopasowania, i konwersje trafiają, ale nie agregują czysto. Naprawą jest pobieranie waluty z zamówienia, nie z konfiguracji na poziomie strony.

Gdzie to żyje w warstwie danych#

Przekazywanie konwersji to jeden element szerszego pipeline'u atrybucji. Cornerstone dla otaczającego pipeline'u to Jak śledzić kampanie UTM end-to-end bez CDP - ten post omawia szczegółowo szablon UTM obszaru roboczego, nadpisania na poziomie kampanii, masowy import i krok weryfikacji dry-run. Ten post to głębsze zagłębienie w serwerowy fan-out zamykający pętlę.

Dla przewodnika operacyjnego dokumentacja przekazywania konwersji to podejście krok po kroku. Dla architektonicznego szczegółu, jak Elido wykonuje fan-out bez przekraczania limitów rate platform, post o architekturze ingestion kliknięć opisuje pipeline fire-and-forget.

Przeczytaj klaster#

Siostrzane posty w klastrze features: Inteligentne linki - wyjaśnienie (cornerstone), Webhooks dla zdarzeń linków (szerszy kształt zdarzenia) i Przekazywanie konwersji do Meta CAPI (głębsze zagłębienie specyficzne dla Meta). Dla wersji skierowanej do persony, solutions/marketers to strona; strona funkcji śledzenia konwersji to powierzchnia produktu.

Powiązane na blogu#

Wypróbuj Elido

Wklej URL, otrzymaj krótki link

Bez rejestracji. Link działa 30 dni. Zarejestruj się, aby zachować go na zawsze.

Za darmo, bez rejestracji · 2 dziennie

Wypróbuj Elido

Skracarka URL hostowana w UE: własne domeny, głęboka analityka i otwarte API. Darmowy plan - bez karty kredytowej.

Tagi
server side conversion tracking
meta capi
ga4 server side
conversion api
tiktok events api
deduplication
click_id

Czytaj dalej