WooCommerce + GA4 E-commerce Tracking | Blue Frog Docs

WooCommerce + GA4 E-commerce Tracking

Implement complete e-commerce tracking for WooCommerce stores with GA4 enhanced measurement

WooCommerce + GA4 E-commerce Tracking

Comprehensive guide to tracking WooCommerce transactions, product performance, and customer behavior with Google Analytics 4.

Overview

WooCommerce is WordPress's leading e-commerce plugin with 5+ million active installations. Proper GA4 integration enables:

  • Product performance analysis (views, add-to-cart rates, revenue)
  • Customer journey tracking (browse → cart → checkout → purchase)
  • Revenue attribution (traffic sources, campaigns, channels)
  • Conversion funnel optimization (checkout abandonment, payment failures)

Implementation Methods

Method 1: MonsterInsights Enhanced E-commerce (Easiest)

Best for: Non-technical users, quick setup, automatic tracking

Setup Steps

  1. Install MonsterInsights Pro

    • Purchase MonsterInsights Pro license ($199.50+/year)
    • Install and activate plugin
    • Connect to Google Analytics account
  2. Enable E-commerce Addon

    • Navigate to Insights → Addons
    • Activate Enhanced Ecommerce
    • Click Settings
  3. Configure E-commerce Settings

    Insights → Settings → eCommerce
    
    ✓ Enable Enhanced Ecommerce Tracking
    ✓ Use Measurement Protocol API (for server-side tracking)
    ✓ Enable Automatic Product Impressions
    ✓ Enable Add to Cart Tracking
    ✓ Enable Checkout Step Tracking
    ✓ Enable Transaction Tracking
    
  4. Verify in GA4

    • Go to GA4 → Reports → Monetization → E-commerce purchases
    • Make a test purchase
    • Confirm transaction appears

What MonsterInsights Tracks Automatically

// Product Impressions (shop pages, archives)
view_item_list

// Product Detail Views
view_item

// Add to Cart
add_to_cart

// Remove from Cart
remove_from_cart

// Begin Checkout
begin_checkout

// Purchase
purchase

MonsterInsights Limitations

  • Annual subscription cost
  • Limited customization options
  • May track duplicate events if custom code exists
  • Performance overhead from plugin

Method 2: Official WooCommerce Google Analytics Integration

Best for: Users wanting official WooCommerce extension

  1. Install WooCommerce Google Analytics Integration

    • WooCommerce → Extensions
    • Search "Google Analytics"
    • Purchase/Install WooCommerce Google Analytics ($79/year)
  2. Configuration

    WooCommerce → Settings → Integration → Google Analytics
    
    Google Analytics Tracking ID: G-XXXXXXXXXX
    ✓ Enable Enhanced E-commerce Tracking
    ✓ Track Add to Cart
    ✓ Track Remove from Cart
    ✓ Track Product Impressions
    □ Track logged-in administrators (disable)
    
  3. Advanced Settings

Method 3: Manual Implementation (Full Control)

Best for: Developers, custom requirements, performance optimization

Step 1: Track Product Impressions

// Add to functions.php or custom plugin
add_action('woocommerce_after_shop_loop_item', 'track_product_impression');
function track_product_impression() {
    global $product;
    ?>
    <script>
        gtag('event', 'view_item_list', {
            'items': [{
                'item_id': '<?php echo esc_js($product->get_sku() ?: $product->get_id()); ?>',
                'item_name': '<?php echo esc_js($product->get_name()); ?>',
                'item_category': '<?php echo esc_js(wp_strip_all_tags(wc_get_product_category_list($product->get_id()))); ?>',
                'item_brand': '<?php echo esc_js(get_post_meta($product->get_id(), '_brand', true)); ?>',
                'price': <?php echo $product->get_price(); ?>,
                'currency': '<?php echo get_woocommerce_currency(); ?>'
            }]
        });
    </script>
    <?php
}

Step 2: Track Product Views

add_action('woocommerce_after_single_product', 'track_product_view');
function track_product_view() {
    global $product;

    $categories = wp_get_post_terms($product->get_id(), 'product_cat', array('fields' => 'names'));
    ?>
    <script>
        gtag('event', 'view_item', {
            'currency': '<?php echo get_woocommerce_currency(); ?>',
            'value': <?php echo $product->get_price(); ?>,
            'items': [{
                'item_id': '<?php echo esc_js($product->get_sku() ?: $product->get_id()); ?>',
                'item_name': '<?php echo esc_js($product->get_name()); ?>',
                'item_category': '<?php echo esc_js(implode('/', $categories)); ?>',
                'item_variant': '<?php echo esc_js($product->is_type('variable') ? 'variable' : 'simple'); ?>',
                'price': <?php echo $product->get_price(); ?>,
                'quantity': 1
            }]
        });
    </script>
    <?php
}

