Skip to main content
ga4analyticstrackingga4-auditecommerceshopify

GA4 Ecommerce Events: Full List, Parameters and Fixes

Thirteen of GA4's ecommerce events describe the path to a sale. The fourteenth, purchase, is the one your revenue reports, ROAS and ad bidding read, and the one where a duplicate, an empty ID or a missing currency does the most damage.

Founder & CEO, Marketing Bar
25 min read
GA4 purchase event dataLayer example with transaction_id, value, currency and items, after clearing the previous ecommerce object.

GA4 ecommerce events are 14 recommended events that track a shopper from product list to refund: view_item_list, select_item, view_item, add_to_wishlist, add_to_cart, remove_from_cart, view_cart, begin_checkout, add_shipping_info, add_payment_info, purchase, refund, plus view_promotion and select_promotion. Twelve of them require an items array; for select_promotion and refund it is optional. Only purchase adds revenue (refund subtracts it), and it needs four fields to do that correctly: transaction_id, value, currency and items.

Names and parameters are checked against Google's GA4 ecommerce measurement guide and the recommended events reference (Google for Developers, 2026).

TL;DR

Key takeaways

  • GA4 has 14 recommended ecommerce events. Twelve require an items array; each item needs item_id or item_name.
  • purchase requires transaction_id, items, and value with currency. Google says to set value to the sum of price × quantity and leave out shipping and tax.
  • GA4 deduplicates purchases with the same transaction_id, but only for web streams, and an empty string ID makes GA4 collapse every purchase that carries it.
  • Most duplicate purchases follow one pattern in GA4 and ad platforms alike: the same order reaches a report through two signals. In one Meta account we checked, summing one purchase across five event names inflated ROAS from 2.53× to 12.63×.
  • Validate in DebugView first, then run a BigQuery query for repeated transaction_id values.

What are GA4 ecommerce events?

They are a subset of GA4's recommended events: names and parameters Google predefines so the Monetization reports can read them. GA4 does not collect them automatically; you send them through gtag.js, Google Tag Manager, or a platform integration. Use the exact names: order_complete or checkout_success arrive as custom events and the ecommerce reports ignore them.

The full list of GA4 ecommerce events, in funnel order

Flow of GA4 ecommerce events in six stages: browse (view_item_list, select_item, view_promotion, select_promotion), product (view_item, add_to_wishlist), cart (add_to_cart, remove_from_cart, view_cart), checkout (begin_checkout, add_shipping_info, add_payment_info), purchase, refund.

14 events, six stages; purchase is the only one that adds revenue. Source: Google for Developers, GA4 ecommerce guide, 2026.

StageEventRequired event-level params
Browseview_item_listitems
Browseselect_itemitems
Browseview_promotionitems
Browseselect_promotionnone (items optional)
Productview_itemitems; value + currency
Productadd_to_wishlistitems; value + currency
Cartadd_to_cartitems; value + currency
Cartremove_from_cartitems; value + currency
Cartview_cartitems; value + currency
Checkoutbegin_checkoutitems; value + currency
Checkoutadd_shipping_infoitems; value + currency
Checkoutadd_payment_infoitems; value + currency
Purchasepurchasetransaction_id, items; value + currency
Refundrefundtransaction_id; value + currency

Google marks value and currency as "Yes*": value "is typically required for meaningful reporting," and "if you set value then currency is required for revenue metrics to be computed accurately." Treat the pair as required on every event that has a price.

Required parameters for the key events

Comparison table of required parameters: every event needs items except refund; value and currency are required from view_item through refund; only purchase and refund require transaction_id.

Of these nine events, only purchase and refund need transaction_id, and refund is the only one where items are optional. Source: Google for Developers, recommended events reference, 2026.

Useful optional parameters: coupon from begin_checkout on, shipping_tier and payment_type on the two checkout steps, and tax, shipping and customer_type (new or returning) on purchase. items is optional on refund, but Google recommends including it "to see item-level refund metrics in Analytics"; the refund itself is tied to the order by transaction_id.

Where these events show up in GA4

ReportBuilt from
Monetization overviewPurchase revenue and purchases across all ecommerce events
Ecommerce purchasesItem-level views, add-to-carts and purchases, from items
Purchase journeyview_item → add_to_cart → begin_checkout → purchase
Checkout journeybegin_checkout → add_shipping_info → add_payment_info → purchase
Promotionsview_promotion, select_promotion
Order couponscoupon on purchase

The report list comes from Google Analytics Help. purchase is also a key event by default for web and app (Google Analytics Help). A missing checkout step leaves a hole in the Checkout journey even when revenue looks right.

The GA4 items array

