Server-side tracking 30 lipca 2026 13 min czytania

Ukryty duplikat Purchase, którego nie ma w żadnym pliku Twojego sklepu

Server-side na Shoperze jest czysty, event_id wszędzie, a Meta pokazuje 14% pokrycia Purchase. Bo drugi Purchase generuje sama Meta - z konfiguracji sprzed lat, której nie ma w żadnym pliku.

Świeżo postawiony tracking na sklepie Shoper. Server-side Purchase z backendu, browserowy piksel z event_id, deduplikacja spięta, wartości zgadzają się z panelem zamówień. A Meta pokazuje, że tylko 14% browserowych Purchase ma pokrycie po stronie API konwersji - przy celu 75%.

Grepujesz motyw. Czysto. Sprawdzasz swój kontener GTM - jeden tag Purchase, z event_id. Wyłączasz po kolei wszystko, co podejrzane. Nic. A mimo to na każde zamówienie do Mety lecą dwa browserowe Purchase. Drugiego nie ma w żadnym pliku, który możesz otworzyć.

Bo on nie jest w pliku. To historia śledztwa na prawdziwym sklepie Shoper: jak czysty server-side ujawnił duplikat, którego źródłem była sama Meta i warstwy integracji, które piksel zbierał latami. Z prawdziwymi ślepymi zaułkami - bo bez nich to byłaby laurka, nie diagnostyka.

Pokrycie zdarzeń to wykrywacz kłamstw Twojego trackingu

Wskaźnik pokrycia zdarzeń piksela przez API konwersji to prosta proporcja: ile Twoich browserowych Purchase ma pasującą parę po stronie serwerowej (to samo event_id). Meta liczy to w oknie 7 dni.

To inny problem niż klasyczna duplikacja, która zawyża ROAS - tamtą i jej trzy najczęstsze, widoczne źródła opisałem w tekście o duplikacji eventów purchase w Shoper. Pokrycie mówi co innego: czy Twój czysty, serwerowy pomiar w ogóle dopina się do tego, co widzi przeglądarka.

I tu jest sedno. Ta metryka staje się widoczna dopiero, gdy zrobisz porządny server-side z deduplikacją. Dopóki mierzysz tylko z przeglądarki, nie masz z czym porównywać. W momencie, w którym wdrażasz warstwę serwerową, Meta dostaje narzędzie do porównania browser kontra serwer - i każde browserowe zdarzenie bez Twojego event_id zaczyna świecić na czerwono. Dobry tracking niczego nie psuje. On ujawnia bałagan, który leżał tam wcześniej. To jest wykrywacz kłamstw.

Objaw: 14% pokrycia mimo czystego stacku

Konkretny sklep Shoper, po wdrożeniu warstwy serwerowej:

  • Serwer: 100% zamówień opłaconych online wychodzi z backendu do API konwersji, każde z event_id w formacie purchase_<numer_zamówienia>.
  • Przeglądarka, Twój tag: Purchase z tym samym event_id, z prawdziwymi ID produktów, wartością i pełnym zaawansowanym dopasowaniem.
  • Deduplikacja: spięta, event_id po obu stronach identyczne.

Wszystko, co napisałeś, jest poprawne. A pokrycie Purchase: 14% przy celu 75%. Skoro serwer wysyła komplet, znaczy to jedno: piksel wysyła znacznie więcej, niż powinien. Na zamówienie lecą dwa browserowe Purchase - Twój czysty i drugi, obcy.

Ślepe zaułki i dlaczego je pokazuję

Zanim trafiłem w prawdziwe źródło, sprawdziłem trzy rzeczy, które się NIE potwierdziły. Pokazuję je, bo to jest realna diagnostyka, nie scenariusz po fakcie:

  • Zewnętrzna aplikacja Shopera. Sklep miał zainstalowaną apkę dociągającą kod ze swojego serwera. Idealny podejrzany. Klient ją usunął - nie pomogło. Endpoint zwracał zresztą pustą odpowiedź, co, w tył patrząc, było sygnałem, że nic nie wstrzykuje.
  • Przełączniki piksela w ustawieniach Mety. „Automatyczne wykrywanie zdarzeń bez kodu” było już wyłączone. Funkcja AI dosyłająca dane ze strony - wyłączona. Bez zmian.
  • Założenie „to obcy kod w pliku”. Przejrzane co do linijki: osiem plików motywu, oba kontenery GTM, każda apka. Zero obcego fbq Purchase.

