Po stronie dewelopera sprowadza się to do jednego: wdrożyć tracking tak, żeby dane były kompletne, dokładne i zgodne z GDPR. Brzmi banalnie, a właśnie tu najczęściej coś przecieka.
Jak działa Google Ads conversion tracking?
Zasada działania nie należy do skomplikowanych: użytkownik klika reklamę i trafia na Twoją stronę, a gdy wykona akcję, na której Ci zależy (np. zakup, formularz, rejestracja), wtedy gtag wysyła event konwersji z powrotem do Google Ads. Tam konwersja zostaje przypisana do konkretnej kampanii, reklamy i słowa kluczowego, dzięki czemu algorytm „rozumie", które kliknięcia przynoszą pieniądze, a które tylko je wydają.
Cała ta układanka opiera się na jednym parametrze, jakim jest (Google Click Identifier), doklejanym do URL po kliknięciu reklamy (?gclid=abc123). To on łączy kliknięcie z konwersją. Chodzi o to, żeby przechwycić go od razu po wejściu i zapisać tak, by przetrwał dalszą nawigację.
Warto wiedzieć, że gtag robi część tej roboty za Ciebie: z włączonym conversion linkerem zapisuje GCLID w first-party cookie _gcl_aw (w formacie GCL.<timestamp>.<gclid>). Dla czysto client-side'owego pomiaru to zwykle odpowiednie rozwiązanie. Ręcznego przechwycenia identyfikatora potrzebujesz wtedy (krok 4), gdy chcesz mieć GCLID we własnej bazie obok zamówienia i wysyłać konwersje server-side, a także, gdy adblocker zablokował sam skrypt gtag, ale parametru w URL już nie.
Dedykowany tag Google Ads czy import konwersji z GA4?
Zanim napiszesz linijkę kodu, podejmij jedną decyzję architektoniczną. Musisz zdecydować, skąd Google Ads ma brać konwersje. Są dwie drogi.
Import z jest atrakcyjny, ponieważ eventy purchase czy generate_lead często już istnieją i wystarczy połączyć konta, by zaimportować je jako konwersje. Jest jednak jeden haczyk: dane z GA4 docierają do Google Ads z opóźnieniem (zwykle liczonym w godzinach), przechodzą przez model atrybucji GA4 i nie wspierają pełnego zakresu funkcji dedykowanego tagu (wliczając enhanced conversions for web).
Dedykowany tag Google Ads, czyli ten, który wdrażamy w tym artykule. Wysyła konwersję bezpośrednio, niemalże w czasie rzeczywistym. Dla strategii automatycznego bidowania (tCPA, tROAS) świeżość sygnału ma znaczenie, ponieważ algorytm uczy się na bieżąco. Do tego dochodzą enhanced conversions i możliwość dosyłania konwersji przez API.
W praktyce rozsądny układ wygląda tak: kluczowe konwersje (zakup, lead) mierz dedykowanym tagiem Google Ads i ustaw je jako primary, a odpowiadające im eventy GA4 zostaw do analityki albo zaimportuj jako secondary — do obserwacji, nie do bidowania. Najgorszy scenariusz to obie ścieżki ustawione jako primary dla tej samej akcji: Google Ads policzy każdą konwersję dwa razy, a kampanie zaczną optymalizować się pod zawyżone liczby.
Krok 1: bazowy setup gtag dla Google Ads
Jeśli masz już GA4 gtag na stronie, nie ładuj gtag dwa razy. Dodaj Google Ads config do istniejącego gtag:
Żeby TypeScript nie protestował przy każdym window.gtag, dodaj deklarację globalną:
Krok 2: wysyłanie konwersji Google Ads
Konwersja zakupu purchase
Wysyłka konwersji na Thank You Page
Ważne: useRef zapobiega podwójnemu wysłaniu konwersji przy React strict mode (double mount w dev).
Krok 3: Enhanced Conversions w Google Ads
Enhanced conversions to mechanizm, który wysyła zahashowane dane użytkownika (email, telefon, adres) razem z konwersją. Google wykorzystuje je do lepszego dopasowania konwersji do interakcji reklamowych, szczególnie tam, gdzie klasyczny pomiar oparty o cookies ma luki.
Dlaczego Enhanced Conversions są ważne?
Safari i Firefox od lat ograniczają klasyczny tracking reklamowy, a adblockery i ustawienia prywatności dodatkowo komplikują pomiar. Enhanced conversions mogą poprawić kompletność danych, ale nie są gwarancją konkretnego upliftu. Traktuj je jako rozszerzenie pomiaru, nie jako automatyczny „booster” wyników.
Implementacja Enhanced Conversions
Samo gtag('set', 'user_data', ...) nie wystarczy — enhanced conversions musisz też włączyć w config (albo zaakceptować warunki i metodę w panelu Google Ads):
Przy wdrożeniu przez Google tag lub Google może wykonać hashing po swojej stronie zgodnie z wybraną metodą implementacji. Przy integracjach API lub importach offline zakres odpowiedzialności bywa inny, więc zawsze sprawdź, czy dana ścieżka oczekuje już danych zhashowanych.
Dwie rzeczy decydują o jakości dopasowania. Po pierwsze format danych: email znormalizowany do małych liter i bez spacji (robi to toLowerCase().trim() w kodzie wyżej), telefon w formacie E.164 z prefiksem kraju (+48123456789) — numer zapisany jako 123 456 789 nie zostanie dopasowany. Po drugie consent: przesyłanie danych użytkownika do Google dla ruchu z EEA/UK/CH wymaga zgody ad_user_data, o której więcej w kroku 5. Bez niej enhanced conversions dla tych użytkowników po prostu nie zadziałają — i słusznie.
Konfiguracja Enhanced Conversions w Google Ads
- Google Ads → Goals → Conversions → Settings
- Włącz "Enhanced conversions"
- Wybierz "Global site tag" jako metodę implementacji
- Zaznacz "Provide user-provided data through JavaScript variables"
Krok 4: server-side conversion tracking
Client-side tracking może być ograniczany przez adblockery, ustawienia prywatności albo utratę identyfikatorów po drodze. W Google Ads „server-side" najczęściej oznacza nie GA4 Measurement Protocol, tylko offline/upload click conversions przez Google Ads API.
Google Ads API i Offline Conversion Upload
Wartości accessToken i customerId nie pojawiają się znikąd i stanowią najtrudniejszą część implementacji po stronie serwera. accessToken generujesz z tokena odświeżającego OAuth2 (zazwyczaj za pomocą oficjalnej biblioteki google-ads-api/google-ads-node, która automatycznie odświeża token), natomiast customerId to identyfikator konta Google Ads, pozbawiony myślników. Obie te wartości przechowujesz w zmiennych środowiskowych po stronie serwera, nigdy w kodzie klienta.
Trzy pola w tym payloadzie mają niuanse, które łatwo przeoczyć:
orderId. Ustaw go na to samo, cotransaction_idw konwersji z gtag. To warunek, żeby Google Ads potraktował client-side event i server-side upload jako jedną konwersję, a nie dwie.conversionDateTime. To moment konwersji (złożenia zamówienia), nie moment przechwycenia GCLID. Musi być późniejszy niż samo kliknięcie reklamy i wymaga jawnej strefy czasowej (+01:00). Upload musi też zmieścić się w oknie konwersji danej akcji — kliknięć starszych niż skonfigurowane okno (maksymalnie 90 dni) nie ma sensu dosyłać.partialFailure: true. Sprawia, że błędne konwersje w batchu nie wywracają całego requestu. Ale to oznacza, że response ze statusem 200 nie gwarantuje sukcesu: błędy siedzą w polupartialFailureError, które trzeba sprawdzić i zalogować.
Zapisywanie GCLID po stronie aplikacji
Żeby wysłać offline conversion, musisz zapisać GCLID z URL przy pierwszej wizycie:
Pamiętaj, że zapis identyfikatora kliknięcia w cookie czy localStorage to też przechowywanie danych na urządzeniu użytkownika — w regionach objętych wymogiem zgody hook powinien respektować ten sam stan consentu co gtag (ad_storage), a nie działać bezwarunkowo.
Hook tylko zapisuje identyfikator. Brakującym ogniwem jest odczyt zapisanego GCLID przy konwersji i wysłanie go server-side — to ono domyka lukę w danych:
Fallback z _gcl_aw domyka scenariusz, w którym Twój hook nie zdążył się wykonać (np. użytkownik wszedł głęboko w serwis linkiem bez parametrów, ale gtag zapisał identyfikator podczas wcześniejszej wizyty).
Wywołaj sendServerConversion(order) w tym samym useEffect na thank you page, w którym odpala się adsConversions.purchase — obie ścieżki idą równolegle, a deduplikację załatwia wspólny identyfikator: transaction_id w gtag i orderId w uploadzie, oba równe order.id.
Zwróć uwagę, że czasem konwersji jest moment złożenia zamówienia (tu: chwila obsługi requestu), a nie timestamp przechwycenia GCLID — ten drugi mówi tylko, kiedy użytkownik kliknął reklamę, i przydaje się co najwyżej do odrzucenia identyfikatorów starszych niż okno konwersji.
W produkcyjnym wdrożeniu ten endpoint warto uszczelnić: wołaj go z logiki serwerowej po potwierdzeniu płatności (np. z webhooka Stripe) zamiast z przeglądarki, a przynajmniej zweryfikuj, że orderId istnieje i nie był już uploadowany. Endpoint przyjmujący dowolne wartości konwersji z klienta to zaproszenie do zaśmiecenia danych kampanii.
Krok 5: Consent Mode v2 i Google Ads
Consent Mode v2 to dla Google Ads warunek gry w EEA/UK/CH. Trzy sygnały mają znaczenie: ad_storage (cookies reklamowe), ad_user_data (przesyłanie danych użytkownika do Google — bez niego nie zadziałają m.in. enhanced conversions) i ad_personalization (personalizacja i remarketing).
Najczęstszy błąd wdrożeniowy: obsłużony jest tylko consent update po kliknięciu w banner, a brakuje stanu domyślnego. wymaga, żeby consent default wykonał się przed pierwszym config — inaczej gtag przy załadowaniu strony zdąży zachować się tak, jakby zgoda była udzielona. W Next.js oznacza to umieszczenie defaultu w tym samym inline skrypcie, przed liniami config:
wait_for_update daje bannerowi 500 ms na dostarczenie zapisanej wcześniej zgody, zanim gtag zacznie wysyłać cokolwiek z domyślnym denied. Parametr region pozwala ograniczyć restrykcyjny default do regionów, które tego wymagają. Po decyzji użytkownika banner wysyła aktualizację:
Gdy consent pozostaje denied, gtag przechodzi w tryb cookieless ping — wysyła zubożone sygnały bez identyfikatorów, na których Google może modelować konwersje (przy wystarczającym wolumenie danych). Dla utrzymania atrybucji bez cookies przydaje się jeszcze url_passthrough:
Z tą flagą gtag dokleja GCLID do linków wewnętrznych podczas nawigacji, dzięki czemu informacja o kliknięciu reklamy nie ginie mimo braku zgody na cookies. To nadal pomiar gorszej jakości niż pełny consent — ale znacznie lepszy niż zero sygnału.
Debugowanie conversion tracking w Google Ads
Google Tag Assistant
Wejdź na tagassistant.google.com, podłącz swoją domenę i przejdź ścieżkę konwersji od wejścia z parametrem gclid po thank you page. Tag Assistant pokaże każde wywołanie gtag w kolejności — w tym stan consentu w momencie odpalenia tagu i przekazane user_data dla enhanced conversions. To najszybszy sposób, żeby wykryć klasyczny błąd kolejności: config wykonany przed consent default.
Diagnostyka konwersji w Google Ads
W panelu Google Ads każda akcja konwersji ma zakładkę diagnostyczną ze statusem tagu: czy jest aktywny, kiedy ostatnio otrzymał dane, jaki odsetek konwersji ma dołączone dane enhanced conversions i czy występują problemy z consentem. Świeżo wdrożony tag potrafi mieć status „No recent conversions" przez kilkadziesiąt godzin — to normalne opóźnienie raportowania, nie sygnał błędu.
Network tab i requesty konwersji
W DevTools filtruj requesty po googleadservices.com/pagead/conversion — to właśnie Twoje konwersje. W parametrach requestu zobaczysz value, currency_code i label; przy enhanced conversions dojdzie zahashowany blok danych użytkownika. Sprawdź też w zakładce Application, czy po wejściu z ?gclid=test123 powstało cookie _gcl_aw (i Twoje _gclid, jeśli używasz hooka z kroku 4).
Debugowanie uploadów server-side
Dla uploadów przez API najważniejsza zasada: loguj partialFailureError, bo HTTP 200 nie oznacza przyjętej konwersji. Typowe błędy to CLICK_NOT_FOUND (GCLID nie istnieje albo pochodzi z innego konta), TOO_RECENT_CONVERSION_ACTION (akcja utworzona przed chwilą — odczekaj kilka godzin) i EXPIRED_CLICK (kliknięcie poza oknem konwersji). Ręcznie spreparowany gclid=test123 zawsze zwróci CLICK_NOT_FOUND — do testów end-to-end potrzebujesz kliknięcia z prawdziwej kampanii.
Najczęstsze błędy conversion tracking
Podwójne konwersje – użytkownik odświeża thank you page i konwersja wysyła się ponownie. Rozwiązanie: transaction_id + deduplikacja.
Podwójne liczenie z dwóch źródeł – tag Google Ads i import z GA4 ustawione jako primary dla tej samej akcji. Każdy zakup liczy się dwa razy, a bidding optymalizuje się pod fikcyjne wyniki. Jedno źródło primary, reszta secondary.
Brak GCLID – jeśli URL jest przepisywany (redirect, UTM stripping), GCLID się gubi. Upewnij się, że GCLID przeżywa redirecty.
Tylko gclid, bez gbraid/wbraid – na ruchu z iOS klasyczny identyfikator często nie dociera i konwersje z urządzeń Apple systematycznie wypadają z pomiaru. Hook z kroku 4 łapie wszystkie trzy.
consent update bez consent default – banner aktualizuje zgodę, ale gtag załadował się bez zdefiniowanego stanu domyślnego, więc do momentu decyzji użytkownika działał tak, jakby zgoda była. Formalnie to brak zgodności z wymogami dla EEA/UK/CH, nawet jeśli dane „wyglądają dobrze".
Różne wartości konwersji w GA4 i Google Ads – upewnij się, że wysyłasz te same wartości (centy vs złotówki, z VAT vs bez VAT) do obu systemów.
