# The Complete WooCommerce Google Tag Manager dataLayer Guide (GA4, 2026) > Everything about the WooCommerce → GTM → GA4 pipeline in one place: the event map, payload schema, container setup, consent, dedup, and the failure modes that corrupt data. *Source: https://plugins.viglan.com/woocommerce-gtm-datalayer-guide/* Google Tag Manager is the right way to run analytics on a WooCommerce store — *if* the dataLayer feeding it is complete and correct. This guide is the reference we wish existed: the full event map, the payload rules that GA4 actually enforces, container wiring, and the classic mistakes that silently corrupt data for months. ## Why GTM instead of pasting gtag.js With GTM, your site publishes *facts* (a clean dataLayer: “someone added product X for €29”) and the container decides which platforms consume them — GA4 today; Google Ads, Meta or a heatmap tool tomorrow, without touching the site. Marketing iterates in GTM’s interface; the site’s code stays stable. The dataLayer is the contract between the two worlds, which is why its quality decides everything downstream. ## The full WooCommerce event map GA4’s eCommerce schema maps onto WooCommerce like this — the funnel in bold: - `view_item_list` — shop/category/search results render (with `item_list_name` and index positions) - `select_item` — click through to a product from a list - **`view_item`** — single product page - **`add_to_cart`** / `remove_from_cart` — including AJAX archive adds and Blocks (see our [add_to_cart deep-dive](https://plugins.viglan.com/ga4-add-to-cart-not-tracking-woocommerce/)) - **`view_cart`** → **`begin_checkout`** → `add_shipping_info` → `add_payment_info` - **`purchase`** — exactly once per order, deduplicated - `refund` — full and partial, same transaction ID - Plus: `view_promotion`/`select_promotion`, `add_to_wishlist`, `search`/`view_search_results`, `login`/`sign_up`, `apply_coupon` ## Payload rules GA4 actually enforces GA4 drops or mangles events that break these rules — silently: 1. **Always reset before pushing:** `dataLayer.push({ ecommerce: null })` before every ecommerce push, or items from the previous event bleed into the next (the single most common corruption). 2. **`value` is a number, `currency` is mandatory.** “€29.99” as a string breaks revenue; a missing currency breaks it quietly in multi-currency stores. 3. **Every item needs `item_id` and `item_name`.** Decide once whether item_id is the product ID or SKU and never mix — mixing splits one product into two GA4 entities. 4. **Categories:** `item_category` through `item_category5`, most general first. Deeper taxonomy is discarded. 5. **`transaction_id` on purchase** — GA4 dedups on it; it is also your reconciliation key against WooCommerce order numbers and the bridge to any server-side events. ## Container wiring (the 20-minute version) 1. One **GA4 configuration tag** (your G- ID), firing on Initialization — after the consent default (below). 2. One **GA4 event tag per event**, trigger = Custom Event matching the event name, with “Send Ecommerce data → Data Layer” enabled — or a single event tag using the event-name variable if you prefer a compact container. 3. **Built-in variables:** enable the ecommerce ones; add a Data Layer Variable for anything custom you push. 4. **Test in Preview mode** against a real order (use a 100% coupon on a staging product) before publishing. The published version — not the draft — is what runs for customers. Or import a prebuilt container: TrackPilot ships one where every tag, trigger and variable above is already wired to its dataLayer. ## Consent Mode v2 changes the firing rules For EEA traffic your tags must respect the four consent signals, with defaults *denied* printed before the container loads. The dataLayer keeps recording either way — consent gates what the *tags* do with it. Full walkthrough: [Consent Mode v2 for WooCommerce](https://plugins.viglan.com/consent-mode-v2-woocommerce/). ## Purchases: one order, one event — ever Thank-you pages get refreshed, bookmarked and revisited from order emails. Deduplicate per order (order meta server-side; GA4’s transaction_id as the backstop) and your revenue survives all of it. If you add server-side events later ([why you should](https://plugins.viglan.com/server-side-tracking-woocommerce/)), the same transaction ID is what keeps browser + server from double-counting. ## The five silent data-corrupters 1. No `ecommerce: null` reset (item bleed) 2. Duplicate GA4 config — a theme’s hardcoded gtag plus your container (every event doubles) 3. item_id flip-flopping between SKU and product ID after a plugin change 4. Tax-inclusive prices in events, tax-exclusive in GA4 settings (or vice versa) 5. Testing only as a logged-in, consent-granted admin Audit each one quarterly; any of them can run unnoticed for a year. *TrackPilot ships all of this out of the box — every GA4 eCommerce event for WooCommerce (classic and Blocks), Consent Mode v2, an importable GTM container and a live debugger. [See TrackPilot →](https://plugins.viglan.com/plugins/trackpilot-for-woocommerce-ga4-gtm-tracking-pro/)*