Loading tutorials…
Loading tutorials…
Ecommerce tracking in GA4 isn't optional — it's the foundation of every revenue report, ROAS calculation, and ad-platform optimization decision. Done right it pays back forever. Done wrong it produces numbers that everyone in the org argues about for months.
Who this is forOwners of ecommerce stores (Shopify, WooCommerce, BigCommerce, Magento, or custom-built) who need full-funnel revenue tracking in GA4. If your monthly revenue is $20K+ and your GA4 revenue doesn't match Shopify within 10%, this tutorial pays back in a single ad-campaign decision.
What you'll need
Step 1
GA4 expects a specific event + parameter structure. Memorize it: purchase, view_item, add_to_cart, begin_checkout, add_payment_info, view_cart.
GA4 has 12 recommended ecommerce events. The 6 you must fire: view_item (product detail page), add_to_cart, view_cart (cart page), begin_checkout (start of checkout), add_payment_info (payment step), purchase (order complete).
Optional but valuable: select_item (clicking a product in a list), view_item_list (PLP impressions), remove_from_cart, add_shipping_info, refund (for processed refunds), purchase_completed (server-side variant).
Every ecommerce event takes the same item array structure: items: [{item_id, item_name, price, quantity, item_brand, item_category, item_variant, currency}].
Currency must be set at the event level (or in items) using ISO 4217 codes (USD, EUR, GBP, CAD). Without it, GA4 can't aggregate revenue across multi-currency stores.
Transaction_id on purchase events must be unique — duplicate transaction_ids cause GA4 to deduplicate (lose) revenue.
Step 2
Shopify (Google channel) and WooCommerce (Kliken plugin / Site Kit / Tatvic) handle this for you. Custom sites need manual dataLayer pushes.
Shopify: install the Google & YouTube channel + use Customer Events for checkout. See the Install GA4 on Shopify tutorial. The channel handles all 6 core events.
WooCommerce: install Site Kit by Google (free, official) OR a dedicated GA4 ecommerce plugin (Tatvic, GTM4WP). These push the standard dataLayer structure automatically.
BigCommerce: native GA4 integration under Settings → Analytics → Google Analytics. Connect your property and BigCommerce handles the events.
Magento 2: use Tatvic's GA4 module or the Magento Marketplace GA4 extension.
Custom site: your developer pushes events to the dataLayer at each step. We'll cover this in the next step.
Step 3
At each ecommerce step, push the appropriate event with the items array. Then GTM fires GA4 Event tags that listen for those pushes.
On a product page: window.dataLayer = window.dataLayer || []; dataLayer.push({event: 'view_item', ecommerce: {currency: 'USD', value: 29.99, items: [{item_id: 'SKU123', item_name: 'Blue T-Shirt', price: 29.99, quantity: 1}]}})
On add-to-cart button click: dataLayer.push({event: 'add_to_cart', ecommerce: {currency: 'USD', value: 29.99, items: [{item_id: 'SKU123', ...}]}})
On cart page load: dataLayer.push({event: 'view_cart', ecommerce: {currency: 'USD', value: total_cart_value, items: [...full cart...]}})
On checkout start: dataLayer.push({event: 'begin_checkout', ...})
On order confirmation page: dataLayer.push({event: 'purchase', ecommerce: {transaction_id: 'ORDER_12345', currency: 'USD', value: 89.97, tax: 7.20, shipping: 5.00, coupon: 'SUMMER10', items: [...]}})
Always push to dataLayer BEFORE the page renders the GTM container or with a manual GTM Custom Event trigger. Order matters.
Step 4
For each event, GTM needs a Custom Event trigger + a GA4 Event tag with the right parameters mapped from Data Layer Variables.
In GTM → Triggers → New → Custom Event. Event name = purchase (or view_item, add_to_cart, etc.). Save.
In GTM → Variables → User-Defined Variables → New → Data Layer Variable. Create one variable per ecommerce parameter you need: ecommerce.transaction_id (DLV - transaction_id), ecommerce.value, ecommerce.currency, ecommerce.items.
In GTM → Tags → New → Google Analytics: GA4 Event. Configuration Tag = your main Google Tag. Event Name = purchase. Add event parameters: transaction_id = {{DLV - transaction_id}}, value = {{DLV - value}}, currency = {{DLV - currency}}, items = {{DLV - items}}, tax = {{DLV - tax}}, shipping = {{DLV - shipping}}.
Trigger = the Custom Event trigger you created.
Repeat for every ecommerce event. Yes, this is 6+ tags. Yes, it's the right way.
Step 5
The items array is the heart of ecommerce tracking. Every item needs item_id (SKU), item_name (string), price (number), and quantity (integer).
item_id must be a string and unique per product variant. For Shopify, this is the variant ID, not the product ID — variants matter for color/size analytics.
item_name is a string product title. Do not use numbers or arrays here.
price is a number, not a string. dataLayer.push({...price: 29.99...}) — not "29.99" with quotes.
quantity is an integer. dataLayer.push({...quantity: 2...}) — not "2".
Optional but valuable: item_brand, item_category (top category), item_category2/3/4/5 (subcategories), item_variant (color, size), item_list_name (which PLP they came from).
Use the schema consistently across all events. If view_item shows item_id as a string but purchase shows it as a number, GA4 deduplicates incorrectly and revenue reports break.
Step 6
Run a full purchase funnel test. Watch every event fire in DebugView with correct parameters.
Open GA4 → Admin → DebugView in one tab.
In a separate incognito tab (no ad blockers), visit your site, click a product, add to cart, view cart, start checkout, complete a real test purchase.
In DebugView, you should see this sequence: page_view → view_item → add_to_cart → view_cart → begin_checkout → add_payment_info → purchase.
Click the purchase event. Verify: transaction_id is set, value is set and correct, currency is set, items array has all line items with item_id/item_name/price/quantity populated.
If anything is "(not set)" or missing, fix the dataLayer push or the DLV mapping before continuing. Never publish broken ecommerce events to production.
Step 7
GA4 → Admin → Events → toggle Mark as Key Event on purchase. Then compare GA4 revenue to Shopify/Stripe weekly for 30 days.
In GA4 → Admin → Events, mark purchase as a Key Event. This is required for Google Ads import and for Smart Bidding signal.
Optionally mark begin_checkout as a Key Event too — useful for tracking checkout abandonment in ad reports.
Set a weekly calendar reminder for the next 30 days: compare GA4 Reports → Monetization → Revenue against your Shopify/Stripe revenue dashboard.
Expect a 3-10% gap (consent rejection, ad blockers, ITP). A gap of 15%+ means something is misconfigured.
If revenue matches but item counts don't, your items array has issues. If transaction count matches but revenue is off, your value parameter is wrong on some events.
Common mistakes
Item array with wrong data types
What goes wrong: price as a string ('29.99'), quantity as a string ('2'), or item_id as a number. GA4 parses the event but item-level reports show (not set) or null. You can't break down revenue by product.
How to avoid: Always: item_id = string, item_name = string, price = number (not string), quantity = integer (not string). Test with DebugView and inspect each parameter type.
Duplicate transaction_id values
What goes wrong: Same transaction_id fires twice (browser refresh, server retry). GA4 deduplicates by transaction_id and you lose one of the purchases. Revenue under-reports.
How to avoid: Ensure transaction_id is the actual order ID and only fires on the order confirmation page (not on cart pages). If you suspect duplicates, audit DebugView for consecutive purchase events with the same ID.
Missing currency parameter
What goes wrong: GA4 silently drops the revenue value when currency is missing. Purchase event fires, items array looks right, but value shows $0 in all reports. Most damaging in multi-currency stores.
How to avoid: Always include currency on every ecommerce event. Use ISO 4217 codes: USD, EUR, GBP, CAD, AUD. Set it at the event level OR within each item.
Firing events from the wrong page
What goes wrong: purchase fires on the cart page instead of the order confirmation page. Every cart view counts as a sale. Revenue inflates 5-10x. Smart Bidding optimizes toward inflated targets.
How to avoid: Audit your dataLayer push triggers. purchase should ONLY fire on the post-payment confirmation page. add_to_cart only fires on the cart-add action. Each event has a specific lifecycle moment.
Not testing refund events
What goes wrong: Returns happen but never sync back to GA4. Revenue stays inflated for refunded orders. ROAS reports overstate ad effectiveness.
How to avoid: Fire a refund event when an order is refunded: dataLayer.push({event: 'refund', ecommerce: {transaction_id: '...', value: 50.00, currency: 'USD'}}). For partial refunds, include the items array with quantities being refunded.
Mixing the legacy UA ecommerce schema with GA4
What goes wrong: Old UA installs pushed events like productClick with different parameter names. If you migrated from UA without updating the dataLayer, GA4 receives garbage events. Reports show zero ecommerce activity despite the events firing.
How to avoid: Rewrite all dataLayer pushes to use GA4's recommended ecommerce schema. The migration is one-time pain but required — there's no compatibility layer.
Recap
Done — what's next
How to install GA4 on Shopify the right way
Read the next tutorial
Hand it off
Ecommerce tracking in GA4 is the foundation of every revenue decision, ad attribution, and ROAS calculation. Done wrong it pollutes everything for months. A vetted GA4 + ecommerce specialist on EverestX typically charges $500-1,500 for a complete ecommerce setup including platform integration, GTM events, ad-platform sync, and 30 days of reconciliation — at $14-16/hr.
See specialist rates
Three usual causes: (1) consent rejection — EEA users who decline tracking are excluded from GA4, typically 5-15% of EU traffic; (2) ad blockers and Safari ITP strip the GA4 pixel, typically 3-8% of traffic; (3) the purchase event fails to fire on some checkout completions due to JS errors or slow page loads. A 3-10% gap is normal; 15%+ means something is broken.
GA4 has ecommerce events built-in but does not fire them automatically. You still need to push the events from your site (via platform integration like Shopify's Google channel, or via manual dataLayer pushes through GTM). The "Enhanced Ecommerce" term is from Universal Analytics; in GA4 it's just called "Ecommerce events."
Yes if you use a platform that has native GA4 ecommerce support — Shopify Google channel, BigCommerce GA4 integration, WooCommerce Site Kit. For custom sites, GTM is strongly recommended because it lets you manage event firing without code deploys.
item_id is the GA4 parameter name for the unique identifier. product_id is the legacy UA name. Use item_id in all GA4 events. For Shopify stores, item_id should be the variant ID (not product ID) so you can analyze sales by color/size.
Fire a purchase event on initial signup with the first payment amount. Fire additional purchase events on each renewal (recurring billing webhook from Stripe/Recharge → server-side GA4 event). Use a custom parameter like subscription_status: "renewal" vs "new" to differentiate in reports.
Google Analytics 4
Shopify's native Google channel app is now the right way to install GA4 — not the old liquid-snippet hacks that haunt half the tutorials online. Here's the current, supported path.
Google Analytics 4
GTM is the right install path for any site that runs more than one tracking pixel. It's also where most DIY installs go sideways — wrong trigger, wrong variable, wrong fire order. Here's the path that actually works.
Google Analytics 4
GA4 renamed Conversions to Key Events in late 2024. The name change matters less than what most owners get wrong: marking too many things as Key Events, which destroys Smart Bidding and inflates every report.
Google Analytics 4
Linking these two correctly is what makes Google's stack actually function as a stack. Done wrong, you'll have two systems that disagree about reality for years. Here's the right setup, in order.