Most e-commerce stores that “have GA4” are tracking less than half their actual revenue. Out-of-the-box GA4 misses add-to-cart events, fires purchase events twice, and collapses all your product data into a single blob. This guide fixes that.
Prerequisites
Before you start, confirm you have:
- A GA4 property created (not Universal Analytics — UA is retired)
- Google Tag Manager installed on your site
- Admin access to both GA4 and GTM
- A test transaction you can trigger
Step 1: Enable Enhanced E-commerce in GA4
GA4 doesn’t “enable” enhanced e-commerce the way Universal Analytics did — it’s event-based by default. But you do need to mark your events correctly.
In GA4 Admin → Events, confirm you see events firing. If you only see page_view and session_start, your e-commerce implementation is missing.
The seven purchase funnel events GA4 expects:
| Event | When It Fires |
|---|---|
view_item_list | Category/search results page |
view_item | Product detail page |
add_to_cart | Add to cart button click |
remove_from_cart | Remove from cart |
begin_checkout | Checkout step 1 |
add_payment_info | Payment info entered |
purchase | Order confirmation page |
Step 2: The Data Layer Push Pattern
Every event needs to push structured data to window.dataLayer before GTM fires the GA4 tag. Here’s the correct structure:
Product View Event
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null }); // Clear previous ecommerce data!
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'USD',
value: 49.99,
items: [{
item_id: 'SKU_12345',
item_name: 'Classic Leather Wallet',
item_category: 'Accessories',
item_brand: 'YourBrand',
price: 49.99,
quantity: 1
}]
}
});
Purchase Event (The Most Critical One)
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'T-1234567', // Must be unique per order
value: 99.98,
tax: 8.00,
shipping: 5.99,
currency: 'USD',
coupon: 'SUMMER20',
items: [
{
item_id: 'SKU_12345',
item_name: 'Classic Leather Wallet',
item_category: 'Accessories',
price: 49.99,
quantity: 2
}
]
}
});
Critical: Always push { ecommerce: null } before each ecommerce event. Without this, GTM’s Data Layer Variables will carry values from the previous event and corrupt your data.
Step 3: Configure GTM Tags
In Google Tag Manager:
-
Create a Data Layer Variable for each ecommerce field you need:
DLV - ecommerce.transaction_id→ Data Layer Variable name:ecommerce.transaction_idDLV - ecommerce.value→ecommerce.valueDLV - ecommerce.items→ecommerce.items
-
Create a GA4 Event tag:
- Tag type: Google Analytics: GA4 Event
- Configuration tag: Your GA4 Config tag (the one with your Measurement ID)
- Event name:
{{DLV - event}}(or hardcodepurchasefor the purchase tag) - Under E-commerce, check “Send Ecommerce data” and select “Data Layer”
-
Create a trigger for each ecommerce event:
- Trigger type: Custom Event
- Event name:
purchase(for the purchase tag)
Step 4: Implement Consent Mode v2
This is now required for EU traffic and Google’s Enhanced Conversions to work. Add this snippet before your GTM container loads:
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Default all consent to denied (for EU/GDPR compliance)
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'wait_for_update': 500
});
</script>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
When your consent banner is accepted, update consent:
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted'
});
Step 5: Validate Your Setup
Use GA4’s DebugView (Admin → DebugView) alongside the Tag Assistant Chrome extension.
Checklist:
-
purchaseevent fires once per order (not on every page refresh) -
transaction_idis unique per order -
valuematches the actual order total (not including tax/shipping unless intended) -
currencyis present (missing currency = data discarded silently) -
itemsarray contains at least one item withitem_idandprice
Common Mistakes That Destroy Your Data
Double-firing the purchase event: If your thank-you page uses both a hardcoded GA4 tag AND a GTM tag, you’ll count every purchase twice. Audit your page source.
Item ID vs Item Name mismatch: GA4 joins item_id and item_name to build item reports. Using different IDs across events breaks this join.
Missing currency parameter: GA4 silently drops events without currency. Your revenue reports will undercount without any warning.
Not clearing ecommerce before each push: Without window.dataLayer.push({ ecommerce: null }), your data layer accumulates values from previous events.
What to Build Next
Once purchase tracking is clean:
- Connect BigQuery export (GA4 Admin → BigQuery Linking) for raw event data
- Build a Looker Studio dashboard with purchase funnel visualization
- Set up GA4 audiences based on purchase behavior for remarketing
Need help getting your GA4 e-commerce tracking set up correctly? Get in touch with our team — we’ve configured tracking for hundreds of stores across Shopify, WooCommerce, and custom platforms.