items is an array of product objects. The rules from Google's reference:

  • One of item_id or item_name is required in each item. Send both: the ID joins to your catalog and ad feeds, the name makes reports readable.
  • price is the unit price after discount. "If a discount applies to the item, set price to the discounted unit price and specify the unit price discount in the discount parameter."
  • quantity is the number of units. Event-level value should equal the sum of price × quantity.
  • Optional: item_brand, item_category to item_category5, item_variant, item_list_name, index, coupon, discount and others.
  • Limits: up to 200 items per event and up to 27 custom item parameters.

Keep item_id identical to the ID in your product feed. If GA4 says SKU-123 and your Google Shopping feed says shopify_US_123_456, item reports and feed data never join.

A correct GA4 purchase event (dataLayer example)

For Google Tag Manager, push the purchase on the order confirmation page, once per order. This follows Google's GTM example, with the items filled in:

dataLayer.push({ ecommerce: null });  // clear the previous ecommerce object
dataLayer.push({
  event: "purchase",
  ecommerce: {
    transaction_id: "100482",      // your order number; unique, never empty
    value: 64.00,                  // sum of price x quantity; no tax, no shipping
    tax: 5.12,
    shipping: 5.99,
    currency: "USD",               // ISO 4217, required when value is set
    coupon: "FALL10",
    customer_type: "new",
    items: [
      {
        item_id: "SKU-1042",
        item_name: "Merino Crew Sock",
        item_brand: "Example Brand",
        item_category: "Socks",
        item_variant: "Charcoal / M",
        price: 16.00,              // unit price after discount
        discount: 2.00,            // unit discount
        quantity: 2
      },
      {
        item_id: "SKU-2210",
        item_name: "Wool Beanie",
        item_category: "Hats",
        price: 32.00,
        quantity: 1
      }
    ]
  }
});

Illustrative numbers. 2 × $16 + 1 × $32 = $64, so value is 64.00, with tax and shipping in their own fields. In GTM, the GA4 Event tag uses {{Event}} as its name with Send Ecommerce data checked and Data Layer as the source.

Common mistakes that break GA4 ecommerce reports

Start from what looks wrong in GA4 and work back:

Symptom in GA4CauseFix
Purchases higher than orders in Shopify or your backendTwo sources send purchase and they disagree on the ID (checkout token vs order number, order name #1042 vs numeric ID) or one sends none; or purchase comes through a stream GA4 does not deduplicateOne purchase source per property; real order number as transaction_id
Purchases far lower than orders, many collapsed into onetransaction_id sent as "" or as a hard-coded valuePass the dynamic order ID; never an empty string
Purchases counted, revenue 0 or wrongvalue sent without currency, or value as a string with a currency symbolNumeric value, ISO currency on every event with a value
"(not set)" item namesItems lack item_name / item_idSend both in every item
No item rows at allItems sent under another key (products)Put products in items
Purchases dated days after the orderPurchase fires on every load of the thank-you page (reloads, bookmarks, order-status links) and the ID is missing or regenerated, so GA4 cannot deduplicateFire once per order: flag the order ID in storage, or render the push only on first view
Revenue off from the backend by a varying marginTax and shipping inside value on some paths, excluded on othersvalue = price × quantity; tax and shipping in their own fields on every path
Ecommerce events carry the previous push's items, or arrive under UA namesNo ecommerce: null clear between pushes on the same page; legacy UA event names (addToCart) passed through {{Event}} become custom events, and UA fields translate only partiallyClear before each push; rebuild the dataLayer to GA4 event names and the GA4 items schema
Revenue gap grows after a cookie banner launchPurchase push fires before the consent platform restores saved consent, so the tag is blocked on that trigger; or basic mode drops all pre-consent hitsSet default consent before any tag; fire purchase on a trigger that runs after consent is restored; choose basic vs advanced mode deliberately

On value, Google is explicit: "Don't include shipping or tax"; the damage comes from mixing conventions, such as subtotal from the storefront and total from a subscription app. A thank-you reload is harmless only while the ID is stable, and ad-platform tags on the same trigger may count it anyway, so fire once per order.

Missing or duplicate transaction_id

Google's ecommerce help states that GA4 "will deduplicate purchases if 2 purchases are registered with the same transaction ID," that this "only works for data collected through web streams, not app streams," and that you should not send an empty string because GA4 "will deduplicate all purchase events that have transaction_id=""" (Google Analytics Help, 2026). Google does not document a time window for transaction_id deduplication, and it applies only to web streams; treat it as a backstop, not a fix.

Under basic consent mode, tags are "blocked until user interaction with a consent banner" and "no data is sent before a user consents." Under advanced mode, tags load with consent denied and send cookieless measurements for modeling (Google for Developers, consent mode, 2026). If the purchase push fires before your consent platform restores a returning customer's saved choice, a tag that requires analytics_storage is blocked on that trigger and GTM does not re-fire it later; the purchase is simply missing. Setting the default after tags fire causes the opposite problem: tags run with no consent state at all. Check the confirmation page specifically; it is often a different template from the rest of the site.

The duplicate-purchase lesson from ad platforms

In one anonymized DTC brand's Meta Ads account connected to Level, our reporting tool, Meta returned each website purchase under five event names with identical values, and summing them gave a ROAS of 12.63× against a real 2.53×. In the same brand's Google Ads account, an old and a new purchase action overlapped for about two weeks during a migration and counted those orders twice. The GA4 version is the same mistake, and the rule carries over: one order, one purchase signal per destination, keyed by the order number (full breakdown in our ROAS formula article; for Meta pixel and CAPI deduplication, see our Meta CAPI for Shopify guide).

How to validate GA4 ecommerce events

  1. Tag Assistant. Walk the funnel in Tag Assistant; confirm each event's name, items, and a numeric value with currency.
  2. DebugView. In GA4 Admin → DebugView, open purchase and check transaction_id and value.
  3. Reload test. Refresh the confirmation page twice. DebugView should not show three purchases from your tags.
  4. Reconcile. Compare a week of GA4 purchases and revenue with backend orders. Our GA4 audit checklist puts this reconciliation first.
  5. BigQuery. With the export linked, query raw events for repeated or empty transaction IDs.

BigQuery query for duplicate transaction_ids

Replace the project and dataset with your own (analytics_ followed by your property ID):

-- Purchase events per transaction_id, last 30 days
SELECT
  ecommerce.transaction_id                   AS transaction_id,
  COUNT(*)                                   AS purchase_events,
  COUNT(DISTINCT user_pseudo_id)             AS users,
  SUM(ecommerce.purchase_revenue)            AS revenue_summed,
  MIN(TIMESTAMP_MICROS(event_timestamp))     AS first_seen,
  MAX(TIMESTAMP_MICROS(event_timestamp))     AS last_seen
FROM `your-project.analytics_123456789.events_*`
WHERE _TABLE_SUFFIX BETWEEN
        FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
    AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())
  AND event_name = 'purchase'