Morał z tej części: nie ufaj eliminacji. Wskazanie winowajcy metodą „co zostaje po wykluczeniu” dwa razy wprowadziło mnie w maliny. Przełom przyszedł, gdy zamiast zgadywać, spojrzałem na faktyczny request sieciowy.

Prawdziwy sprawca: codeless events samej Mety

W Pixel Helperze, przy tym obcym Purchase, otworzyłem „Wywołany adres URL” - czyli dosłowny request do facebook.com/tr. I on zdradził wszystko:

...&ev=Purchase
&cd[content_ids]=["238875","238875"]
&cd[cs_est]=true
&es=automatic
&est_source=360XXXXXXXXXXXX

es=automatic to nie nasz kod. To Meta sama generuje to zdarzenie. Mechanizm: Event Setup Tool (narzędzie do konfiguracji zdarzeń bez kodu). Ktoś dawno temu kliknięciem skonfigurował tam regułę: „gdy URL pasuje do /basket/done, odpal Purchase”. Meta zapisała ją po swojej stronie i renderuje przy każdym wejściu na stronę podziękowania:

  • content_ids to numer zamówienia zeskrobany z URL (zdublowany), nie ID produktów
  • value zeskrobane ze strony
  • brak event_id - bo to nie Twój kod, więc nie ma jak zdedupować

To dlatego tego nie ma w żadnym pliku sklepu. Tej reguły nie ma w motywie ani w GTM - ona żyje na serwerach Mety, przypięta do piksela. A piksel okazał się starszy niż obecny sklep - utworzony lata temu, na poprzedniej platformie. Reguła przeleżała od tamtej epoki, niewidoczna, aż czysty dedup ją wytropił.

Dlaczego akurat sklepy na Shoperze obrastają takimi warstwami

Tu wchodzi nisza. Piksel sklepu Shoper, który żyje od kilku lat, obrasta integracjami jak dno łodzi pąklami. Każdy produkt i partner, który kiedykolwiek go dotknął, zostawia warstwę:

  • reguły Event Setup Tool z dawnych konfiguracji
  • piksel i katalog podpięte przez reklamowy produkt platformy (jego strona Meta i osobno strona Google)
  • partnerskie konektory analityczne wstrzykiwane przez platformę
  • stare połączenia typu Facebook Business Extension
  • martwe granty narzędzi server-side (np. CAPI Gateway), które nadal mają dostęp do piksela

Żadna z tych warstw nie zna Twoich kluczy deduplikacji. Każda strzela na Twój piksel po swojemu. Dopóki nie masz czystego server-side, wszystkie po cichu się sumują i nikt nie patrzy. Architekturę, która robi to porządnie od podstaw na Shoperze, rozpisałem w kompletnym przewodniku server-side GTM na Shoper, a pakiet pod ten zamknięty front opisuje strona trackingu dla Shoper.

Drugi front: podwójny funnel od partnerskiego konektora

Przy okazji wyszło drugie dno. Funnel (ViewContent, AddToCart) też dublował się dwa razy - ale to już były czyste zdarzenia, z prawdziwymi produktami. Tag Assistant pokazał, że ten sam add_to_cart trafia do dataLayer dwukrotnie, z dwóch źródeł:

  • manualna wtyczka GA4 (z opcją „Przesyłaj przez GTM”)
  • partnerski konektor GA4 wstrzykiwany przez platformę - rozpoznasz go po tagach oznaczonych jako „product-owned”, czyli należących do platformy, nie do Ciebie, i poza Twoim kontenerem

Dwa pushe tego samego eventu - nasze Custom Event triggery łapią go dwa razy - tag Meta i GA4 odpalają się podwójnie. Fix: zostawić jedno źródło dataLayer. Po wyłączeniu zbędnej wtyczki funnel zszedł do pojedynczego strzału, a partnerski konektor został jako jedyne źródło.

