# E-commerce GA4 w WooCommerce: wdrożenie od zera

**Author:** Piotr Litwa - GTM & Analytics Specialist  
**Published:** 2026-10-16  
**URL:** https://piotrlitwa.com/articles/pl/ga4-woocommerce-ecommerce.html  
**Language:** pl  
**Keywords:** ga4 woocommerce, śledzenie e-commerce woocommerce, gtm4wp woocommerce, zdarzenie purchase woocommerce, data layer woocommerce

---

Śledzenie e-commerce GA4 w WooCommerce to wysyłanie ze sklepu do GA4 siedmiu zdarzeń (`view_item_list`, `view_item`, `add_to_cart`, `begin_checkout`, `add_shipping_info`, `add_payment_info`, `purchase`), każdego z tablicą `items`, oraz `transaction_id` przy zakupie, żeby GA4 umiało odróżnić zamówienia. Dojdziesz do tego wtyczką, GTM4WP z kontenerem GTM albo własnym kodem data layer.

Większość sklepów, które sprawdzam, ma te zdarzenia. Dużo mniej ma przychód zgodny z WooCommerce w granicach 10%. O tej różnicy jest ten poradnik: zdublowane zakupy, gdy ktoś odświeża stronę podziękowania, checkout blokowy psujący środek lejka i bramki płatności, które nigdy nie odsyłają klienta z powrotem.

> **Najważniejsze wnioski**
> - Wybierz jedną metodę: wtyczka dla prostych sklepów, GTM4WP plus GTM, jeśli masz też pixele reklamowe, własny data layer tylko przy mocno przerobionym checkoucie.
> - Tablica `items` to serce e-commerce w GA4. `item_id` musi się zgadzać z feedem produktowym, inaczej raporty Google Ads i Merchant Center się nie połączą.
> - Strona podziękowania odpala `purchase` przy każdym odświeżeniu. Blokuj to po stronie serwera flagą w metadanych zamówienia, nie tylko licząc na deduplikację GA4.
> - Checkout blokowy (domyślny dla nowych sklepów od WooCommerce 8.3) nie odpala klasycznych zdarzeń jQuery. `add_shipping_info` i `add_payment_info` psują się jako pierwsze.
> - Porównuj co miesiąc przychód w GA4 z zamówieniami w WooCommerce, po numerze zamówienia. Różnica 10-20% jest w UE normalna przez zgody. 40% już nie.

## Trzy sposoby na wysyłanie danych z WooCommerce do GA4

Nie ma jednej dobrej odpowiedzi. Jest dobra odpowiedź dla stopnia skomplikowania Twojego sklepu.

| Metoda | Co to jest | Dobre dla | Na co uważać |
|---|---|---|---|
| **Własne rozszerzenie GA od WooCommerce** | "Google Analytics for WooCommerce", darmowe od WooCommerce | Jedna usługa GA4, zero innych pixeli | Mała kontrola nad parametrami, własny gtag.js potrafi zdublować GTM |
| **GTM4WP + GTM** | Wtyczka GTM Thomasa Geigera, wypycha data layer e-commerce w formacie GA4 | Sklepy z GA4 plus Meta, TikTok, Google Ads | Tagi i reguły GA4 w GTM i tak budujesz sam |
| **Własny data layer** | Twoje własne pushe z PHP i JS do `dataLayer` | Headless, mocno przerobione checkouty | Każdy błąd i każda aktualizacja WooCommerce są Twoje |

Słowo o "Google for WooCommerce": to oficjalna wtyczka do Merchant Center i Google Ads. Przydaje się do feedu produktowego i konwersji w Ads. Nie jest tym, czego użyłbym do budowy lejka e-commerce w GA4.

Mój standard dla sklepu z płatnym ruchem to GTM4WP plus GTM. Jeden data layer zasila GA4, Metę, TikToka i Google Ads z jednego miejsca, a każdy tag widzisz w jednym kontenerze. Wtyczka sprawdza się do dnia, w którym dokładasz drugiego dostawcę. Wtedy masz dwa systemy czytające koszyk i one się ze sobą nie zgodzą.