GROUP BY transaction_id
HAVING COUNT(*) > 1
    OR transaction_id IS NULL
    OR transaction_id IN ('', '(not set)')
ORDER BY purchase_events DESC;

Today's data sits in events_intraday_* and is excluded; dates are in UTC suffix order, not your property timezone. The export holds events as collected, and Google does not document applying transaction_id deduplication to it, which is why duplicates can show up here even when GA4 reports look right.

Two events minutes apart point to reloads or two tags; dozens across many users point to a hard-coded or empty ID. A NULL or (not set) row with a large count means purchases GA4 cannot deduplicate at all.

GA4 ecommerce tracking on Shopify

Shopify connects GA4 through its Google & YouTube app, which tracks "certain ecommerce events" automatically (Shopify Help Center). According to PPC Land (2026), Google began sending Shopify purchases to GA4 server-to-server in July 2026, deduplicated by transaction ID, and the same report quotes Littledata's founder: only the purchase is server-side, the other events remain browser-based. Per that report, the app now sends page_view, view_item, add_to_cart, begin_checkout, purchase, and since August 17, 2026 also view_item_list, remove_from_cart, view_cart and add_shipping_info; add_payment_info and refund are not in that list.

What that means in practice:

  • Pick one purchase source. If the app sends purchases, do not also send them from GTM or a custom pixel to the same property.
  • Storefront and checkout need different routes. Storefront events the app does not send (select_item, the promotion events, add_to_wishlist) can come from theme code or GTM in the theme. Checkout events such as add_payment_info can only come through Shopify's Customer Events: an app pixel or a custom pixel subscribed to payment_info_submitted. Since Shopify's checkout extensibility upgrade, checkout, thank-you and order status pages run no theme code and no Additional Scripts: Additional Scripts became view-only on August 28, 2025, and August 26, 2026 was the deadline for non-Plus stores to upgrade those pages (Shopify Help Center). Custom pixels run in a sandboxed iframe, so GTM's preview mode does not work inside them and page_location must be set explicitly.
  • refund does not come from the browser. Send it server-side (Measurement Protocol or a connector) with the original transaction_id.
  • Check what actually arrives. Shopify's Google app changed how purchase is sent (July 2026) and which events it sends (August 2026). Run DebugView on your own store before assuming any event is or is not sent.

You cannot see where checkout loses people if add_shipping_info never fires; our Shopify conversion rate optimization guide uses these steps as its funnel.

How we got these numbers

Event names, parameters, limits and report names come from Google's documentation, read on 2026-10-07; quotes are verbatim. Shopify behavior comes from Shopify's help center and PPC Land (August 2026), not confirmed on a live store. The ad-platform figures come from one anonymized DTC brand's accounts in Level, Q3 2026, as each API reported them; one account is an example, not a benchmark.

If you want this set up and reconciled against your backend, that is our GA4 and tracking setup service.

FAQ

Written by

Founder & CEO, Marketing Bar

Built Marketing Bar in LA after a decade in performance and analytics. Sets agency strategy, owns every client outcome, and keeps the bar high.

Share