GA4 ecommerce tracking is a contract between your website and Google Analytics. Your site promises to send specific events with specific parameters at specific moments in the shopping journey, and GA4 promises to turn that data into revenue reports, funnel analysis, and product performance metrics. When the contract is fulfilled correctly, you get visibility into every step from product view to purchase; when it isn't, you get zero revenue in your reports and no way to diagnose where the funnel breaks.
This piece translates Google's ecommerce implementation specification into plain language. If you're the person explaining to your developer what needs to be built, or the developer trying to understand what the analytics team is asking for, this is the reference.
What GA4 expects from your ecommerce tracking
GA4 ecommerce tracking works through a series of predefined events that represent steps in the purchase funnel, where each event has a specific name that GA4 recognizes and each carries parameters that provide the details GA4 needs to calculate metrics. Use Google's exact event names and parameter names rather than custom alternatives, because the built-in ecommerce reports only populate when GA4 sees its expected event names.
The tracking follows a funnel structure: a customer views a product, adds it to cart, begins checkout, enters shipping and payment information, and completes the purchase, with GA4 defining an event for each step. You don't need to implement all of them to get some ecommerce data, but implementing all of them gives you funnel analysis that shows exactly where customers drop off — and that's the insight that actually drives revenue improvements.
The data flows through a standard path: your ecommerce platform pushes structured data to the browser's data layer, Google Tag Manager reads that data and maps it to a GA4 event tag, and the tag sends the event to your GA4 property. Every piece of this chain needs to be correct for revenue to appear in reports.
The ecommerce funnel events in order
Here's each event in the purchase funnel, what it captures, and when it should fire:
| Event | When it fires | What it tells you |
|---|---|---|
| view_item_list | Customer sees a category page or search results | Which product listings get viewed |
| select_item | Customer clicks a product from a list | Which products attract clicks from listings |
| view_item | Customer lands on a product detail page | Which products get detailed attention |
| add_to_cart | Customer adds a product to their cart | Purchase intent signals |
| remove_from_cart | Customer removes a product from cart | What gets reconsidered |
| view_cart | Customer views their cart page | Cart review behavior |
| begin_checkout | Customer starts the checkout process | Checkout entry rate |
| add_shipping_info | Customer enters shipping details | Shipping step completion |
| add_payment_info | Customer enters payment details | Payment step completion |
| purchase | Transaction completes | Revenue, transaction count, product sales |
The most critical events are view_item, add_to_cart, begin_checkout, and purchase — these four give you the core funnel, and the others add granularity that becomes valuable as your traffic grows and you need to diagnose specific conversion problems.
Every ecommerce event also accepts a refund counterpart for handling returns, which uses the same transaction_id as the original purchase to subtract revenue from GA4 reports.
Required parameters per ecommerce event
Every ecommerce event needs an items array containing at least one product, and the purchase event has additional required parameters. Here's the breakdown:
| Parameter | Required on | Format | What happens if missing |
|---|---|---|---|
| currency | All events with monetary values | ISO 4217 string (e.g., "USD", "EUR") | Revenue not calculated |
| value | purchase, recommended on others | Number (not string) | Revenue shows $0 |
| transaction_id | purchase | Unique string per transaction | Duplicate purchases not deduplicated |
| items | All ecommerce events | Array of item objects | Event recorded but no product data |
| coupon | Optional on all | String | Coupon reporting unavailable |
| shipping | Optional on purchase | Number | Shipping revenue not tracked |
| tax | Optional on purchase | Number | Tax data not tracked |
The three non-negotiable parameters on purchase are transaction_id, value, and currency. Google's documentation is explicit: without all three, GA4 will not calculate revenue metrics for the transaction — the event still fires and counts, but the money doesn't show up.
The items array and how to structure it
The items array is where product-level data lives, and every ecommerce event should include it. Each item in the array follows a specific structure:
| Field | Required | Format | Example |
|---|---|---|---|
| item_id | Yes | String | "SKU-12345" |
| item_name | Yes | String | "Widget Pro" |
| price | Recommended | Number | 49.99 |
| quantity | Recommended | Integer | 1 |
| item_brand | Optional | String | "Acme Corp" |
| item_category | Optional | String | "Electronics" |
| item_category2 | Optional | String | "Gadgets" |
| item_variant | Optional | String | "Blue / Large" |
| index | Optional | Integer | 0 |
| discount | Optional | Number | 5.00 |
Either item_id or item_name is required for GA4 to recognize the item, though best practice is to include both. The price should be the per-unit price rather than the line total, since GA4 calculates line totals internally by multiplying price by quantity.
GA4 supports up to five item categories through item_category, item_category2, item_category3, item_category4, and item_category5, which map to product taxonomy levels. If your product is "Electronics > Gadgets > Smart Home > Thermostats", you'd use four category levels.
A common implementation error: sending price as a string ("49.99") instead of a number (49.99). GTM's Data Layer Variable can handle type coercion in some cases, but the safest approach is to ensure the data layer always pushes numeric values for any monetary field.
The data layer push format
Here's what the data layer push looks like for each major event — this is what your developer needs to produce from the ecommerce platform:
Product page view:
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'USD',
value: 49.99,
items: [{
item_id: 'SKU-12345',
item_name: 'Widget Pro',
price: 49.99,
item_brand: 'Acme',
item_category: 'Electronics'
}]
}
});Add to cart:
window.dataLayer.push({
event: 'add_to_cart',
ecommerce: {
currency: 'USD',
value: 49.99,
items: [{
item_id: 'SKU-12345',
item_name: 'Widget Pro',
price: 49.99,
quantity: 1
}]
}
});Purchase (the critical one):
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'TXN-98765',
value: 54.98,
currency: 'USD',
tax: 4.99,
shipping: 0.00,
items: [{
item_id: 'SKU-12345',
item_name: 'Widget Pro',
price: 49.99,
quantity: 1
}]
}
});One important detail: the data layer should be cleared before each ecommerce push to prevent stale data from a previous event contaminating the next one. Add this before each ecommerce push:
window.dataLayer.push({ ecommerce: null });Without this clearing step, if a customer views a product and then views a different product, the second view_item event might carry items data from both product views because the ecommerce object persists in the data layer between pushes.
Common shortcuts that break ecommerce tracking
Hardcoded currency instead of dynamic values. When a developer hardcodes currency: 'USD' in the GTM tag configuration instead of reading it from the data layer, the implementation works for US transactions but breaks silently for international orders. Always read currency from the data layer push, where it should be set by the ecommerce platform based on the actual transaction currency.
The purchase event on a page load trigger. The purchase event should fire when the data layer receives the purchase push, not when the order confirmation page loads — page load triggers fire before the data layer is populated, sending a purchase event with empty parameters. The correct trigger is a Custom Event trigger in GTM that matches the data layer push event name.
Missing the ecommerce toggle. GA4 property settings include an ecommerce reporting toggle that must be enabled for ecommerce data to appear in the monetization reports. The data layer can be perfect, the GTM tags can fire correctly, and the events can appear in DebugView with all parameters, but with this toggle off the ecommerce reports stay empty.
Incomplete funnel coverage. Implementing only view_item and purchase is better than nothing but eliminates the diagnostic value of funnel analysis — when revenue drops, you can see that fewer people purchased but not whether they stopped adding to cart, abandoned checkout, or never made it past the shipping step. Implementing the full funnel from the start costs marginally more development effort and saves significant debugging effort later.
Testing only the happy path. A purchase with one item, the default currency, and a simple product structure will work in most implementations, but the edge cases are what break things: multi-item carts where the items array needs multiple objects, transactions with discounts where the value should reflect the discounted total, and cross-currency purchases where the currency parameter changes per transaction.
The developer handoff
The conversation with your development team doesn't need to involve GA4 terminology — frame it in terms of what data needs to be available and when:
"When a customer views a product page, I need the product ID, product name, price, brand, and category pushed to the data layer. When they add something to the cart, I need the same product information plus the quantity. When they complete a purchase, I need a unique transaction ID, the total order value, the currency, and the full list of products they bought with individual prices and quantities."
Pair this with a link to Google's ecommerce developer guide, which provides the exact JSON structure. The developer doesn't need to understand GA4 reporting — they need to understand the data format, and your job is to explain what information you need and why while their job is to produce it in the specified format from whatever ecommerce platform runs the backend.
Create a shared spreadsheet that serves as the spec document, listing each event in the funnel, the data layer push format (you can copy the examples above), and which page or interaction triggers each push. This becomes the testing checklist: walk through a purchase flow and verify that each event fires with the correct data at the correct moment, checking the browser console's data layer output at each step.
For platforms with built-in GA4 support (Shopify, WooCommerce, Magento, BigCommerce), the data layer implementation may already exist through a plugin or native integration, so check whether the platform's integration sends all the events and parameters you need before building a custom implementation. Many do, but with gaps: Shopify's built-in integration, for instance, handles the core ecommerce events but may not include all optional parameters or intermediate funnel steps depending on the theme and checkout configuration. WooCommerce implementations vary by plugin, with some providing the full funnel and others stopping at purchase, so testing against the spec document catches these gaps before they become reporting problems.
TagManifest checks the GTM side of this contract: whether purchase events include required parameters, whether ecommerce events fire on the correct trigger types, and whether the funnel events are all present or if steps are missing. The data layer implementation lives outside GTM and needs verification through DebugView and the testing process described above.