GA4 pokazuje co innego niż sklep?Optymalizacja PrestaShop
← Blog
E-commerce

Audyt GA4 i GTM w sklepie: zdublowany purchase, zgoda i cache

Zakup trafiał do GA4 z trzech miejsc, baner zgody blokował Clarity, UET i remarketing, a stary kontener GTM wisiał w cache miesiąc. Co znaleźliśmy w audycie i co zmieniliśmy.

Audyt GA4 i GTM w sklepie internetowym zaczyna się od pytania, ile źródeł wysyła zdarzenie purchase i czy wszystkie tagi w ogóle mają szansę odpalić. W sklepie na PrestaShop, który przejęliśmy jako zewnętrzny dział IT, zakup trafiał do GA4 z trzech miejsc, baner zgody po cichu blokował część tagów, a Cloudflare trzymał stary kontener GTM nawet przez 31 dni. Poniżej opisujemy, jak to znaleźliśmy, co zmieniliśmy i dlaczego dziwne zdarzenia przypominające SQL injection okazały się ruchem skanera, a nie dziurą w sklepie.

Po czym poznać, że analityka sklepu wymaga audytu?

Właściciel zwykle widzi objaw, nie przyczynę. Liczba zamówień w GA4 nie zgadza się z panelem sklepu, kampania w Google Ads raportuje inną wartość niż analityka, a w raporcie zdarzeń pojawiają się nazwy, których nikt nie tworzył. Tak było i tutaj.

Zebraliśmy listę sygnałów, które w tym projekcie miały konkretną przyczynę:

  • w raporcie zdarzeń GA4 nazwy wyglądające jak fragmenty zapytań SQL,
  • Microsoft Clarity, Bing UET i remarketing Google Ads bez danych mimo zgody użytkowników,
  • zmiany opublikowane w GTM widoczne u części odwiedzających dopiero po tygodniach,
  • martwy hit Universal Analytics, który ładował bibliotekę analytics.js na każdej stronie,
  • słaby wynik PageSpeed na karcie produktu, w którym duży udział miały skrypty Google.

Dlaczego GA4 liczy zakupy podwójnie?

Bo kilka mechanizmów wysyła to samo zdarzenie. W tym sklepie purchase pochodził z trzech źródeł: modułu GTM, drugiego modułu analitycznego oraz osobnego skryptu, który wysyłał dane zamówienia przez AJAX. Drugi moduł wysyłał zdarzenie przy każdym odświeżeniu strony podziękowania, bo nie zapamiętywał, że zamówienie zostało już zgłoszone. Moduł GTM miał deduplikację w bazie, ale z włączonym ponownym wysyłaniem przez 7 dni. W kontenerze tag GA4 purchase był podpięty pod dwa różne triggery.

Zanim cokolwiek usunęliśmy, policzyliśmy skalę. GA4 skleja zakupy o tym samym transaction_id, więc w raportach duplikaty stanowiły 1,4%. To niewiele, ale Google Ads i tagi remarketingowe nie zawsze stosują tę samą deduplikację, a trzy źródła oznaczają trzy miejsca, w których coś może się rozjechać przy aktualizacji modułu.

Zrobiliśmy dwie zmiany. Do szablonu drugiego modułu dodaliśmy zabezpieczenie oparte na cookie, takie samo, jakiego używa moduł płatności na swojej stronie potwierdzenia. W GTM tag purchase został podpięty pod jeden trigger.

Co pokazało zamówienie testowe?

Konfiguracja wyglądała poprawnie, więc złożyliśmy prawdziwe zamówienie z płatnością przelewem i obserwowaliśmy je w Tag Assistant. Zdarzenia begin_checkout i kroki checkoutu przeszły, ale na stronie podziękowania purchase się nie pojawił.

Przyczyna siedziała w nadpisanym kontrolerze potwierdzenia zamówienia. Wywoływał on hook potwierdzenia dwa razy, a za drugim razem wynik drugiego modułu ginął. Ten błąd istniał od dawna i był niewidoczny, bo zakupy opłacone przelewem, za pobraniem i na raty i tak docierały do GA4 przez trigger modułu GTM. Po poprawce override'u Tag Assistant pokazał na purchase tagi GA4, Google Ads i Bing UET.

Drugi test, z płatnością online przez bramkę płatniczą, pokazał, że po powrocie z bramki zdarzenie wysyła wyłącznie moduł GTM. Dlatego jego trigger został w kontenerze na stałe jako zabezpieczenie. Wniosek dla każdego sklepu: deduplikację trzeba sprawdzić osobno dla każdej metody płatności, bo każda kończy się inną ścieżką.

Czy zdarzenia z SQL injection w GA4 to atak na sklep?