Jak namierzyć to u siebie

Jeśli masz czysty stack i niskie pokrycie, idź po dowody, nie po przeczucia:

  1. Events Manager, zdarzenie Purchase, zakładka Deduplikacja. Zobacz, ile browserowych Purchase ma event_id. Niski procent po stronie przeglądarki to czerwona flaga - bo Twój tag zawsze go ustawia.
  2. Eksport aktywności Purchase do CSV. Szukasz drugiej sygnatury: content_ids ustawione na numer zamówienia, brak wartości, brak event_id, nietypowy parametr typu cs_est.
  3. Pixel Helper, „Wywołany adres URL”. Jeśli w requeście jest es=automatic i cs_est=true - to Meta dorabia zdarzenie sama, z reguły Event Setup Tool.
  4. Tag Assistant na karcie produktu - policz, ile razy odpala się ViewContent i AddToCart. Dwa to duplikat.
  5. Profil firmowy Meta. Przejrzyj, jakie aplikacje mają dostęp do piksela. Stare granty reklamowych produktów i bramek server-side potrafią tam leżeć latami.

Mechanikę inspekcji tagów rozpisałem szerzej w tekście o debugowaniu GTM dla e-commerce.

Jak to wyciąć

Sęk w tym, że części tego nie wyłączysz w pliku - bo to nie plik. Realne dźwignie:

Codeless Purchase od Mety. Najmocniejszy ruch jest po stronie przeglądarki - powiedz pikselowi, żeby nie pobierał automatycznej konfiguracji:

fbq('set', 'autoConfig', false, 'TWOJ_PIXEL_ID');
fbq('init', 'TWOJ_PIXEL_ID');

autoConfig: false wyłącza całą automatykę piksela (reguły Event Setup Tool, wykrywanie kliknięć, automatyczne dopasowanie) i nie rusza Twoich jawnych fbq('track', ...). Tracisz śmieci, zostają prawdziwe zdarzenia z event_id. Wstaw to przed każdym init piksela na stronie.

Warstwy platformy i partnerów. Stary reklamowy produkt platformy (strona Meta i Google), partnerski konektor GA4, martwe granty apek - to odłączasz w panelu sklepu i w profilu firmowym Meta. Cel: jedno źródło danych dla każdego systemu.

I jedna rzecz, o której trzeba uprzedzić właściciela sklepu: pokrycie w panelu nie skoczy od razu. Konfiguracja piksela siedzi też w cache Mety, propagacja to godziny. Naprawa jest natychmiastowa, liczba w panelu tylko goni rzeczywistość.

Najtrudniejszy do znalezienia bug to nie ten, który rzuca błędem. To ten, którego kod nie istnieje w żadnym pliku, do którego masz dostęp, i który „działał” tak długo, że nikt go nie podejrzewa.

Podsumowanie

Ukryty duplikat Purchase wygląda na niemożliwy: stack czysty w każdym pliku, a metryka i tak na czerwono. Sęk w tym, że piksel sklepu Shoper żyjący od lat to wykopalisko archeologiczne - warstwa po warstwie integracji, których nikt nie napisał w kodzie i nikt nie posprzątał. Reguły Event Setup Tool, partnerskie konektory, granty produktów reklamowych - każda strzela bez Twoich kluczy deduplikacji.

Morał jest dwuczęściowy. Po pierwsze: porządny server-side z deduplikacją to nie tylko lepszy pomiar - to jedyny sposób, żeby w ogóle zobaczyć te zaszłości. Po drugie: gdy pokrycie nie domyka się mimo czystego kodu, nie szukaj błędu w swoim kodzie. Szukaj kodu, którego w Twoim kodzie nie ma - w requeście sieciowym, w ustawieniach piksela, w profilu firmowym Meta.

Rozplątanie takiego zaśmieconego piksela na Shoperze to standardowy element audytu i czyszczenia trackingu - jeśli Twoje pokrycie nie domyka się mimo poprawnego wdrożenia, zobacz zakres usług.

Porozmawiajmy o Twoim trackingu

30 minut bez zobowiązań. Bez sesji sprzedażowej. Powiem czy mogę pomóc i co realnie da się odzyskać.