TagIntact
Module 3 · Lesson 1 of 4 · 10 min

Ecommerce events, start to finish

view_item to purchase with the items[] array done right, the refresh guard, and where revenue quietly goes wrong.

Verified against GA4 recommended ecommerce events + GTM, September 2026 on 2026-09-27

Ecommerce is where tracking earns its keep and where it breaks most expensively. The good news: GA4 has one fixed vocabulary, and if the site pushes it correctly, the container side is four nearly-identical tags.

The funnel

Step Event Pushed when
Browse view_item_list a list of products renders
select_item a product in a list is clicked
Product view_item product page loads
Cart add_to_cart / remove_from_cart the cart changes
view_cart cart page loads
Checkout begin_checkout checkout starts
add_shipping_info / add_payment_info those steps complete
Done purchase the order is confirmed — on the thank-you page
Later refund from the back office, usually server-side

Every one carries an ecommerce object with currency, value, and items[]. purchase adds transaction_id, and should carry tax and shipping so value can be product revenue.

The items[] array

Each item is an object; the fields GA4 understands:

{
  item_id: "SKU-1001",       // one of item_id / item_name is required
  item_name: "Canvas Tote",
  item_brand: "TagIntact Goods",
  item_category: "Bags",     // up to item_category5
  item_variant: "Natural",
  price: 24,                  // unit price, number
  quantity: 1,
  index: 0,                   // position in a list, for select_item / view_item_list
  item_list_id: "search_results",
  coupon: "WELCOME10",
  discount: 2.4
}

The mistakes that show up in the auditor and in reports, in order of frequency:

  • price as a string — "24.00" or "$24". GA4 wants a number. Revenue-by-item reports go blank.
  • items as an object instead of an array with one element.
  • value that doesn't equal the sum of price × quantity — fine on purpose (discounts), confusing by accident.
  • Missing transaction_id — GA4 can't dedupe, and a refreshed thank-you page becomes a second order.
  • currency missing — the hit is accepted; revenue in the reports shows as (not set).

The container side

Because the site does the work, each event is the same tag with a different name:

  • GA4 Event tag · Event name add_to_cart · Send Ecommerce data from Data Layer · trigger: Custom Event add_to_cart.

Copy it four or five times, change the name and trigger. Do not type items parameters by hand; that's what Send Ecommerce data is for. The one thing worth adding manually is value and currency as explicit event parameters when the site's push is unreliable — but the real fix is the push.

Google Ads conversions ride the same trigger: a Google Ads Conversion Tracking tag on the purchase Custom Event, with {{DL – ecommerce.value}}, {{DL – ecommerce.currency}} and {{DL – ecommerce.transaction_id}} as the Conversion Value / Currency / Transaction ID. Same event, two tags, one source of truth.

The refresh guard

This is the bug every store has had at least once. The thank-you page pushes purchase on load; the customer refreshes, or comes back from their email; the push runs again; revenue is now 2× for that order.

Fixes, best first:

  1. Server-side idempotence — the page only renders the push the first time the order is viewed.
  2. A client-side flag — sessionStorage or a cookie keyed to transaction_id, checked before pushing. The sandbox thank-you page does exactly this; reload it and watch no second purchase request appear.
  3. GA4's own dedupe — GA4 will ignore a repeated purchase with the same transaction_id within a session. Useful, not sufficient: sessions end.

Prove it end to end

Walk the sandbox from home to thank-you with Preview connected and the network tab filtered to collect. You should see seven events in order, each with one request, purchase carrying pr1… items and epn.value in the payload, and nothing on refresh. That sequence — a journey, replayed, with assertions on each step — is what the monitor automates on a schedule. For now, you've done it by hand, which is how you'll know when the automation is lying to you.

Try it in the sandbox

The sandbox store fires real ecommerce dataLayer events and loads your GTM container, so you can build the tag from this lesson against live events.

Open the sandbox
Ecommerce events, start to finish — Tracking Foundations · TagIntact