W tym przypadku nie. Pierwsza hipoteza zakładała, że moduł GTM wpisuje surowy parametr controller z adresu URL do zmiennych dataLayer, więc spreparowany link trafia do GA4 jako nazwa kategorii strony. Parametr i tak oczyściliśmy w jednym miejscu modułu, bo to tania higiena. Dalsza analiza pokazała jednak, że dziwne nazwy zdarzeń nie przechodziły przez sklep.

GA4 przyjmuje dane na publicznym adresie zbierającym /g/collect. Identyfikator pomiaru jest widoczny w kodzie każdej strony, a Google nie wymaga przy tym żadnego uwierzytelnienia. Skaner podatności, który testuje wszystko, co widzi na stronie, wysłał więc żądania z payloadami SQL prosto do Google. W raportach wyglądało to groźnie, ale baza sklepu nie wykonała ani jednego z tych zapytań.

Jak to odróżnić od prawdziwego problemu:

  • sprawdź, czy podejrzane wartości pojawiają się w logach serwera sklepu, czy tylko w GA4,
  • przejrzyj dataLayer i zobacz, czy którakolwiek zmienna przepisuje parametry URL bez filtrowania,
  • jeśli zdarzenia nie mają odpowiednika w ruchu na serwerze, to śmieci w analityce, a nie włamanie.

Takie wpisy wystarczy odfiltrować w raportach. Reakcja na incydent nie jest potrzebna.

Dlaczego baner CookieYes blokował tagi mimo zgody?

CookieYes działał w trybie defer, czyli ładował się po kontenerze GTM. Aktualizacja zgody przychodziła więc w momencie, gdy GTM już zdecydował, które tagi odpalić. GTM nie uruchamia wstecz tagów zablokowanych na starcie strony.

Skutek: tagi z dodatkowym warunkiem zgody, czyli Clarity, Bing UET i remarketing Google Ads, były blokowane u wszystkich użytkowników, również tych, którzy wcześniej zaakceptowali cookies. Bing UET nie zbierał danych od dnia wprowadzenia trybu zgody w kontenerze.

Poprawka polegała na tym, żeby w nagłówku strony, jeszcze przed GTM, odczytać zapisane cookie zgody i na jego podstawie ustawić consent default. Powracający użytkownik, który kiedyś kliknął „akceptuj”, ma wtedy właściwy stan zgody, zanim GTM zdąży zdecydować o pierwszym tagu, więc nic nie czeka na baner. Po wdrożeniu Tag Assistant pokazał przy Clarity, UET i remarketingu dynamicznym status „Powodzenie”.

Jak Cloudflare może cache'ować kontener GTM przez miesiąc?

Kontener ładował się przez Google Tag Gateway z domeny sklepu. Na tej ścieżce działała reguła Cloudflare „Cache Everything”, która nadpisywała nagłówek cache-control. Google ustawia dla kontenera 900 sekund, a Cloudflare zmieniał to na 31 dni i trzymał plik na serwerach brzegowych. Powracający klient mógł więc dostawać starą wersję kontenera nawet przez miesiąc po publikacji.

Wykluczyliśmy ścieżkę bramy z reguły cache. Odpowiedź ma teraz status BYPASS i max-age=900, czyli tyle, ile przewiduje Google.

Przy okazji okazało się, że kontener był pobierany dwa razy: raz przez auto-inject Cloudflare, raz przez własny loader w szablonie. Zdarzenia się nie dublowały, bo GTM inicjalizuje się tylko raz, ale każda strona płaciła za to 176 KB transferu i około 100 ms pracy procesora przed LCP. Własny loader usunęliśmy i zostawiliśmy wstrzykiwanie przez Cloudflare. Ma to swoją cenę: działanie GTM zależy teraz od ustawienia w panelu Cloudflare, co zapisaliśmy w dokumentacji sklepu.

Co jeszcze poprawiliśmy w kontenerze?

Co zastaliśmyCo zmieniliśmy
Martwy gtag config Universal Analytics w szablonie modułuUsunięta linia, analytics.js zniknął ze wszystkich stron
Skrypt motywu dołączony dwa razy, przez co add_to_cart wysyłał się wielokrotnieJeden include, jedno zdarzenie w GA4
remove_from_cart nie wysyłał się przy przycisku „Usuń”Push do dataLayer przed przeładowaniem koszyka
Tag remarketingu z parametrem items zdefiniowanym 6 razy, wygrywał ostatni, nazwa zdarzenia pustaTag przepisany, 6 triggerów zamiast 14, items w formacie oczekiwanym przez Google Ads
Wyszukiwarka w nakładce zapisywała frazę w adresie, event search nie powstawałEvent search z nasłuchu zmiany adresu, w GA4 Realtime widać go od razu
Key events w GA4 odznaczonePrzywrócone 4, żeby agencja mogła je importować do Ads

Każda zmiana w GTM szła jako nowa wersja kontenera, a przed pierwszą zrobiliśmy kopię wersji wyjściowej. Powrót do stanu sprzed audytu to jedno kliknięcie w historii wersji, a w sklepie odtworzenie plików z kopii.

