WooCommerce Enhanced Ecommerce Tracking with GA4 | OpsBlu Docs

WooCommerce Enhanced Ecommerce Tracking with GA4

Complete guide to implementing enhanced eCommerce tracking for WooCommerce stores with product, cart, and purchase analytics

Enhanced eCommerce tracking provides comprehensive product performance data, revenue attribution, and customer journey insights for WooCommerce stores. This guide covers the complete implementation from product impressions to purchase completion.

What is Enhanced Ecommerce?

Enhanced eCommerce tracking captures the full customer journey:

  1. Product Impressions - Which products customers see
  2. Product Clicks - Which products generate interest
  3. Product Detail Views - Deep engagement with specific products
  4. Add/Remove from Cart - Cart behavior and abandonment signals
  5. Checkout Process - Multi-step checkout funnel
  6. Purchases - Revenue, products sold, transaction details
  7. Refunds - Returns and revenue adjustments

Complete WooCommerce Enhanced Ecommerce Implementation

1. Product Impressions (Shop/Category Pages)

Track all products displayed to customers:

// Track product impressions on archive pages
add_action('woocommerce_after_shop_loop', 'track_product_impressions');
function track_product_impressions() {
    global $wp_query;

    if (!$wp_query->have_posts()) return;

    $items = array();
    $position = 1;

    // Loop through displayed products
    foreach ($wp_query->posts as $post) {
        $product = wc_get_product($post->ID);
        if (!$product) continue;

        $items[] = array(
            'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
            'item_name' => $product->get_name(),
            'item_category' => get_product_primary_category($product),
            'item_category2' => get_product_secondary_category($product),
            'item_brand' => get_product_brand($product),
            'price' => (float) $product->get_price(),
            'index' => $position,
            'quantity' => 1
        );
        $position++;
    }

    if (empty($items)) return;

    // Determine list name
    $list_name = get_current_list_name();
    ?>
    <script>
        gtag('event', 'view_item_list', {
            item_list_id: '<?php echo sanitize_title($list_name); ?>',
            item_list_name: '<?php echo esc_js($list_name); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

function get_product_primary_category($product) {
    $categories = get_the_terms($product->get_id(), 'product_cat');
    if ($categories && !is_wp_error($categories)) {
        $primary = $categories[0];
        return $primary->name;
    }
    return '';
}

function get_product_secondary_category($product) {
    $categories = get_the_terms($product->get_id(), 'product_cat');
    if ($categories && !is_wp_error($categories) && count($categories) > 1) {
        return $categories[1]->name;
    }
    return '';
}

function get_product_brand($product) {
    // If using a brand taxonomy or attribute
    $brands = get_the_terms($product->get_id(), 'product_brand');
    if ($brands && !is_wp_error($brands)) {
        return $brands[0]->name;
    }
    return '';
}

function get_current_list_name() {
    if (is_shop()) {
        return 'Shop Page';
    } elseif (is_product_category()) {
        $category = get_queried_object();
        return 'Category: ' . $category->name;
    } elseif (is_product_tag()) {
        $tag = get_queried_object();
        return 'Tag: ' . $tag->name;
    } elseif (is_search()) {
        return 'Search Results';
    } elseif (is_front_page()) {
        return 'Homepage';
    }
    return 'Product List';
}

2. Product Clicks

Track when customers click on products:

// Add product click tracking via JavaScript
add_action('wp_footer', 'track_product_select_items');
function track_product_select_items() {
    if (!is_shop() && !is_product_category() && !is_product_tag() && !is_front_page()) {
        return;
    }
    ?>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            var listName = '<?php echo esc_js(get_current_list_name()); ?>';

            // Track product link clicks
            document.querySelectorAll('.products .product a.woocommerce-LoopProduct-link, .products .product a.woocommerce-loop-product__link').forEach(function(link, index) {
                link.addEventListener('click', function(e) {
                    var product = this.closest('.product');
                    var productName = product.querySelector('.woocommerce-loop-product__title')?.textContent || 'Unknown';
                    var productId = product.querySelector('[data-product_id]')?.getAttribute('data-product_id') || '';
                    var priceElement = product.querySelector('.price .amount, .price');
                    var productPrice = priceElement ? parseFloat(priceElement.textContent.replace(/[^0-9.-]+/g, '')) : 0;

                    gtag('event', 'select_item', {
                        item_list_id: listName.toLowerCase().replace(/[^a-z0-9]+/g, '_'),
                        item_list_name: listName,
                        items: [{
                            item_id: productId,
                            item_name: productName,
                            price: productPrice,
                            index: index
                        }]
                    });
                });
            });
        });
    </script>
    <?php
}

3. Product Detail Views

Track single product page views:

// Track product detail views
add_action('woocommerce_after_single_product', 'track_product_detail_view');
function track_product_detail_view() {
    global $product;

    if (!$product) return;

    $item_data = array(
        'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
        'item_name' => $product->get_name(),
        'item_category' => get_product_primary_category($product),
        'item_category2' => get_product_secondary_category($product),
        'item_brand' => get_product_brand($product),
        'price' => (float) $product->get_price(),
        'quantity' => 1
    );

    // Add variant info for variable products
    if ($product->is_type('variable')) {
        $item_data['item_variant'] = 'Variable Product';
    }
    ?>
    <script>
        gtag('event', 'view_item', {
            currency: '<?php echo get_woocommerce_currency(); ?>',
            value: <?php echo (float) $product->get_price(); ?>,
            items: [<?php echo json_encode($item_data); ?>]
        });
    </script>
    <?php
}

4. Add to Cart (AJAX-Compatible)

Track cart additions with full product data:

// Track add to cart on single product pages
add_action('woocommerce_after_add_to_cart_button', 'track_add_to_cart_button');
function track_add_to_cart_button() {
    global $product;
    ?>
    <script>
        jQuery(document).ready(function($) {
            $('form.cart').on('submit', function(e) {
                var quantity = parseInt($('input.qty').val()) || 1;
                var productData = {
                    item_id: '<?php echo $product->get_sku() ? $product->get_sku() : $product->get_id(); ?>',
                    item_name: '<?php echo esc_js($product->get_name()); ?>',
                    item_category: '<?php echo esc_js(get_product_primary_category($product)); ?>',
                    price: <?php echo (float) $product->get_price(); ?>,
                    quantity: quantity
                };

                gtag('event', 'add_to_cart', {
                    currency: '<?php echo get_woocommerce_currency(); ?>',
                    value: productData.price * quantity,
                    items: [productData]
                });
            });
        });
    </script>
    <?php
}

// Track AJAX add to cart from shop pages
add_action('wp_footer', 'track_ajax_add_to_cart_enhanced');
function track_ajax_add_to_cart_enhanced() {
    if (is_shop() || is_product_category() || is_product_tag()) {
        ?>
        <script>
            jQuery(document.body).on('added_to_cart', function(event, fragments, cart_hash, $button) {
                var product = $button.closest('.product');
                var productId = $button.data('product_id');
                var quantity = $button.data('quantity') || 1;
                var productName = product.find('.woocommerce-loop-product__title').text() || $button.attr('aria-label');
                var priceText = product.find('.price .amount').first().text();
                var price = parseFloat(priceText.replace(/[^0-9.-]+/g, ''));

                gtag('event', 'add_to_cart', {
                    currency: '<?php echo get_woocommerce_currency(); ?>',
                    value: price * quantity,
                    items: [{
                        item_id: productId,
                        item_name: productName,
                        price: price,
                        quantity: quantity
                    }]
                });
            });
        </script>
        <?php
    }
}

5. Remove from Cart

Track cart item removals:

// Track remove from cart
add_action('woocommerce_remove_cart_item', 'track_remove_from_cart_enhanced', 10, 2);
function track_remove_from_cart_enhanced($cart_item_key, $cart) {
    $cart_item = $cart->get_cart_item($cart_item_key);
    if (!$cart_item) return;

    $product = $cart_item['data'];
    ?>
    <script>
        gtag('event', 'remove_from_cart', {
            currency: '<?php echo get_woocommerce_currency(); ?>',
            value: <?php echo (float) $product->get_price() * $cart_item['quantity']; ?>,
            items: [{
                item_id: '<?php echo $product->get_sku() ? $product->get_sku() : $product->get_id(); ?>',
                item_name: '<?php echo esc_js($product->get_name()); ?>',
                price: <?php echo (float) $product->get_price(); ?>,
                quantity: <?php echo $cart_item['quantity']; ?>
            }]
        });
    </script>
    <?php
}

6. View Cart

Track cart page views with all items:

// Track cart view
add_action('woocommerce_after_cart', 'track_view_cart_enhanced');
function track_view_cart_enhanced() {
    $cart = WC()->cart;

    if ($cart->is_empty()) {
        return;
    }

    $items = array();
    foreach ($cart->get_cart() as $cart_item) {
        $product = $cart_item['data'];
        $items[] = array(
            'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
            'item_name' => $product->get_name(),
            'item_category' => get_product_primary_category($product),
            'price' => (float) $product->get_price(),
            'quantity' => $cart_item['quantity']
        );
    }
    ?>
    <script>
        gtag('event', 'view_cart', {
            currency: '<?php echo get_woocommerce_currency(); ?>',
            value: <?php echo $cart->get_cart_contents_total(); ?>,
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

7. Begin Checkout

Track checkout initiation:

// Track begin checkout
add_action('woocommerce_before_checkout_form', 'track_begin_checkout_enhanced');
function track_begin_checkout_enhanced() {
    // Prevent duplicate tracking
    static $tracked = false;
    if ($tracked) return;
    $tracked = true;

    $cart = WC()->cart;
    $items = array();

    foreach ($cart->get_cart() as $cart_item) {
        $product = $cart_item['data'];
        $item_data = array(
            'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
            'item_name' => $product->get_name(),
            'item_category' => get_product_primary_category($product),
            'price' => (float) $product->get_price(),
            'quantity' => $cart_item['quantity']
        );

        // Add variation data if applicable
        if (isset($cart_item['variation']) && !empty($cart_item['variation'])) {
            $item_data['item_variant'] = implode(', ', $cart_item['variation']);
        }

        $items[] = $item_data;
    }
    ?>
    <script>
        gtag('event', 'begin_checkout', {
            currency: '<?php echo get_woocommerce_currency(); ?>',
            value: <?php echo $cart->get_total('raw'); ?>,
            coupon: '<?php echo implode(', ', $cart->get_applied_coupons()); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

8. Add Shipping Info

Track shipping method selection:

// Track shipping info
add_action('woocommerce_checkout_order_processed', 'track_add_shipping_info_enhanced', 10, 1);
function track_add_shipping_info_enhanced($order_id) {
    $order = wc_get_order($order_id);
    $shipping_method = $order->get_shipping_method();

    if (!$shipping_method) return;

    $items = array();
    foreach ($order->get_items() as $item) {
        $product = $item->get_product();
        $items[] = array(
            'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
            'item_name' => $item->get_name(),
            'price' => (float) ($item->get_total() / $item->get_quantity()),
            'quantity' => $item->get_quantity()
        );
    }
    ?>
    <script>
        gtag('event', 'add_shipping_info', {
            currency: '<?php echo $order->get_currency(); ?>',
            value: <?php echo $order->get_total(); ?>,
            shipping_tier: '<?php echo esc_js($shipping_method); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

9. Add Payment Info

Track payment method selection:

// Track payment info
add_action('woocommerce_checkout_order_processed', 'track_add_payment_info_enhanced', 10, 1);
function track_add_payment_info_enhanced($order_id) {
    $order = wc_get_order($order_id);
    $payment_method = $order->get_payment_method_title();

    $items = array();
    foreach ($order->get_items() as $item) {
        $product = $item->get_product();
        $items[] = array(
            'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
            'item_name' => $item->get_name(),
            'price' => (float) ($item->get_total() / $item->get_quantity()),
            'quantity' => $item->get_quantity()
        );
    }
    ?>
    <script>
        gtag('event', 'add_payment_info', {
            currency: '<?php echo $order->get_currency(); ?>',
            value: <?php echo $order->get_total(); ?>,
            payment_type: '<?php echo esc_js($payment_method); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

10. Purchase Event

Track completed purchases on the thank you page:

// Track purchase completion
add_action('woocommerce_thankyou', 'track_purchase_enhanced', 10, 1);
function track_purchase_enhanced($order_id) {
    if (!$order_id) return;

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

    $order = wc_get_order($order_id);

    // Build items array
    $items = array();
    foreach ($order->get_items() as $item) {
        $product = $item->get_product();

        $item_data = array(
            'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
            'item_name' => $item->get_name(),
            'item_category' => get_product_primary_category($product),
            'item_brand' => get_product_brand($product),
            'price' => (float) ($item->get_total() / $item->get_quantity()),
            'quantity' => $item->get_quantity()
        );

        // Add variation data if applicable
        if ($product->is_type('variation')) {
            $item_data['item_variant'] = $product->get_attribute_summary();
        }

        $items[] = $item_data;
    }

    // Get coupon codes
    $coupons = $order->get_coupon_codes();
    $coupon_string = !empty($coupons) ? implode(', ', $coupons) : '';

    // Determine new vs returning customer
    $customer_email = $order->get_billing_email();
    $customer_orders = wc_get_orders(array(
        'billing_email' => $customer_email,
        'status' => array('wc-completed', 'wc-processing'),
        'limit' => -1
    ));
    $is_new_customer = count($customer_orders) <= 1 ? 'new' : 'returning';
    ?>
    <script>
        gtag('event', 'purchase', {
            transaction_id: '<?php echo $order->get_order_number(); ?>',
            value: <?php echo $order->get_total(); ?>,
            tax: <?php echo $order->get_total_tax(); ?>,
            shipping: <?php echo $order->get_shipping_total(); ?>,
            currency: '<?php echo $order->get_currency(); ?>',
            coupon: '<?php echo esc_js($coupon_string); ?>',
            affiliation: '<?php echo esc_js(get_bloginfo('name')); ?>',
            customer_type: '<?php echo $is_new_customer; ?>',
            payment_method: '<?php echo esc_js($order->get_payment_method_title()); ?>',
            shipping_method: '<?php echo esc_js($order->get_shipping_method()); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php

    // Mark as tracked
    update_post_meta($order_id, '_ga4_purchase_tracked', true);
}

11. Refund Tracking

Track refunds and returns:

// Track refunds
add_action('woocommerce_order_refunded', 'track_refund_enhanced', 10, 2);
function track_refund_enhanced($order_id, $refund_id) {
    $order = wc_get_order($order_id);
    $refund = wc_get_order($refund_id);

    if (!$refund) return;

    $items = array();
    foreach ($refund->get_items() as $item) {
        $product_id = $item->get_product_id();
        $product = wc_get_product($product_id);

        if ($product) {
            $items[] = array(
                'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
                'item_name' => $item->get_name(),
                'price' => (float) abs($item->get_total() / $item->get_quantity()),
                'quantity' => abs($item->get_quantity())
            );
        }
    }
    ?>
    <script>
        gtag('event', 'refund', {
            transaction_id: '<?php echo $order->get_order_number(); ?>',
            value: <?php echo abs($refund->get_total()); ?>,
            currency: '<?php echo $order->get_currency(); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

Handling Variable Products

Track Variation Selection

// Add variation tracking to product pages
add_action('woocommerce_after_add_to_cart_button', 'track_variation_selection_enhanced');
function track_variation_selection_enhanced() {
    global $product;

    if (!$product->is_type('variable')) return;
    ?>
    <script>
        jQuery('.variations_form').on('found_variation', function(event, variation) {
            var variationData = {
                item_id: variation.sku || variation.variation_id,
                item_name: '<?php echo esc_js($product->get_name()); ?>',
                item_variant: Object.values(variation.attributes).filter(v => v).join(', '),
                price: parseFloat(variation.display_price)
            };

            gtag('event', 'view_item', {
                currency: '<?php echo get_woocommerce_currency(); ?>',
                value: variationData.price,
                items: [variationData]
            });
        });
    </script>
    <?php
}

Complete Data Layer Approach (Alternative)

For GTM users, push complete data to the data layer:

// Push complete eCommerce data to dataLayer
add_action('wp_footer', 'push_ecommerce_datalayer', 99);
function push_ecommerce_datalayer() {
    global $product;

    // Product pages
    if (is_product() && $product) {
        ?>
        <script>
            window.dataLayer = window.dataLayer || [];
            dataLayer.push({
                'event': 'productDetailView',
                'ecommerce': {
                    'detail': {
                        'products': [{
                            'id': '<?php echo $product->get_sku() ? $product->get_sku() : $product->get_id(); ?>',
                            'name': '<?php echo esc_js($product->get_name()); ?>',
                            'price': <?php echo (float) $product->get_price(); ?>,
                            'brand': '<?php echo esc_js(get_product_brand($product)); ?>',
                            'category': '<?php echo esc_js(get_product_primary_category($product)); ?>'
                        }]
                    }
                }
            });
        </script>
        <?php
    }
}

Testing Enhanced Ecommerce

1. Complete Purchase Flow Test

  1. Browse shop page → Verify view_item_list
  2. Click product → Verify select_item
  3. View product details → Verify view_item
  4. Add to cart → Verify add_to_cart
  5. View cart → Verify view_cart
  6. Begin checkout → Verify begin_checkout
  7. Complete purchase → Verify purchase

2. GA4 Reports to Check

After 24-48 hours:

  • Monetization → Ecommerce Purchases - Revenue and transactions
  • Monetization → Item List Name & Item Name - Product performance
  • Monetization → Item Promotion - Product discovery paths
  • Exploration → Funnel Exploration - Create custom checkout funnel

3. Real-Time Validation

Use GA4 → Reports → Realtime → Events to verify events fire immediately.

Best Practices

  1. Use SKUs when available - More reliable than product IDs
  2. Track deduplication - Prevent duplicate purchase events on page refresh
  3. Include all item parameters - Categories, brands, variants for rich analysis
  4. Test AJAX thoroughly - WooCommerce uses AJAX extensively
  5. Handle variable products - Track variations separately
  6. Monitor data quality - Regular audits of revenue and transaction counts

Next Steps