Case study: server-side tracking na Shoperze - od gubionych zakupów BLIK do pełnego pomiaru w tydzień
Sklep na Shoperze z płatnym ruchem. Pomiar, który gubił zakupy opłacane BLIK-iem. Historia wdrożenia server-side: architektura, trzy awarie po drodze i twarde liczby na końcu.
Sklep na Shoperze z regularnym płatnym ruchem w Meta Ads. Kilkaset zamówień miesięcznie, budżet reklamowy na poziomie, przy którym każdy procent błędu pomiaru to realne pieniądze wydawane na ślepo.
Problem, z którym przyszedł właściciel, brzmiał prosto: Meta nie widzi części zakupów. Diagnostyka piksela pokazywała pokrycie zdarzeń na poziomie 33-43%, czyli większość zakupów widzianych przez przeglądarkę nie miała potwierdzenia po stronie serwera. Algorytm optymalizował kampanie na takim materiale.
To jest pełna historia tego wdrożenia: co zastałem w audycie, jaką architekturę postawiłem, co poszło nie tak po drodze (trzy razy) i jakie liczby zostały na końcu. Z prawdziwymi ślepymi zaułkami, bo wdrożenie bez nich to laurka, a nie case study.
Punkt wyjścia: czemu piksel gubił zakupy
Audyt przed wdrożeniem pokazał klasyczny obraz sklepu, który przez lata zbierał warstwy integracji:
- Pomiar Meta przez wbudowaną integrację Shopera (FBE2) - browserowy Purchase odpalał się na stronie podziękowania. Problem: przy płatności BLIK-iem albo przelewie z redirectem część klientów nigdy na tę stronę nie wraca. Zakup jest, zdarzenia nie ma. To ten sam mechanizm, który opisałem przy gubionych konwersjach GA4 przez redirect bramek płatności - tutaj zjadał Purchase Mety.
- Dwa równoległe strumienie GA4 dublujące zdarzenia.
- Piksel z wieloletnią historią - z konfiguracją po stronie Mety, której nie widać w żadnym pliku sklepu (do tego wrócimy, bo to ona zdetonowała się po wdrożeniu).
- Baner zgód Shopera de facto niedziałający - luka RODO przy sklepie, który codziennie wydaje na reklamę.
- Inwentarz obcych trackerów zbierających dane obok oficjalnego stacku.
Wniosek z audytu: poprawianie browserowego piksela nic nie da. Źródłem prawdy o zakupie musi być backend sklepu, nie przeglądarka klienta.
Architektura: backend jako źródło prawdy
Wdrożenie oparłem o trzy elementy, każdy na koncie klienta, nie moim:
- Server-side GTM na subdomenie first-party sklepu (kontener serwerowy + web, hosting sGTM w regionie EU). Jak to działa od środka, opisałem w kompletnym przewodniku po server-side GTM na Shoperze.
- Webhook
order.paidz Shopera do warstwy pośredniej, która waliduje podpis HMAC, pilnuje idempotencji (jedno zamówienie = jedno zdarzenie, niezależnie od powtórek webhooka) i wzbogaca zdarzenie o dane zamówienia z Shoper REST API: e-mail, telefon, imię, nazwisko, adres. Stamtąd Purchase leci do Meta CAPI przez kontener serwerowy. - Consent Mode v2 z certyfikowanym CMP w miejsce zepsutego banera - domyślnie denied, tagi odpalają się dopiero po zgodzie.
Kluczowa właściwość tej architektury: backendowy Purchase odpala się w momencie opłacenia zamówienia, a nie w momencie powrotu klienta na stronę podziękowania. BLIK bez powrotu na stronę podziękowania, przelew z porzuconym redirectem, zamknięta karta - wszystko jedno, zdarzenie i tak wychodzi.
Browserowy piksel zostaje, ale w nowej roli: dostarcza sygnały przeglądarkowe (fbp, fbc) i funnel (ViewContent, AddToCart, InitiateCheckout), a z serwerowym Purchase łączy się po wspólnym event_id w formacie purchase_<numer_zamówienia>. Identyfikatory przeglądarkowe przechwytuje lekki beacon na stronie podziękowania i dokleja je do backendowego zdarzenia przy order.paid. Dzięki temu wyłączenie FBE2 nie obniżyło jakości dopasowania - serwerowy Purchase wychodzi z kompletem 12 kluczy danych użytkownika. Dlaczego CAPI bez tej pary identyfikatorów traci na wartości, opisałem w tekście o Meta CAPI na Shoperze bez wtyczek.
Awaria pierwsza: duch piksela sprzed lat
Tydzień po starcie pomiar wyglądał na czysty: dedup spięty, wartości zgodne z panelem zamówień. A Events Manager pokazywał pokrycie Purchase 14% przy celu 75%.
Krótka wersja śledztwa: na każde zamówienie do Mety leciały dwa browserowe Purchase, a drugiego nie było w żadnym pliku sklepu ani w GTM. Generowała go sama Meta - z konfiguracji narzędzia Event Setup Tool zapiętej na pikselu lata wcześniej, jeszcze na poprzedniej platformie sklepu. Zdarzenie bez event_id, więc bez szans na deduplikację.
Po drodze były ślepe zaułki: podejrzana aplikacja zewnętrzna (niewinna), przełączniki piksela w panelu (nieskuteczne). Przełom przyszedł z dowodu sieciowego, nie z eliminacji. Fix: wyłączenie automatycznej konfiguracji piksela u źródła, w obu miejscach inicjalizacji. Pełną historię tego śledztwa, z requestem sieciowym i sposobem namierzenia tego u siebie, rozpisałem w tekście o ukrytym duplikacie Purchase, którego nie ma w żadnym pliku sklepu.
Lekcja, która wraca w każdym audycie: dobry server-side niczego nie psuje, on ujawnia bałagan, który leżał w koncie latami. Dopóki mierzysz tylko z przeglądarki, nie masz z czym porównać. Deduplikacja robi z pokrycia zdarzeń wykrywacz kłamstw.
Awaria druga: platformowa bramka zgód uśmierciła funnel
Najciekawszy przypadek z całego wdrożenia. Po przejściu na własny CMP baner Shopera został ukryty - i funnel browserowy (ViewContent, AddToCart, InitiateCheckout) umarł dla nowych użytkowników, czyli dla 99% ruchu.
Mechanizm: Shoper bramkuje swoje partnerskie integracje własnym, platformowym consentem. Ukryty baner = brak platformowej zgody = wtyczka, która pushowała zdarzenia e-commerce do dataLayer, milczy. Strata rzędu 55-65% sygnału AddToCart, udowodniona empirycznie testem z podmianą konfiguracji w locie.
Doraźny fix był w kontenerach, ale docelowe rozwiązanie poszło głębiej: własna warstwa dataLayer wpisana bezpośrednio w szablony motywu - pięć zdarzeń e-commerce, z AddToCart odtwarzanym przez sessionStorage tam, gdzie Shoper robi przeładowanie strony. Funnel przestał zależeć od wtyczek, partnerskich konektorów i platformowych zgód Shopera. To zresztą ta sama klasa problemu, co natywna wtyczka GA4 na Shoper RWD i jej dataLayer - warstwa danych, nad którą nie masz kontroli, w końcu się pod Tobą zawali.
Awaria trzecia: wieczorny publish nadpisał beacon
Najbardziej prozaiczna z trzech, ale poszkodowała najszybciej: publikacja zmian w sklepie nadpisała slot ze skryptem przechwytującym fbp/fbc na stronie podziękowania. Przez cały dzień żadne zamówienie nie miało doklejonych identyfikatorów przeglądarkowych - jakość dopasowania tych zdarzeń przepadła.
Wykryło to dopiero porównanie danych dzień po dniu w audycie pokrycia. Fix: ponowne wklejenie slotu w wersji odpornej na łamanie długich linii przez edytor Shopera, weryfikacja end-to-end. Lekcja: po każdej publikacji zmian w motywie sprawdzaj sloty z kodem pomiarowym - edytor Shopera potrafi po cichu zepsuć długie linie JavaScriptu.
Pułapka interpretacji: pokrycie 27% to nie był bug
Osobny wątek, który mógł skończyć się tygodniem niepotrzebnego debugowania. Kilka dni po naprawach Events Manager pokazywał pokrycie 27% - daleko od celu. Panika? Nie: Meta liczy pokrycie w oknie 7 dni wstecz, a serwerowa warstwa łapała zdarzenia dopiero od kilku dni. Stare browserowe Purchase bez pary serwerowej wciąż siedziały w oknie i zaniżały wynik.
Model trajektorii przewidział na ten dzień pasmo 24,6-28,4% - obserwacja trafiła w środek. Ustawiłem linię decyzyjną (jeśli do konkretnej daty pokrycie nie przekroczy 50-55%, to realny bug) i wynik sam dorósł do sufitu.
No właśnie, sufit: w tym sklepie 22% zamówień to pobranie, którego klient nie opłaca online, więc strukturalny maksymalny poziom pokrycia to około 78%. Warto to wiedzieć przed wdrożeniem, bo inaczej goni się brakujące 22 punkty procentowe, których nie ma skąd wziąć.
Wyniki: co pokazał audyt końcowy
Audyt zamykający (świeży profil przeglądarki, dekodowanie opublikowanych kontenerów, przegląd kodu i bazy warstwy pośredniej, triangulacja z Shoper REST API):
- Wszystkie opłacone zamówienia z okresu po starcie przekazane do Meta CAPI, co do sztuki - 100% skuteczności warstwy serwerowej, zweryfikowane przez porównanie z zapleczem sklepu.
- Deduplikacja 100% na realnych zakupach: browser i serwer z tym samym
event_id. - Komplet 12 kluczy danych użytkownika w serwerowym Purchase (e-mail, telefon, imię, nazwisko, adres, identyfikatory przeglądarkowe, IP).
- Pokrycie zdarzeń przy strukturalnym suficie ~78% wynikającym z udziału pobrania - zamiast 33-43% z fałszywych powodów na starcie.
- Funnel niezależny od platformy: własny dataLayer w motywie, odporny na zmiany wtyczek i zgód Shopera.
- Consent Mode v2 działa - default denied, tagi gated, luka RODO zamknięta.
Po drodze audyt wyłapał też rzeczy spoza pierwotnego zakresu, m.in. plaintext token API w publicznie dostępnym eksporcie kontenera (rotacja od ręki) i dziurę atrybucji w GA4: gros sesji z płatnych kampanii Meta raportowanych jako zwykły referral, bo reklamy nie miały UTM-ów. To już materiał na osobny etap pracy - tracking Mety naprawiony, raporty kanałów w GA4 to kolejna warstwa.
Co z tego wynika dla Twojego sklepu
Trzy wnioski, które przenoszą się na każdy sklep na Shoperze z płatnym ruchem:
- Jeśli przyjmujesz BLIK lub płatności z redirectem, Twój browserowy Purchase gubi zamówienia. Nie “może gubić” - gubi, pytanie tylko ile. Jedyne trwałe wyjście to zdarzenie z backendu, odpalane przy opłaceniu zamówienia.
- Wdrożenie server-side ujawni stare grzechy konta. Piksel z historią, partnerskie integracje, automatyczne konfiguracje po stronie Mety - to wszystko wychodzi dopiero, gdy pojawia się serwerowy punkt odniesienia. Zaplanuj na to czas w projekcie, zamiast traktować jak awarię wdrożenia.
- Pokrycie zdarzeń czytaj ze zrozumieniem okna pomiarowego i miksu płatności. Bez tego albo wpadniesz w panikę przy zdrowym pomiarze, albo będziesz gonić sufit, którego nie da się przebić.
Całe wdrożenie - od audytu, przez architekturę, trzy awarie i audyt końcowy - zamknęło się w tygodniu. Szczegóły pakietu i zakres takiej pracy znajdziesz na stronie trackingu dla Shopera.
Podsumowanie
Sklep wszedł z pomiarem, w którym większość zdarzeń zakupu nie domykała się między przeglądarką a serwerem, i optymalizował kampanie na dziurawych danych. Wyszedł z architekturą, w której źródłem prawdy o zakupie jest backend: 100% opłaconych zamówień w Meta CAPI, pełna deduplikacja, komplet danych dopasowania, funnel niezależny od wtyczek platformy i domknięta warstwa zgód.
Najważniejsza obserwacja z całego projektu nie dotyczy jednak architektury, tylko procesu: żadna z trzech awarii po drodze nie była winą warstwy serwerowej. Wszystkie trzy były starym bałaganem (ukrytą konfiguracją Mety, platformową bramką zgód, kruchym edytorem motywu), który dopiero czysty pomiar zrobił widocznym. Server-side nie jest magicznym przełącznikiem. Jest punktem odniesienia, bez którego nie wiesz nawet, ile tracisz.