Jak porządek w GTM wpłynął na PageSpeed?

Wynik PageSpeed Insights na mobile dla karty produktu wyraźnie wzrósł. Złożyło się na to kilka zmian naraz: loader GTM przez bramę first-party, Clarity i UET uruchamiane później, inline JavaScript przeniesiony do osobnego pliku z defer i poprawki LCP. Sama analityka nie odpowiada za cały wzrost.

PSI ma też dużą zmienność. W kolejnych przebiegach ta sama karta produktu dostawała wyniki różniące się o ponad 10 punktów, a pomiary uruchamiane równolegle wypadały gorzej. Dlatego w raportach dla klientów podajemy zakres, a nie jedną liczbę.

Na co uważać przy testach w Tag Assistant?

  • Tag Assistant przypina wersję kontenera z chwili połączenia i wymusza ją we wszystkich kartach domeny. Po testach zamknij sesję.
  • Zamówienie testowe trzeba potem anulować w panelu, żeby nie trafiło do raportów sprzedaży.
  • Przekierowanie kategorii potrafi zgubić parametr omijający cache i pokazać starą wersję strony z Cloudflare.
  • Każdą metodę płatności testujesz osobno, bo każda kończy się inną stroną.

Jak robimy audyt GA4 i GTM w ASAPDevs?

Zaczynamy od kopii kontenera i plików sklepu, potem spisujemy wszystkie źródła zdarzeń, a dopiero na końcu cokolwiek wyłączamy. Każdą poprawkę sprawdzamy na żywym zamówieniu w Tag Assistant i w GA4 Realtime. Pracujemy na PrestaShop i WooCommerce, a analitykę traktujemy jako część utrzymania sklepu, nie osobny projekt.

Liczby w GA4 nie zgadzają się z zamówieniami w panelu? Opisz, jakich modułów i bramek płatności używasz. Zobacz optymalizację PrestaShop → albo optymalizację WooCommerce →

Źródła: Google, Consent mode w Tag Managerze; Google, Measurement Protocol GA4; Cloudflare, Cache Rules.
Kamil Perzowski
Kamil Perzowski
CEO i co-founder ASAPDevs. Programuje i utrzymuje sklepy, aplikacje webowe i serwery klientów. LinkedIn · Optymalizacja PrestaShop
Masz ten sam problem?

GA4 pokazuje co innego niż sklep?

Kamil Perzowski, ASAPDevs
Kamil Perzowski
CEO & Co-founder, ASAPDevs
Sprawdzimy, skąd lecą zdarzenia purchase, co blokuje baner zgody i ile kosztuje kontener GTM w PageSpeed. Każdą zmianę testujemy na prawdziwym zamówieniu.

Wysyłając formularz, przekazujesz nam dane, żebyśmy mogli odpowiedzieć. Szczegóły w polityce prywatności.

FAQ

Pytania i odpowiedzi

Skąd biorą się zdublowane transakcje purchase w GA4?

+
Najczęściej z kilku źródeł wysyłających to samo zdarzenie: moduł GTM, drugi moduł analityczny i własny skrypt na stronie podziękowania. Drugi typowy powód to brak zabezpieczenia przed odświeżeniem strony potwierdzenia zamówienia, po którym zdarzenie leci ponownie.

Czy GA4 sam usuwa duplikaty zakupów?

+
GA4 skleja zakupy z tym samym transaction_id, więc część dubli znika w raportach. W sklepie, który audytowaliśmy, mimo trzech źródeł purchase duplikaty stanowiły 1,4%. Nie zwalnia to z porządku, bo Google Ads i remarketing mogą liczyć konwersję inaczej niż raport GA4.

Czy zdarzenia z SQL injection w GA4 oznaczają, że sklep został zhakowany?

+
Nie muszą. Identyfikator pomiaru GA4 jest jawny w kodzie strony, więc każdy skaner może wysyłać żądania bezpośrednio do Google z dowolną nazwą zdarzenia. Takie wpisy pokazują, że ktoś testuje formularze i parametry, a nie że baza sklepu wykonała zapytanie.

Dlaczego tagi wymagające zgody na cookies nie odpalają, choć użytkownik kliknął akceptuj?

+
Jeśli baner zgody ładuje się z opóźnieniem i aktualizuje zgodę dopiero po starcie kontenera, GTM nie uruchamia wstecz tagów, które już raz zostały zablokowane. Rozwiązaniem jest ustawienie domyślnego stanu zgody z zapisanego cookie, zanim załaduje się kontener.

Ile trwa audyt GA4 i GTM w sklepie?

+
Diagnoza i pierwsze poprawki w opisanym sklepie zajęły nam dwa dni pracy, z zamówieniami testowymi włącznie. Czas zależy od liczby modułów analitycznych, metod płatności do przetestowania i tego, czy kontener GTM ma kopię zapasową, do której można wrócić.

Przeczytaj też