Step 3: Track Add to Cart

add_action('wp_footer', 'track_add_to_cart_js');
function track_add_to_cart_js() {
    if (!is_product()) {
        return;
    }
    global $product;
    ?>
    <script>
        jQuery(document).ready(function($) {
            $('.single_add_to_cart_button').on('click', function() {
                // Get variation data if variable product
                let variation = {};
                if ($('.variations_form').length) {
                    const variationData = $('.variations_form').data('product_variations');
                    const selectedVariation = $('.variation_id').val();
                    variation = variationData.find(v => v.variation_id == selectedVariation) || {};
                }

                gtag('event', 'add_to_cart', {
                    'currency': '<?php echo get_woocommerce_currency(); ?>',
                    'value': parseFloat(variation.display_price || <?php echo $product->get_price(); ?>),
                    'items': [{
                        'item_id': variation.sku || '<?php echo esc_js($product->get_sku() ?: $product->get_id()); ?>',
                        'item_name': '<?php echo esc_js($product->get_name()); ?>',
                        'price': parseFloat(variation.display_price || <?php echo $product->get_price(); ?>),
                        'quantity': parseInt($('.qty').val() || 1)
                    }]
                });
            });
        });
    </script>
    <?php
}

Step 4: Track Remove from Cart

add_action('wp_footer', 'track_remove_from_cart');
function track_remove_from_cart() {
    if (!is_cart()) {
        return;
    }
    ?>
    <script>
        jQuery(document).ready(function($) {
            $(document.body).on('click', '.product-remove a.remove', function() {
                const $row = $(this).closest('tr');
                const itemName = $row.find('.product-name a').text();
                const itemPrice = parseFloat($row.find('.product-price .amount').text().replace(/[^0-9.]/g, ''));
                const itemQty = parseInt($row.find('.qty').val() || 1);

                gtag('event', 'remove_from_cart', {
                    'currency': '<?php echo get_woocommerce_currency(); ?>',
                    'value': itemPrice * itemQty,
                    'items': [{
                        'item_name': itemName,
                        'price': itemPrice,
                        'quantity': itemQty
                    }]
                });
            });
        });
    </script>
    <?php
}

Step 5: Track Begin Checkout

