Analytics
GA4 ecommerce events that match real revenue
GA4 ecommerce events only help a store if purchase revenue looks like the gateway, not like a dashboard fiction. I am a Gold Coast web developer with 18 years on Magento, Shopify and WooCommerce. I have sat in meetings where conversion rate went up because we double-fired add_to_cart, and meetings where it went down because checkout moved and begin_checkout died. In 2026 the recommended event names are stable. The implementations are not.
Google's GA4 ecommerce collection guide is the schema I implement against. This note is how that schema fails on real catalogues: item IDs that do not match SKUs, tax included twice, shipping omitted, refunds never sent, and thank-you pages that fire on every reload.
If you cannot debug a purchase, you cannot trust a report. Use this with GA4 DebugView and with a dataLayer your theme owns, not only GTM visual tagging.
Which GA4 ecommerce events a store actually needs
GA4 ecommerce events a store actually needs start with the funnel you will defend, not with every optional event in the spec. I implement these as the spine:
view_item_list when a collection or search result renders items you can identify. select_item when a card is chosen. view_item on the PDP. add_to_cart and remove_from_cart with the same item shape. view_cart if the cart is a real page or drawer you care about. begin_checkout. add_shipping_info and add_payment_info when those steps exist as separate moments. purchase once per order. refund when the gateway or OMS says so.
That is already a lot. I do not start with view_promotion and add_to_wishlist unless merchandising lives on those actions. A boutique Shopify theme can wait. A Magento catalogue with layered nav cannot skip view_item_list if you want collection performance.
The item object is the contract. item_id should be the SKU you use in the warehouse and in the Shopping feed, not a hashed Magento entity ID that changes per store view. item_name should be human. item_brand, item_category, price, quantity should be honest. index on lists helps you see whether anyone clicks row 24.
purchase needs transaction_id, value, currency, items, and then tax and shipping as their own fields rather than smuggled into value twice. Value should be the order total you agreed with finance: usually revenue including tax or excluding tax, but not both in different weeks. Pick a definition, write it down, and keep Ads conversion value on the same definition if you can.
Do not send purchase with an empty items array. You will get revenue without product reports, and merchandisers will not forgive you.
On Their Nibs the published outcome was a storefront rebuild: 31 percent more conversions, 48 percent more orders. That was journey and theme. GA4 still had to record those orders once. On retail conversion at scale Magento work, sessions, funnels and cart abandonment were operational tools. If begin_checkout was missing, we would have been arguing about abandonment that was actually a tag gap.
How GA4 ecommerce events should be shaped in the dataLayer
GA4 ecommerce events should be shaped as a push you own, with event and ecommerce keys, not as GTM scraping button text. Shopify pixels, WooCommerce plugins and Magento modules all promise a complete dataLayer. I still print the payload on staging.
Clear previous ecommerce data before a new event if you reuse the same object in GTM. Stale items from view_item attached to purchase is a classic contamination. The current GA4 recommendation is a clean ecommerce object per event.
Currency is ISO codes. Do not send $. Value is numeric. Quantity is integer. Discount can live on the item. Coupon can live on the purchase. If you run Magento multi-store, do not let store-view currency leak into a property that finance reads in AUD.
User properties and user_id are separate from ecommerce. Logged-in wholesale customers should not share a client_id story with guest retail if you are about to compare conversion rates. That is account design, not an item field.
Consent still wraps this. If analytics_storage is denied, you may get no GA4 events or cookieless pings depending on Consent Mode. Do not debug a missing purchase for two hours before you check the CMP.
Server-side collection can send the same events via Measurement Protocol or sGTM. The schema does not change. The temptation is to fire both client and server purchase. Deduplicate with transaction_id and a single pipeline. I expand that in server-side vs client-side analytics for stores.
Theme apps love to inject their own gtag with a different measurement ID. You then have two properties, or duplicates in one. Inventory tags the same way I inventory Ads tags: one owner.
I still write the push in the theme or in a small module I control, even when an app offers a "complete GA4 setup" checkbox. Apps guess at Magento configurable SKUs and at Shopify variant IDs. They often send the parent as item_id on view_item and the variant on purchase. Product reports then look like two catalogues. If I cannot change the app, I overwrite on the thank-you with an order-object pixel and I disable the app's purchase event. Two incomplete events are worse than one complete one.
List name and index on view_item_list are how you see whether merchandising position 1 actually earns the click. Without them, collection work is a feeling. With them, you can tell a merchandiser that row 1 is ignored on mobile because the filter drawer covers it. That is a storefront ticket, not an analytics philosophy.
Production checklist for items, tax and purchase
A store's GA4 ecommerce is ready when a test order in DebugView matches the order admin.
- Measurement ID is production, not a leftover UA-era property, not a duplicate GA4.
- dataLayer events use the GA4 event names, not Universal Analytics
checkoutsteps as the only story. item_idmatches SKU in admin and feed.view_itemfires once per PDP load, not on every image swap unless you truly want that.add_to_cartfires on success, not on button mousedown before variant validation fails.begin_checkoutfires when checkout actually starts, including Shop Pay and express wallets if those skip your cart page.purchaseincludes items, tax, shipping, transaction_id, value, currency.- Thank-you reload does not send a second
purchase. Use a flag, a server event, or GTM that keys on transaction_id already seen. - Refunds: at least a process for full refunds. Partial refunds if OMS can emit them.
- Compare seven-day
purchaserevenue in GA4 to gateway, with timezone alignment.
WooCommerce block checkout and Shopify checkout extensibility both move where the thank-you lives. If you still listen for a classic order-received body class, you will miss wallet users. Test those paths on purpose.
What breaks totals until nobody trusts GA4
Duplicates. Theme pixel plus GTM plus an app. Each purchase is +1 order in GA4. ROAS looks incredible. Finance calls you a liar.
Missing items. Some connectors send value and transaction_id only. Product reports empty. People then "fix" it by adding a second plugin.
Tax double count. Value includes tax and you also add tax, or Magento display tax confuses the theme developer who copies grand_total and tax_amount into the wrong fields.
Currency mix. A USD test order in an AUD property. Outliers destroy average order value.
SPA collection pages that never fire view_item_list after filter AJAX. Merchandisers think the collection is dead. It is unmeasured.
Consent deny plus no server backup. Safari-heavy fashion traffic looks like a recession.
Item_id as parent product on configurable Magento SKUs. You lose colour and size in reports. You also disagree with Shopping, which advertised the variant.
Refunds ignored. Revenue only goes up. A high-return category looks like a hero.
I fix measurement before I argue merchandising. That was true when I ran Magento retail conversion work and it is true on contract Shopify builds.
Coupon and discount fields are where finance and marketing start separate arguments. If the theme sends value after discount and also sends a discount parameter that GTM adds again, AOV looks like a sale that never happened. If you run automatic Shopify discounts plus a code, send the order-level total from the order object, not from a running cart JS variable that missed a second discount. Magento cart rules have the same trap when a developer copies subtotal instead of grand_total and then "fixes" shipping in GTM by guesswork.
How to measure whether GA4 matches the gateway
Pick a timezone. Pick a definition of revenue. Pull gateway orders for seven days after conversion lag. Pull GA4 purchase event count and total revenue. Pull item quantity for a hero SKU and compare to units sold.
A small gap is consent, blockers, and people who never load the thank-you. A large gap is your tag. A GA4 number above the gateway is almost always duplicates or test traffic.
Use DebugView on a real purchase, then use exploration reports, not only the monetisation overview. Overviews hide parameter mistakes.
When the numbers agree, you can talk about GA4 campaign benchmarks and GA4 attribution without lying. Until then, benchmarks compare your broken funnel to someone else's.
I also spot-check one SKU through the funnel in an exploration: view_item to add_to_cart to purchase item quantity. If views are huge and purchases exist but add-to-cart is almost zero, the add event is tied to the wrong button (wishlist, notify me, or a size guide). If add-to-cart is huge and purchase items are zero, checkout is untagged or items were dropped from the purchase payload. That SKU walk finds bugs faster than a property-wide conversion rate.
Related work on this site
Retail conversion at scale is three Magento stores, funnels and a $2.5 million year-on-year sales increase over three years. Measurement was part of the job. Their Nibs is a Shopify rebuild with published conversion and order lifts. GA4 ecommerce events sit under both: one order, one purchase, items that merchandisers recognise. For the debug pass, use GA4 DebugView. For how the payload gets into GTM, use visual tagging vs dataLayer events.
FAQ
Which GA4 ecommerce events are mandatory?
None are mandatory in the product sense, but a store that cannot send a correct purchase should not be making channel decisions from GA4. I treat view_item, add_to_cart, begin_checkout and purchase as the minimum honest funnel.
Why do GA4 ecommerce events show more revenue than Shopify or Magento?
Duplicates, tax included twice, or test orders. DebugView the thank-you. Count how many purchase events you see for one order. Then check value against the order admin.
Can GA4 ecommerce events use product name as item_id?
You can, and you will regret it when names change. Use the SKU. Names belong in item_name.
Do GA4 ecommerce events replace Google Ads conversion tags?
No. They can share a dataLayer. Ads still needs its own conversion action, preferably with the same transaction_id and value rules. Keep them aligned, not merged into one vague "pixel."
Keep reading
Contact if you want this kind of work on a live store.