Cokolwiek wybierzesz, używaj tylko jednego. Rozszerzenie GA4 wysyłające gtag.js plus kontener GTM z tagiem GA4 na tym samym identyfikatorze pomiaru to podwójne tagowanie, o czym napisałem cały tekst [Google tag czy GTM](https://piotrlitwa.com/articles/pl/google-tag-czy-gtm.html).

## Siedem zdarzeń i tablica items

GA4 ma stały, zalecany schemat e-commerce. Używaj dokładnie tych nazw. `addToCart` albo `add_to_basket` wyląduje jako [zdarzenie niestandardowe](https://piotrlitwa.com/articles/pl/zdarzenia-niestandardowe-ga4.html) i nigdy nie pojawi się w raportach Generowanie przychodu.

| Zdarzenie | Kiedy odpala się w WooCommerce | Parametry, które zawsze wysyłam |
|---|---|---|
| `view_item_list` | Renderuje się sklep, kategoria, wyszukiwarka albo produkty powiązane | `item_list_id`, `item_list_name`, `items` |
| `view_item` | Ładuje się strona pojedynczego produktu | `currency`, `value`, `items` |
| `add_to_cart` | Dodanie do koszyka, łącznie z przyciskami AJAX na listingach | `currency`, `value`, `items` |
| `begin_checkout` | Ładuje się checkout z niepustym koszykiem | `currency`, `value`, `coupon`, `items` |
| `add_shipping_info` | Klient wybiera metodę dostawy | `currency`, `value`, `shipping_tier`, `items` |
| `add_payment_info` | Klient wybiera metodę płatności | `currency`, `value`, `payment_type`, `items` |
| `purchase` | Strona otrzymanego zamówienia, raz na zamówienie | `transaction_id`, `currency`, `value`, `tax`, `shipping`, `coupon`, `items` |

Każdy obiekt w `items` powinien mieć co najmniej `item_id`, `item_name`, `price` i `quantity`. Dokładam `item_brand`, `item_category` i `item_variant` tam, gdzie sklep je ma. GA4 przyjmuje do 200 produktów w jednym zdarzeniu, co ma znaczenie tylko dla sklepów B2B z hurtowymi koszykami.

Trzy decyzje do podjęcia, zanim ktokolwiek napisze kod:

1. **`item_id`: SKU czy ID produktu?** To, czego używa Twój feed w Merchant Center, inaczej raporty na poziomie produktu nie zgrają się między narzędziami.
2. **Warianty.** Dla koszulki w rozmiarze M wysyłaj SKU wariantu jako `item_id` i "M" jako `item_variant`, inaczej każdy rozmiar liczy się jako jeden produkt.
3. **`value` przy zakupie.** Biorę sumę produktów po rabatach, a podatek i dostawę wysyłam w osobnych parametrach.

Sama reguła ma mniejsze znaczenie niż to, żeby stosować ją wszędzie tak samo.

Przed każdym pushem wyczyść poprzedni obiekt e-commerce przez `dataLayer.push({ ecommerce: null })`. GTM4WP robi to za Ciebie. Własny kod lubi o tym zapominać i wtedy `view_item` niesie produkty z poprzedniej listy. Strukturę pushy omawiam dokładniej w [poradniku o data layer dla GA4](https://piotrlitwa.com/articles/pl/data-layer-ga4-gtm-poradnik.html).

## Problem strony podziękowania: zdublowane zakupy

Strona otrzymanego zamówienia w WooCommerce siedzi pod `/checkout/order-received/{order_id}/?key=wc_order_...`. Ten URL jest stały. Klienci go zapisują, odświeżają, wracają na niego z maila z potwierdzeniem. Każde wejście renderuje stronę na nowo, a naiwna konfiguracja znowu wypycha `purchase`.

GA4 według dokumentacji deduplikuje zakupy z tym samym `transaction_id`. W praktyce nie buduję wyłącznie na tym. Nie pomaga to tagowi zakupu Mety czy TikToka czytającemu ten sam push, a duplikaty przechodzące w GA4 też już widziałem.

Julia prowadzi sklep z ceramiką we Wrocławiu, około 900 zamówień miesięcznie. GA4 pokazało 1060 zakupów za wrzesień 2026, a WooCommerce miał 912 opłaconych zamówień. W BigQuery 214 wartości `transaction_id` pojawiało się więcej niż raz. Większość to klienci płacący przez Przelewy24, którzy trafiali na stronę podziękowania, a potem otwierali ten sam link jeszcze raz z maila potwierdzającego.

Rozwiązanie to flaga na zamówieniu. Wypychasz `purchase` tylko wtedy, gdy zamówienie nie było jeszcze śledzone, a potem je oznaczasz:

```php
add_action( 'woocommerce_thankyou', function ( $order_id ) {
    $order = wc_get_order( $order_id );
    if ( ! $order || $order->get_meta( '_ga4_purchase_sent' ) ) {
        return;
    }
    $items = array();
    $value = 0;
    foreach ( $order->get_items() as $item ) {
        $product = $item->get_product();
        $price   = (float) $order->get_item_total( $item, false );
        $value  += $price * $item->get_quantity();
        $items[] = array(
            'item_id'   => $product ? ( $product->get_sku() ?: (string) $product->get_id() ) : '',
            'item_name' => $item->get_name(),
            'price'     => round( $price, 2 ),
            'quantity'  => $item->get_quantity(),
        );
    }
    $data = array(
        'event'     => 'purchase',
        'ecommerce' => array(
            'transaction_id' => (string) $order->get_order_number(),
            'currency'       => $order->get_currency(),
            'value'          => round( $value, 2 ),
            'tax'            => round( (float) $order->get_total_tax(), 2 ),
            'shipping'       => round( (float) $order->get_shipping_total(), 2 ),
            'items'          => $items,
        ),
    );
    echo '<script>window.dataLayer=window.dataLayer||[];dataLayer.push({ecommerce:null});dataLayer.push(' . wp_json_encode( $data ) . ');</script>';
    $order->update_meta_data( '_ga4_purchase_sent', 1 );
    $order->save();
} );
```

Kod używa `get_meta` i `update_meta_data`, więc działa też z HPOS (High-Performance Order Storage).

Kompromis: jeśli pierwsze załadowanie się nie uda, bo na przykład przeglądarka zamknęła się w trakcie renderowania, to zamówienie nigdy nie zostanie wysłane. Wolę jedno zgubione zamówienie niż jedno podwójne. Po zmianie liczby Julii za październik: 812 zakupów w GA4, 931 zamówień w WooCommerce, zero zdublowanych ID. 87% zgodności, czyli mniej więcej tyle, ile pozwala jej baner.

## Pułapki checkoutu blokowego

Od WooCommerce 8.3 (listopad 2023) nowe sklepy dostają domyślnie bloki Koszyk i Zamówienie zamiast shortcode'u `[woocommerce_checkout]`. Checkout blokowy to aplikacja w React rozmawiająca ze Store API. Stary kod śledzący nie wie, że ona w ogóle istnieje.

Oto, co się psuje:

- **Nie ma zdarzeń jQuery.** Klasyczny checkout odpala `updated_checkout` i `payment_method_selected` na `document.body`. Tracking, który na nie nasłuchuje, w checkoucie blokowym nie dostaje nic. Tak właśnie `add_shipping_info` i `add_payment_info` po cichu przestają działać.
- **Hooki PHP wewnątrz formularza nie ruszają.** Snippety podpięte pod `woocommerce_after_checkout_form` albo `woocommerce_review_order_before_payment` nigdy się nie wykonają, bo bloki nie renderują tych szablonów.
- **AJAX-owe dodawanie do koszyka w blokach.** Bloki Kolekcja produktów na listingach mają własny mechanizm dodawania do koszyka. Sprawdź, czy `add_to_cart` dalej odpala się na stronach kategorii, a nie tylko na stronie produktu.

Szymon, który sprzedaje części rowerowe z Torunia, przeszedł na checkout blokowy wiosną 2025, kiedy przebudowywał stronę zamówienia. Jego eksploracja lejka pokazywała przejście z `begin_checkout` do `add_payment_info` na poziomie 0% przez sześć tygodni. Nikt nie zauważył, bo `purchase` dalej działał. Naprawa: aktualizacja GTM4WP do bieżącej wersji, usunięcie własnego listenera jQuery od poprzedniego programisty i ponowny test każdego kroku checkoutu w podglądzie GTM.

Jeśli masz własne wdrożenie, testuj oba checkouty. Jeśli korzystasz z wtyczki, przed przejściem sprawdź w jej changelogu wsparcie dla bloku Zamówienie.

## Zgody: co zmienia się w sklepie na WooCommerce

W UE każde z tych zdarzeń podlega zgodzie. Przy Consent Mode v2 w trybie zaawansowanym GA4 nadal dostaje pingi bez ciasteczek od użytkowników, którzy odmówili, i modeluje część luki. W trybie podstawowym odmawiający nie wysyłają nic.

Na WordPressie oznacza to CMP, który ustawia domyślne zgody, zanim załaduje się GTM. Konfigurację opisałem w [poradniku o Cookiebot na WordPressie](https://piotrlitwa.com/articles/pl/cookiebot-wordpress-jak-zainstalowac.html), a ta sama logika dotyczy każdego CMP. Dwie kwestie specyficzne dla WooCommerce:

- Push `purchase` do data layer może się dziać niezależnie od zgody. To tylko obiekt JavaScript. Liczy się to, czy tagi, które go czytają, respektują zgody.
- Pixele spoza Google (Meta, TikTok) nie czytają Consent Mode. Każdy potrzebuje własnego wymogu zgody w GTM.

## Weryfikacja przychodu z zamówieniami w WooCommerce

To krok, który mówi Ci, czy wdrożenie działa. Robię go 7. i 30. dnia po starcie, potem co miesiąc.

1. **Najpierw przetestuj lejek w DebugView.** Złóż prawdziwe zamówienie z kuponem i dwoma produktami, korzystając z [trybu debugowania GA4](https://piotrlitwa.com/articles/pl/ga4-tryb-debugowania.html). Sprawdź, czy każde zdarzenie ma `items`, a `purchase` ma `transaction_id` zgodny z numerem zamówienia w WooCommerce.
2. **Wyeksportuj zamówienia z WooCommerce** za zamknięty miesiąc, tylko statusy W trakcie realizacji i Zrealizowane. Oczekujące na płatność, Nieudane i Anulowane to nie sprzedaż.
3. **Wyciągnij zakupy z GA4 po identyfikatorze transakcji.** W Eksploracjach tabela dowolna z wymiarem Identyfikator transakcji i danymi Przychody z zakupów. BigQuery jest czystsze, jeśli masz eksport.
4. **Połącz po numerze zamówienia.** Zamówienia, które są w WooCommerce, a nie ma ich w GA4, to odmowy zgody, adblocki albo klienci, którzy nie wrócili z bramki. ID, które są w GA4, a nie ma ich w WooCommerce, to zamówienia testowe albo nieudane płatności policzone za wcześnie.
5. **Spójrz na różnicę według metody płatności.** Jeśli jedna bramka ma dużo większą lukę, nie odsyła klientów na stronę otrzymanego zamówienia.

Różnica 10-20% to norma dla sklepu w UE z uczciwym banerem. Powyżej 30% coś jest zepsute. Nie ufałbym żadnemu raportowi przychodu w GA4, dopóki ta kontrola nie zostanie zrobiona choć raz. Jeśli przechodzisz z Shopify, mechanika jest inna, ale kontrola ta sama co w moim [poradniku o GTM na Shopify](https://piotrlitwa.com/articles/pl/gtm-shopify-konfiguracja.html).

## Najczęstsze pytania

**Jakiej wtyczki użyć do GA4 w WooCommerce?**
Dla sklepu z samym GA4 i bez innych pixeli wystarczy darmowe rozszerzenie Google Analytics od WooCommerce. Jeśli masz też tagi Mety, TikToka albo Google Ads, użyj GTM4WP z kontenerem GTM, żeby jeden data layer zasilał wszystkich dostawców. Nie uruchamiaj obu na tym samym identyfikatorze pomiaru.

**Dlaczego GA4 pokazuje więcej zakupów niż WooCommerce?**
Najczęściej strona podziękowania odpala `purchase` ponownie przy odświeżeniu albo gdy klient otwiera ją jeszcze raz z maila z potwierdzeniem. Sprawdź powtarzające się wartości `transaction_id`. Napraw to flagą w metadanych zamówienia, żeby każde zamówienie było wypychane raz.

**Dlaczego GA4 pokazuje mniejszy przychód niż WooCommerce?**
Odmowy zgody, adblocki i bramki płatności, z których klienci nie wracają na stronę otrzymanego zamówienia. Różnica 10-20% jest w UE normalna. Porównaj według metody płatności, żeby znaleźć bramkę, która gubi więcej niż reszta.

**Czy checkout blokowy WooCommerce działa ze śledzeniem GA4?**
Tak, ale kod pisany pod klasyczny checkout z shortcode'em się psuje. Zdarzenia jQuery, takie jak `updated_checkout`, nie odpalają się w checkoucie blokowym, więc `add_shipping_info` i `add_payment_info` znikają jako pierwsze. Użyj wersji wtyczki ze wsparciem dla bloku Zamówienie albo przepisz własne listenery.

**Czy item_id to ma być SKU, czy ID produktu w WooCommerce?**
To, czego używa Twój feed produktowy w Merchant Center. Zgodne ID pozwalają połączyć raporty GA4, Google Ads i Merchant Center na tym samym produkcie. Przy produktach z wariantami używaj SKU albo ID wariantu.

**Czy transaction_id jest wymagany przy zdarzeniu purchase?**
Technicznie GA4 przyjmie zakup bez niego, ale nie rób tego. `transaction_id` to sposób, w jaki GA4 odróżnia zamówienia, i sposób, w jaki uzgodnisz przychód z WooCommerce. Używaj numeru zamówienia, który widzi klient.

## Co dalej

Zacznij od uzgodnienia, nie od budowy. Wyeksportuj opłacone zamówienia z WooCommerce z zeszłego miesiąca, wyciągnij zakupy z GA4 po identyfikatorze transakcji i porównaj. Ten jeden arkusz powie Ci, czy potrzebujesz poprawki, czy przebudowy.

Jeśli liczby rozjeżdżają się o ponad 30% albo widzisz powtarzające się identyfikatory transakcji, [darmowy audyt GTM](https://piotrlitwa.com/checkGTM/) pokaże, co odpala Twój kontener i co ignoruje zgody. Jeśli chcesz, żeby ktoś zbudował cały e-commerce i sprawdził go z Twoimi zamówieniami, od tego jest [wdrożenie GA4](https://piotrlitwa.com/services.html#ga4).

---

**Źródła i dalsza lektura**
- [Pomiar e-commerce w GA4](https://developers.google.com/analytics/devguides/collection/ga4/ecommerce) (Google for Developers)
- [Zalecane zdarzenia GA4, dokumentacja](https://developers.google.com/analytics/devguides/collection/ga4/reference/events) (Google for Developers)
- [Wtyczka GTM4WP](https://wordpress.org/plugins/duracelltomi-google-tag-manager/) (WordPress.org)
- [Bloki Koszyk i Zamówienie](https://woocommerce.com/document/cart-checkout-blocks-status/) (WooCommerce)

---

*Written by [Piotr Litwa](https://piotrlitwa.com/about.html) - independent GTM & Analytics specialist.*