add_action('woocommerce_before_checkout_form', 'track_begin_checkout');
function track_begin_checkout() {
    $cart = WC()->cart;
    $items = array();

    foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
        $product = $cart_item['data'];
        $items[] = array(
            'item_id' => $product->get_sku() ?: $product->get_id(),
            'item_name' => $product->get_name(),
            'price' => $product->get_price(),
            'quantity' => $cart_item['quantity']
        );
    }
    ?>
    <script>
        gtag('event', 'begin_checkout', {
            'currency': '<?php echo get_woocommerce_currency(); ?>',
            'value': <?php echo $cart->get_total(''); ?>,
            'coupon': '<?php echo esc_js(implode(', ', $cart->get_applied_coupons())); ?>',
            'items': <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

Step 6: Track Add Payment Info

add_action('woocommerce_review_order_before_payment', 'track_add_payment_info');
function track_add_payment_info() {
    ?>
    <script>
        jQuery(document).ready(function($) {
            $('input[name="payment_method"]').on('change', function() {
                const paymentMethod = $(this).val();
                gtag('event', 'add_payment_info', {
                    'currency': '<?php echo get_woocommerce_currency(); ?>',
                    'value': <?php echo WC()->cart->get_total(''); ?>,
                    'payment_type': paymentMethod
                });
            });
        });
    </script>
    <?php
}

Step 7: Track Purchase (Most Important)

add_action('woocommerce_thankyou', 'track_purchase_complete');
function track_purchase_complete($order_id) {
    if (!$order_id) {
        return;
    }

    // Prevent duplicate tracking on page refresh
    $tracked = get_post_meta($order_id, '_ga4_tracked', true);
    if ($tracked) {
        return;
    }

    $order = wc_get_order($order_id);
    $items = array();

    foreach ($order->get_items() as $item_id => $item) {
        $product = $item->get_product();
        $items[] = array(
            'item_id' => $product->get_sku() ?: $product->get_id(),
            'item_name' => $item->get_name(),
            'item_category' => wp_strip_all_tags(wc_get_product_category_list($product->get_id())),
            'price' => $item->get_total() / $item->get_quantity(),
            'quantity' => $item->get_quantity()
        );
    }
    ?>
    <script>
        gtag('event', 'purchase', {
            'transaction_id': '<?php echo $order->get_order_number(); ?>',
            'value': <?php echo $order->get_total(); ?>,
            'currency': '<?php echo $order->get_currency(); ?>',
            'tax': <?php echo $order->get_total_tax(); ?>,
            'shipping': <?php echo $order->get_shipping_total(); ?>,
            'coupon': '<?php echo implode(', ', $order->get_coupon_codes()); ?>',
            'items': <?php echo json_encode($items); ?>
        });
    </script>
    <?php

    // Mark as tracked
    update_post_meta($order_id, '_ga4_tracked', 'yes');
}

Server-Side Tracking with Measurement Protocol

Client-side tracking can miss conversions due to ad blockers or checkout redirects. Implement server-side tracking for accuracy.

Setup Server-Side Purchase Tracking

add_action('woocommerce_order_status_completed', 'server_side_ga4_purchase');
function server_side_ga4_purchase($order_id) {
    $order = wc_get_order($order_id);

    // Prevent duplicate tracking
    $tracked_server = get_post_meta($order_id, '_ga4_server_tracked', true);
    if ($tracked_server) {
        return;
    }

    // Get GA4 Measurement ID and API Secret (store in wp-config.php)
    $measurement_id = defined('GA4_MEASUREMENT_ID') ? GA4_MEASUREMENT_ID : 'G-XXXXXXXXXX';
    $api_secret = defined('GA4_API_SECRET') ? GA4_API_SECRET : 'your-api-secret';

    // Get or generate client ID
    $client_id = isset($_COOKIE['_ga']) ? substr($_COOKIE['_ga'], 6) : wp_generate_uuid4();

    // Build items array
    $items = array();
    foreach ($order->get_items() as $item) {
        $product = $item->get_product();
        $items[] = array(
            'item_id' => $product->get_sku() ?: $product->get_id(),
            'item_name' => $item->get_name(),
            'price' => $item->get_total() / $item->get_quantity(),
            'quantity' => $item->get_quantity()
        );
    }

    // Build payload
    $payload = array(
        'client_id' => $client_id,
        'events' => array(
            array(
                'name' => 'purchase',
                'params' => array(
                    'transaction_id' => $order->get_order_number(),
                    'value' => floatval($order->get_total()),
                    'currency' => $order->get_currency(),
                    'tax' => floatval($order->get_total_tax()),
                    'shipping' => floatval($order->get_shipping_total()),
                    'items' => $items
                )
            )
        )
    );

    // Send to GA4 Measurement Protocol
    $url = "https://www.google-analytics.com/mp/collect?measurement_id={$measurement_id}&api_secret={$api_secret}";

    wp_remote_post($url, array(
        'body' => json_encode($payload),
        'headers' => array('Content-Type' => 'application/json')
    ));

    update_post_meta($order_id, '_ga4_server_tracked', 'yes');
}

Get GA4 API Secret

  1. Go to GA4 → Admin → Data Streams
  2. Click your web stream
  3. Scroll to Measurement Protocol API secrets
  4. Click Create → Name it → Copy secret

Store Credentials Securely

// Add to wp-config.php (never commit to version control)
define('GA4_MEASUREMENT_ID', 'G-XXXXXXXXXX');
define('GA4_API_SECRET', 'your-api-secret-here');

Refund Tracking

Track refunds to maintain accurate revenue reporting:

add_action('woocommerce_order_status_refunded', 'track_order_refund');
function track_order_refund($order_id) {
    $order = wc_get_order($order_id);

    $items = array();
    foreach ($order->get_items() as $item) {
        $product = $item->get_product();
        $items[] = array(
            'item_id' => $product->get_sku() ?: $product->get_id(),
            'item_name' => $item->get_name(),
            'price' => $item->get_total() / $item->get_quantity(),
            'quantity' => $item->get_quantity()
        );
    }

    // Send server-side refund event
    $measurement_id = defined('GA4_MEASUREMENT_ID') ? GA4_MEASUREMENT_ID : 'G-XXXXXXXXXX';
    $api_secret = defined('GA4_API_SECRET') ? GA4_API_SECRET : '';

    $payload = array(
        'client_id' => wp_generate_uuid4(),
        'events' => array(
            array(
                'name' => 'refund',
                'params' => array(
                    'transaction_id' => $order->get_order_number(),
                    'value' => floatval($order->get_total()),
                    'currency' => $order->get_currency(),
                    'items' => $items
                )
            )
        )
    );

    wp_remote_post("https://www.google-analytics.com/mp/collect?measurement_id={$measurement_id}&api_secret={$api_secret}", array(
        'body' => json_encode($payload),
        'headers' => array('Content-Type' => 'application/json')
    ));
}

WooCommerce Subscriptions Tracking

For WooCommerce Subscriptions plugin:

// Track subscription sign-ups
add_action('woocommerce_subscription_status_active', 'track_subscription_signup', 10, 1);
function track_subscription_signup($subscription) {
    $subscription_id = $subscription->get_id();
    $tracked = get_post_meta($subscription_id, '_ga4_subscription_tracked', true);

    if ($tracked) {
        return;
    }

    ?>
    <script>
        gtag('event', 'subscription_signup', {
            'event_category': 'Subscriptions',
            'event_label': '<?php echo esc_js($subscription->get_name()); ?>',
            'value': <?php echo $subscription->get_total(); ?>,
            'currency': '<?php echo $subscription->get_currency(); ?>',
            'subscription_period': '<?php echo $subscription->get_billing_period(); ?>'
        });
    </script>
    <?php

    update_post_meta($subscription_id, '_ga4_subscription_tracked', 'yes');
}

// Track subscription cancellations
add_action('woocommerce_subscription_status_cancelled', 'track_subscription_cancel', 10, 1);
function track_subscription_cancel($subscription) {
    gtag('event', 'subscription_cancel', {
        'event_category': 'Subscriptions',
        'event_label': $subscription->get_name(),
        'subscription_id': $subscription->get_id()
    });
}

GTM Implementation for WooCommerce

Alternative approach using Google Tag Manager data layer:

add_action('wp_footer', 'woocommerce_gtm_data_layer');
function woocommerce_gtm_data_layer() {
    if (is_product()) {
        global $product;
        ?>
        <script>
            dataLayer.push({
                'event': 'productView',
                'ecommerce': {
                    'detail': {
                        'products': [{
                            'id': '<?php echo esc_js($product->get_sku() ?: $product->get_id()); ?>',
                            'name': '<?php echo esc_js($product->get_name()); ?>',
                            'price': '<?php echo $product->get_price(); ?>',
                            'category': '<?php echo esc_js(wp_strip_all_tags(wc_get_product_category_list($product->get_id()))); ?>'
                        }]
                    }
                }
            });
        </script>
        <?php
    }
}

See GTM Data Layer Guide for complete WooCommerce GTM setup.

Testing E-commerce Tracking

1. Enable Test Mode in WooCommerce

// Add to wp-config.php for testing environment
define('WC_TAX_ROUNDING_MODE', 'auto');
define('WP_ENVIRONMENT_TYPE', 'staging');

2. Make Test Purchases

  • Use Cash on Delivery payment method (no real charges)
  • Or use Stripe Test Mode with test cards
  • Test card: 4242 4242 4242 4242, Exp: any future date, CVC: any 3 digits

3. Verify in GA4 DebugView

// Enable debug mode
add_action('wp_head', 'enable_ga4_debug');
function enable_ga4_debug() {
    if (defined('WP_ENVIRONMENT_TYPE') && WP_ENVIRONMENT_TYPE === 'staging') {
        ?>
        <script>
            gtag('config', 'G-XXXXXXXXXX', {
                'debug_mode': true
            });
        </script>
        <?php
    }
}

4. Check E-commerce Reports

After 24-48 hours, verify data in:

  • Reports → Monetization → Overview
  • Reports → Monetization → E-commerce purchases
  • Explore → E-commerce funnel

Deduplication Best Practices

Prevent double-counting purchases:

// Check if purchase already tracked before firing event
function track_purchase_complete($order_id) {
    // Check custom meta
    if (get_post_meta($order_id, '_ga4_tracked', true)) {
        return; // Already tracked, skip
    }

    // ... tracking code ...

    // Mark as tracked
    update_post_meta($order_id, '_ga4_tracked', 'yes');
}

Performance Optimization

Conditional Script Loading

// Only load e-commerce tracking on shop pages
add_action('wp_enqueue_scripts', 'conditional_ecommerce_scripts');
function conditional_ecommerce_scripts() {
    if (is_woocommerce() || is_cart() || is_checkout() || is_account_page()) {
        wp_enqueue_script('wc-ga4-tracking', get_stylesheet_directory_uri() . '/js/wc-ga4.js', array('jquery'), '1.0', true);
    }
}

Defer Non-Critical Tracking

// Delay product impression tracking until page is interactive
if ('requestIdleCallback' in window) {
    requestIdleCallback(() => {
        // Fire impression events here
    });
} else {
    setTimeout(() => {
        // Fire impression events here
    }, 1000);
}

Troubleshooting

Purchases Not Tracking

  • Check order confirmation page loads (not redirected away)
  • Verify transaction ID is unique
  • Ensure purchase event fires only once per order
  • Check for JavaScript errors in console

Revenue Mismatch

  • Compare WooCommerce reports with GA4
  • Account for refunds, cancelled orders
  • Verify tax and shipping are included correctly
  • Check currency conversion if multi-currency store

See Tracking Troubleshooting Guide for detailed debugging.

Next Steps

// SYS.FOOTER