
GA 4 E-commerce Tracking Masterclass
Last week, we fixed the Critical 15 items that break GA4 for everyone.
This week? We're going deep on e-commerce tracking.
Here's why this matters:
When attribution is wrong by 30%, every decision you make is wrong:
❌ You kill profitable campaigns
❌ You scale unprofitable campaigns
❌ You can't calculate true ROAS
❌ Smart Bidding optimizes for the wrong conversions
Today, I'm showing you exactly how to track e-commerce correctly so you never lose another dollar.
🎯 What You’ll Learn Today
By the end of this post, you’ll know:
The complete e-commerce event flow (8 events from browse → purchase)
How to implement each event with code examples
Common mistakes that break revenue tracking
How to validate your tracking is working
Advanced tracking for cart abandonment and product performance
🛒 The Complete E-commerce Event Flow
Here’s the customer journey and which events to fire:
Product Discovery:
1. view_item_list (Category/Collection page)
2. select_item (Click on product)
3. view_item (Product detail page)
Shopping Cart:
4. add_to_cart (Add to cart button)
5. view_cart (Cart page)
Checkout Process:
6. begin_checkout (Start checkout)
7. add_payment_info (Payment method selected)
8. add_shipping_info (Shipping info entered)
Purchase:
9. purchase (Order completed) 🎯
Pro Tip: Implement in this order. Get purchase working first, then work backward.
💰 Event #1: Purchase (Start Here)
This is THE most important event. Get this wrong, and nothing else matters.
Implementation
// Fire on order confirmation page ONLYgtag('event', 'purchase', {
// REQUIRED FIELDS 'transaction_id': 'ORD_2025_12345', // Must be unique! 'value': 84.97, // Total revenue 'currency': 'USD', // ISO 4217 code // RECOMMENDED FIELDS 'tax': 5.00, // Tax amount 'shipping': 9.99, // Shipping cost 'coupon': 'SAVE20', // Coupon code used 'affiliation': 'Online Store', // Store name // ITEMS ARRAY (all products in order) 'items': [
{
'item_id': 'SKU_12345', // Product SKU 'item_name': 'Wireless Mouse', // Product name 'item_category': 'Electronics', // Primary category 'item_category2': 'Accessories', // Secondary category 'item_brand': 'Logitech', // Brand name 'price': 29.99, // Item price 'quantity': 2, // Quantity purchased 'item_variant': 'Black' // Color/size/variant }, {
'item_id': 'SKU_67890', 'item_name': 'USB-C Cable', 'item_category': 'Electronics', 'item_category2': 'Cables', 'item_brand': 'Anker', 'price': 14.99, 'quantity': 1 }
]
});
Critical Rules for Purchase Event
1. Transaction ID MUST Be Unique
// ❌ BAD: Static transaction ID'transaction_id': 'ORDER_12345'// ❌ BAD: Only timestamp (not unique across users)'transaction_id': Date.now().toString()
// ✅ GOOD: Use your database order ID'transaction_id': orderData.id // 'ORD_2025_12345'// ✅ GOOD: Generate unique ID'transaction_id': 'ORD_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)
Why This Matters: Duplicate transaction IDs cause GA4 to:
Deduplicate the revenue (losing transactions)
Or count duplicates (inflating revenue)
Break your ROAS calculations
2. Fire Purchase Event ONLY ONCE
// Prevent duplicate firing on page refreshvar purchaseTracked = sessionStorage.getItem('purchase_' + transactionId);if (!purchaseTracked) {
gtag('event', 'purchase', { /* data */ }); sessionStorage.setItem('purchase_' + transactionId, 'true');}
3. Value = Total Revenue (Including Tax + Shipping)
// Calculate correctlyvar itemsTotal = 59.97; // Sum of all item prices × quantitiesvar taxAmount = 5.00;var shippingCost = 9.99;var discount = 10.00; // If coupon appliedvar totalValue = itemsTotal + taxAmount + shippingCost - discount; // 64.96gtag('event', 'purchase', {
'transaction_id': 'ORD_12345', 'value': 64.96, // ✅ Total customer paid 'tax': 5.00, // Separate for reporting 'shipping': 9.99, // Separate for reporting 'items': [ /* ... */ ]
});
4. Currency Must Match Property Settings
// ✅ ALWAYS specify currencygtag('event', 'purchase', {
'currency': 'USD', // ISO 4217 code 'value': 99.99});// Common Currency Codes:// USD - US Dollar// EUR - Euro// GBP - British Pound// INR - Indian Rupee// AUD - Australian Dollar
🛍️ Event #2: Add to Cart
Fire when user clicks “Add to Cart” button.
document.getElementById('addToCartBtn').addEventListener('click', function() {
var product = getProductData(); // Your function to get product info gtag('event', 'add_to_cart', {
'currency': 'USD', 'value': product.price * product.quantity, 'items': [
{
'item_id': product.sku, 'item_name': product.name, 'item_category': product.category, 'item_brand': product.brand, 'price': product.price, 'quantity': product.quantity, 'item_variant': product.variant // e.g., "Large / Blue" }
]
});});
Pro Tip: Track add_to_cart vs purchase to calculate cart abandonment rate:
Cart Abandonment Rate = 1 - (Purchases ÷ Add to Carts)
Example:
- 1,000 add_to_cart events
- 250 purchase events
- Abandonment Rate = 1 - (250 ÷ 1,000) = 75%
🛒 Event #3: Begin Checkout
Fire when user clicks “Proceed to Checkout” or lands on checkout page.
// On checkout page loadwindow.addEventListener('load', function() {
if (window.location.pathname === '/checkout') {
var cartItems = getCartItems(); // Your function var cartTotal = calculateCartTotal(); // Your function gtag('event', 'begin_checkout', {
'currency': 'USD', 'value': cartTotal, 'coupon': getCouponCode(), // If applied 'items': cartItems
}); }
});
What to Track:
Total cart value at checkout start
Number of items
Whether coupon is applied
Why It Matters:
Measure checkout abandonment
Identify friction in checkout flow
Remarket to users who started but didn’t complete
📦 Event #4: View Item (Product Detail Page)
Fire when user lands on a product page.
// On product page loadgtag('event', 'view_item', {
'currency': 'USD', 'value': 29.99, // Product price 'items': [
{
'item_id': 'SKU_12345', 'item_name': 'Wireless Mouse', 'item_category': 'Electronics', 'item_category2': 'Accessories', 'item_brand': 'Logitech', 'price': 29.99, 'quantity': 1, // Default to 1 for view_item 'item_list_name': 'Related Products', // Where they came from 'item_list_id': 'related_products' }
]
});
Track This To:
See which products get the most views
Calculate view-to-purchase conversion rate
Identify products with high views but low conversions (pricing issue?)
📋 Event #5: View Item List (Category/Collection Page)
Fire when users see a list of products (category page, search results, homepage).
gtag('event', 'view_item_list', {
'item_list_id': 'category_electronics', 'item_list_name': 'Electronics', 'items': [
{
'item_id': 'SKU_12345', 'item_name': 'Wireless Mouse', 'item_category': 'Electronics', 'item_brand': 'Logitech', 'price': 29.99, 'index': 1 // Position in list (important!) }, {
'item_id': 'SKU_67890', 'item_name': 'USB-C Cable', 'item_category': 'Electronics', 'item_brand': 'Anker', 'price': 14.99, 'index': 2 }
// ... up to 200 items max ]
});
Pro Tip: Use index to track which position in list gets most clicks. Usually, positions 1-3 get 80% of clicks.
🖱️ Event #6: Select Item
Fire when user clicks on a product from a list.
// On product card clickdocument.querySelectorAll('.product-card').forEach(function(card, index) {
card.addEventListener('click', function() {
var product = getProductDataFromCard(this); gtag('event', 'select_item', {
'item_list_id': 'category_electronics', 'item_list_name': 'Electronics', 'items': [
{
'item_id': product.sku, 'item_name': product.name, 'item_category': product.category, 'item_brand': product.brand, 'price': product.price, 'index': index + 1 // Position clicked }
]
}); });});
Track This To:
See which products get clicked most
Identify high-click, low-conversion products
Optimize product positioning
💳 Event #7: Add Payment Info
Fire when user selects a payment method.
// When payment method radio button changesdocument.querySelectorAll('input[name="payment-method"]').forEach(function(radio) {
radio.addEventListener('change', function() {
gtag('event', 'add_payment_info', {
'currency': 'USD', 'value': calculateCartTotal(), 'coupon': getCouponCode(), 'payment_type': this.value, // 'credit_card', 'paypal', 'apple_pay' 'items': getCartItems()
}); });});
🚚 Event #8: Add Shipping Info
Fire when user enters shipping information.
// When shipping form is submitteddocument.getElementById('shippingForm').addEventListener('submit', function() {
gtag('event', 'add_shipping_info', {
'currency': 'USD', 'value': calculateCartTotal(), 'coupon': getCouponCode(), 'shipping_tier': getSelectedShippingMethod(), // 'standard', 'express' 'items': getCartItems()
});});
🗑️ Event #9: Remove from Cart
Fire when user removes item from cart.
function removeFromCart(item) {
gtag('event', 'remove_from_cart', {
'currency': 'USD', 'value': item.price * item.quantity, 'items': [
{
'item_id': item.sku, 'item_name': item.name, 'price': item.price, 'quantity': item.quantity }
]
});}
Why Track This:
Identify products often removed (quality issue?)
See if shipping cost causes removals
Track cart composition changes
🔄 Event #10: View Cart
Fire when user views their shopping cart.
// On cart page loadif (window.location.pathname === '/cart') {
gtag('event', 'view_cart', {
'currency': 'USD', 'value': calculateCartTotal(), 'items': getCartItems()
});}
⚠️ Common E-commerce Tracking Mistakes
Mistake #1: Including Tax/Shipping in Item Prices
// ❌ WRONG: Tax and shipping in item price'items': [{ 'item_id': 'SKU_12345', 'price': 35.00 // Includes tax + shipping}] // ✅ CORRECT: Item price only, tax/shipping separate'value': 35.00, // Total including tax + shipping'tax': 3.00, // Separate'shipping': 2.00, // Separate'items': [{ 'item_id': 'SKU_12345', 'price': 30.00 // Item price only}]
Mistake #2: Not Tracking Refunds
// When order is refundedgtag('event', 'refund', {
'transaction_id': 'ORD_2025_12345', // Original transaction ID 'value': 84.97, // Refund amount 'currency': 'USD', // Optional: Partial refund (specific items) 'items': [
{
'item_id': 'SKU_12345', 'item_name': 'Wireless Mouse', 'quantity': 1 }
]
});
Mistake #3: Firing Purchase on Cart Page
// ❌ WRONG: Purchase event on cart or checkout pageif (window.location.pathname === '/cart') {
gtag('event', 'purchase', { /* ... */ }); // NO!}
// ✅ CORRECT: Purchase ONLY on confirmation pageif (window.location.pathname === '/order-confirmation') {
gtag('event', 'purchase', { /* ... */ }); // YES!}
Mistake #4: Not Handling Quantity Correctly
// ❌ WRONG: Quantity not considered in value'value': 29.99, // Price for 1 item'items': [{
'price': 29.99, 'quantity': 3 // But ordered 3!}]
// ✅ CORRECT: Value includes quantity'value': 89.97, // 29.99 × 3'items': [{
'price': 29.99, 'quantity': 3}]
✅ Validating Your E-commerce Tracking
Step 1: Test Purchase in DebugView
1. Enable debug mode:
gtag('config', 'G-XXXXXXXXXX', {'debug_mode': true});
2. Make a test purchase
3. Check DebugView (Admin → DebugView):
- Look for 'purchase' event
- Verify transaction_id is present and unique
- Check all parameters are captured
- Confirm items array is populated correctly
Step 2: Verify in Real-Time Report
1. Reports → Real-time
2. Make a test purchase
3. Event should appear within 60 seconds
4. Check event count = 1 (not duplicate)
Step 3: Revenue Reconciliation
Do this monthly:
GA4 Revenue Check:
1. Reports → Monetization → Ecommerce purchases
2. Date range: Last month
3. Note total revenue
Payment Processor Check:
1. Stripe/PayPal/etc dashboard
2. Same date range
3. Note total revenue
Compare:
- Within 2-5% = Good (normal variance)
- >5% difference = Investigation needed
Common causes of mismatch:
- Refunds not tracked in GA4
- Test transactions not filtered
- Time zone differences
- Orders awaiting payment confirmation
🎯 Advanced E-commerce Tracking
Cart Abandonment Sequence
Track exactly when users abandon carts:
// Set cart sessionsessionStorage.setItem('cart_started', Date.now());// Track abandonment before user leaveswindow.addEventListener('beforeunload', function() {
var cartStarted = sessionStorage.getItem('cart_started'); var purchased = sessionStorage.getItem('purchase_completed'); if (cartStarted && !purchased) {
gtag('event', 'cart_abandoned', {
'cart_value': calculateCartTotal(), 'items_count': getCartItems().length, 'time_in_cart': Date.now() - cartStarted
}); }
});
Product Performance Analysis
Track which products convert best:
// Create custom metricfunction calculateProductConversionRate(productId) {
// In GA4 Exploration: // Metric = (purchase events / view_item events) × 100 // Filter: item_id = productId}
// Results tell you:// - High views + High purchases = Winner (promote more)// - High views + Low purchases = Pricing or quality issue// - Low views + High purchases = Hidden gem (improve visibility)// - Low views + Low purchases = Consider discontinuing
Revenue by Traffic Source
// Automatically captured with purchase event// View in GA4:// Reports → Monetization → Overview// Secondary dimension: Session source/medium// Shows which channels drive most revenue:// - google / cpc = $50,000// - facebook / cpc = $35,000// - organic = $25,000// - email = $15,000
📊 E-commerce Reports to Monitor Weekly
1. Ecommerce Purchases Report
Reports → Monetization → Ecommerce purchases
Track:
- Total revenue trend
- Average order value (AOV)
- Items per purchase
- Top products by revenue
2. Checkout Funnel
Explore → Funnel exploration
Steps:
1. view_item (100% - baseline)
2. add_to_cart (40% - 60% typical)
3. begin_checkout (25% - 35% typical)
4. purchase (15% - 25% typical)
Identify biggest drop-off point and fix it.
3. Product Performance
Reports → Monetization → Ecommerce purchases
Add: item_name dimension
Metrics to watch:
- Total revenue per product
- Quantity sold
- Average price
- Revenue contribution %
🛠️ Implementation Checklist
Phase 1: Core Events (Week 1)
[ ] Purchase event implemented
[ ] Transaction IDs are unique
[ ] Purchase fires only once
[ ] Revenue reconciliation within 5%
[ ] All required parameters included
Phase 2: Cart Events (Week 2)
[ ] add_to_cart tracking
[ ] remove_from_cart tracking
[ ] view_cart tracking
[ ] begin_checkout tracking
Phase 3: Discovery Events (Week 3)
[ ] view_item tracking
[ ] view_item_list tracking
[ ] select_item tracking
Phase 4: Advanced (Week 4)
[ ] add_payment_info tracking
[ ] add_shipping_info tracking
[ ] refund tracking
[ ] Cart abandonment tracking
[ ] Checkout funnel exploration created
📥 Download Week 2 Resources
E-commerce Tracking Checklist (CSV)
🚀 Next Week Preview
Week 3: Privacy-First Analytics - GDPR, Consent Mode v2, and GA4
With new EU regulations (March 2024 deadline), you NEED to:
Implement Consent Mode v2 correctly
Avoid €20M GDPR fines
Keep Google Ads campaigns running in EU
Can’t wait? Reply with “PRIVACY” for early access.
About This Series:
This is Week 2 of our 4-week GA4 Audit Series:
✅ Week 1: GA4 Audit Essentials
✅ Week 2: E-commerce Tracking (You are here)
Week 3: Privacy-First Analytics
Week 4: Advanced GA4 Features
The AI Driven Marketer Helping digital marketers leverage AI and automation to work smarter, not harder.

