GA4's ecommerce model has a checkout funnel built in. Four events, in order, each carrying the same items array: begin_checkout, add_shipping_info, add_payment_info and purchase. When all four fire, the funnel exploration shows exactly where shoppers abandon. When only the first and last fire, which is the state most stores are in, the report shows a cliff with nothing in between.
What each event means
- begin_checkout fires when the shopper enters checkout, usually on the first checkout page or when the cart drawer's checkout button is clicked. It should carry the cart contents and value.
- add_shipping_info fires when the shopper submits a shipping method. Carry the chosen method in shipping_tier.
- add_payment_info fires when the shopper submits a payment method. Carry the method in payment_type.
- purchase fires once per order, with transaction_id, value, currency, tax, shipping and the items array.
The items array should be the same across all four. If the cart changes mid-checkout, send the current cart on each event, but do not drop the array on the middle two steps; the funnel exploration segments by item.
Why the middle events get skipped
On a hosted checkout such as Shopify's, the theme has no code running on the middle pages, so a theme-level dataLayer never sees them. The fix there is the customer events pixel, which exposes checkout_shipping_info_submitted and checkout_payment_info_submitted and can map them to the GA4 names.
On a custom checkout, the middle events are usually skipped because nobody asked for them. The purchase event got built because finance needed revenue; the step events had no owner.
What the funnel tells you when it works
- A big drop between begin_checkout and add_shipping_info usually means account creation friction or a surprise shipping cost.
- A drop between add_shipping_info and add_payment_info points at the shipping options themselves: too slow, too expensive, or not available to that region.
- A drop between add_payment_info and purchase is a payment failure problem, a fraud rule, or an express checkout that completes on a different path and is not being tracked.
That last case is worth repeating: a funnel that shows payment info submitted but no purchase is often a tracking gap, not a conversion problem.
Sending the events correctly
Push each event to the dataLayer before the corresponding GTM trigger fires, with the ecommerce object cleared first so stale items do not leak between events:
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: 'add_shipping_info',
ecommerce: {
currency: 'USD',
value: 86.00,
shipping_tier: 'Ground',
items: [{ item_id: 'SKU123', item_name: 'Trail jacket', price: 86.00, quantity: 1 }]
}
});
Use the same currency on every event. Mixed currencies in one funnel make the value columns meaningless.
Validating it
Open the GA4 funnel exploration, choose the four events as steps, and set it to closed funnel. Then place a test order on your own store and watch the step counts increment. If a step stays at zero, the event is not arriving with that name.
FAQ
Do I need all four checkout events in GA4?
For a revenue number, no, purchase alone is enough. For diagnosing where checkout loses people, yes. The middle two events are what make the funnel exploration useful.
Should the items array be the same on every checkout event?
Yes, unless the cart changed. The funnel exploration can segment by item, which only works if each step carries the items. Send the current cart on every step.
Why does my funnel show add_payment_info but very few purchases?
Check for an untracked checkout path first, especially express wallets. If every path is tracked, look at payment failures and fraud rules, which GA4 cannot see on its own.
The free audit at tageasy.io/check checks whether your purchase event carries revenue and whether your container has a GA4 purchase tag wired at all.