WooCommerce Event Tracking with Google Analytics 4 | OpsBlu Docs

WooCommerce Event Tracking with Google Analytics 4

Track custom WooCommerce events including product interactions, cart updates, and customer behavior with GA4

Beyond standard eCommerce events, WooCommerce provides numerous opportunities for custom event tracking to understand customer behavior, optimize conversions, and improve the shopping experience.

Standard WooCommerce GA4 Events

These events form the foundation of WooCommerce analytics:

Event When It Fires Key Parameters
view_item_list Product archive pages items, item_list_name
view_item Single product page items, value, currency
add_to_cart Product added to cart items, value, currency
remove_from_cart Product removed from cart items, value, currency
view_cart Cart page viewed items, value, currency
begin_checkout Checkout page loaded items, value, currency
add_payment_info Payment method selected payment_type
add_shipping_info Shipping method selected shipping_tier
purchase Order completed transaction_id, value, tax, shipping

Advanced WooCommerce Event Tracking

1. Product List Views (Shop Pages)

Track which product categories customers browse:

// Track product category views
add_action('woocommerce_after_shop_loop', 'track_product_list_view');
function track_product_list_view() {
    global $wp_query;

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

    if ($wp_query->have_posts()) {
        while ($wp_query->have_posts()) {
            $wp_query->the_post();
            global $product;

            $items[] = array(
                'item_id' => $product->get_sku() ? $product->get_sku() : $product->get_id(),
                'item_name' => $product->get_name(),
                'item_category' => get_product_first_category($product),
                'price' => $product->get_price(),
                'index' => $position
            );
            $position++;
        }
        wp_reset_postdata();
    }

    if (empty($items)) return;

    $list_name = 'Shop Page';
    if (is_product_category()) {
        $category = get_queried_object();
        $list_name = 'Category: ' . $category->name;
    } elseif (is_product_tag()) {
        $tag = get_queried_object();
        $list_name = 'Tag: ' . $tag->name;
    } elseif (is_search()) {
        $list_name = 'Search Results';
    }
    ?>
    <script>
        gtag('event', 'view_item_list', {
            item_list_name: '<?php echo esc_js($list_name); ?>',
            items: <?php echo json_encode($items); ?>
        });
    </script>
    <?php
}

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

2. Product Click Tracking

Track when customers click products from lists:

// Track product clicks from archive pages
add_action('wp_footer', 'track_product_clicks');
function track_product_clicks() {
    if (!is_shop() && !is_product_category() && !is_product_tag()) {
        return;
    }
    ?>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // Track clicks on product links
            document.querySelectorAll('.woocommerce-LoopProduct-link, .woocommerce-loop-product__link').forEach(function(link) {
                link.addEventListener('click', function(e) {
                    var productName = this.querySelector('.woocommerce-loop-product__title')?.textContent || 'Unknown';
                    var productPrice = this.querySelector('.price .amount')?.textContent || '0';

                    gtag('event', 'select_item', {
                        item_list_name: '<?php echo is_product_category() ? "Category: " . get_queried_object()->name : "Shop Page"; ?>',
                        items: [{
                            item_name: productName,
                            price: parseFloat(productPrice.replace(/[^0-9.-]+/g, ''))
                        }]
                    });
                });
            });
        });
    </script>
    <?php
}

3. Remove from Cart Tracking

Track cart removals to understand abandonment:

// Track remove from cart (AJAX compatible)
add_action('wp_footer', 'track_remove_from_cart');
function track_remove_from_cart() {
    if (!is_cart()) {
        return;
    }
    ?>
    <script>
        jQuery(document).on('click', '.product-remove a.remove', function(e) {
            var $row = jQuery(this).closest('.cart_item');
            var productName = $row.find('.product-name a').text();
            var quantity = parseInt($row.find('.qty').val()) || 1;
            var price = parseFloat($row.find('.product-price .amount').text().replace(/[^0-9.-]+/g, ''));

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

4. Shipping Method Selection

Track which shipping methods customers choose:

// Track shipping method selection
add_action('woocommerce_checkout_update_order_review', 'track_shipping_selection');
function track_shipping_selection($posted_data) {
    parse_str($posted_data, $data);

    if (isset($data['shipping_method'][0])) {
        $shipping_method = $data['shipping_method'][0];
        $chosen_methods = WC()->session->get('chosen_shipping_methods');

        // Check if shipping method actually changed
        if ($chosen_methods && $chosen_methods[0] !== $shipping_method) {
            ?>
            <script>
                gtag('event', 'add_shipping_info', {
                    currency: '<?php echo get_woocommerce_currency(); ?>',
                    value: <?php echo WC()->cart->get_total('raw'); ?>,
                    shipping_tier: '<?php echo esc_js($shipping_method); ?>'
                });
            </script>
            <?php
        }
    }
}

5. Payment Method Selection

Track payment method choices:

// Track payment method selection
add_action('woocommerce_review_order_after_payment', 'track_payment_method_js');
function track_payment_method_js() {
    ?>
    <script>
        jQuery('input[name="payment_method"]').on('change', function() {
            var paymentMethod = jQuery(this).val();
            var paymentLabel = jQuery('label[for="payment_method_' + paymentMethod + '"]').text().trim();

            gtag('event', 'add_payment_info', {
                currency: '<?php echo get_woocommerce_currency(); ?>',
                value: <?php echo WC()->cart->get_total('raw'); ?>,
                payment_type: paymentMethod
            });
        });
    </script>
    <?php
}

6. Coupon Usage Tracking

Track coupon applications and removals:

// Track coupon application
add_action('woocommerce_applied_coupon', 'track_coupon_applied', 10, 1);
function track_coupon_applied($coupon_code) {
    $coupon = new WC_Coupon($coupon_code);
    ?>
    <script>
        gtag('event', 'coupon_applied', {
            coupon_code: '<?php echo esc_js($coupon_code); ?>',
            discount_type: '<?php echo esc_js($coupon->get_discount_type()); ?>',
            discount_amount: <?php echo $coupon->get_amount(); ?>
        });
    </script>
    <?php
}

// Track coupon removal
add_action('woocommerce_removed_coupon', 'track_coupon_removed', 10, 1);
function track_coupon_removed($coupon_code) {
    ?>
    <script>
        gtag('event', 'coupon_removed', {
            coupon_code: '<?php echo esc_js($coupon_code); ?>'
        });
    </script>
    <?php
}

7. Product Search Tracking

Track internal product searches:

// Track WooCommerce product search
add_action('pre_get_posts', 'track_product_search');
function track_product_search($query) {
    if (!is_admin() && $query->is_main_query() && $query->is_search() && isset($query->query_vars['s'])) {
        $search_term = $query->query_vars['s'];

        // Store in session to output on results page
        WC()->session->set('search_term_tracked', $search_term);
    }
}

add_action('woocommerce_before_shop_loop', 'output_search_tracking');
function output_search_tracking() {
    if (is_search()) {
        $search_term = WC()->session->get('search_term_tracked');
        if ($search_term) {
            global $wp_query;
            ?>
            <script>
                gtag('event', 'search', {
                    search_term: '<?php echo esc_js($search_term); ?>',
                    results_count: <?php echo $wp_query->found_posts; ?>
                });
            </script>
            <?php
            WC()->session->__unset('search_term_tracked');
        }
    }
}

8. Wishlist Interactions

If using a wishlist plugin like YITH:

// Track add to wishlist
add_action('yith_wcwl_added_to_wishlist', 'track_add_to_wishlist');
function track_add_to_wishlist() {
    $product_id = isset($_POST['add_to_wishlist']) ? absint($_POST['add_to_wishlist']) : 0;
    if (!$product_id) return;

    $product = wc_get_product($product_id);
    ?>
    <script>
        gtag('event', 'add_to_wishlist', {
            currency: '<?php echo get_woocommerce_currency(); ?>',
            value: <?php echo $product->get_price(); ?>,
            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 $product->get_price(); ?>
            }]
        });
    </script>
    <?php
}

9. Product Reviews / Ratings

Track when customers leave reviews:

// Track product review submission
add_action('comment_post', 'track_product_review', 10, 3);
function track_product_review($comment_id, $approved, $commentdata) {
    // Only track approved product reviews
    if ($approved && get_post_type($commentdata['comment_post_ID']) === 'product') {
        $product = wc_get_product($commentdata['comment_post_ID']);
        $rating = get_comment_meta($comment_id, 'rating', true);
        ?>
        <script>
            gtag('event', 'product_review', {
                item_id: '<?php echo $product->get_sku() ? $product->get_sku() : $product->get_id(); ?>',
                item_name: '<?php echo esc_js($product->get_name()); ?>',
                rating: <?php echo $rating ? $rating : 0; ?>
            });
        </script>
        <?php
    }
}

10. Product Quick View

If using quick view functionality:

// Track quick view opens
add_action('wp_footer', 'track_quick_view');
function track_quick_view() {
    if (!is_shop() && !is_product_category()) {
        return;
    }
    ?>
    <script>
        jQuery(document).on('click', '.quick-view-button', function() {
            var productId = jQuery(this).data('product-id');
            var productName = jQuery(this).closest('.product').find('.woocommerce-loop-product__title').text();

            gtag('event', 'quick_view', {
                item_id: productId,
                item_name: productName
            });
        });
    </script>
    <?php
}

Variable Products and Variations

Track Variation Selection

// Track when customer selects a product variation
add_action('woocommerce_after_add_to_cart_button', 'track_variation_change');
function track_variation_change() {
    global $product;

    if (!$product->is_type('variable')) {
        return;
    }
    ?>
    <script>
        jQuery('.variations_form').on('found_variation', function(event, variation) {
            gtag('event', 'view_item_variant', {
                currency: '<?php echo get_woocommerce_currency(); ?>',
                value: variation.display_price,
                items: [{
                    item_id: variation.sku || variation.variation_id,
                    item_name: '<?php echo esc_js($product->get_name()); ?>',
                    item_variant: Object.values(variation.attributes).join(', '),
                    price: variation.display_price
                }]
            });
        });
    </script>
    <?php
}

WooCommerce Subscriptions

Track Subscription Events

// Track subscription creation
add_action('woocommerce_checkout_subscription_created', 'track_subscription_created', 10, 3);
function track_subscription_created($subscription, $order, $recurring_cart) {
    ?>
    <script>
        gtag('event', 'start_subscription', {
            subscription_id: '<?php echo $subscription->get_id(); ?>',
            value: <?php echo $subscription->get_total(); ?>,
            currency: '<?php echo $subscription->get_currency(); ?>',
            billing_period: '<?php echo $subscription->get_billing_period(); ?>',
            billing_interval: <?php echo $subscription->get_billing_interval(); ?>
        });
    </script>
    <?php
}

// Track subscription cancellation
add_action('woocommerce_subscription_status_cancelled', 'track_subscription_cancelled', 10, 1);
function track_subscription_cancelled($subscription) {
    ?>
    <script>
        gtag('event', 'cancel_subscription', {
            subscription_id: '<?php echo $subscription->get_id(); ?>',
            value: <?php echo $subscription->get_total(); ?>,
            currency: '<?php echo $subscription->get_currency(); ?>'
        });
    </script>
    <?php
}

// Track subscription renewal
add_action('woocommerce_subscription_renewal_payment_complete', 'track_subscription_renewal', 10, 2);
function track_subscription_renewal($subscription, $order) {
    ?>
    <script>
        gtag('event', 'subscription_renewal', {
            subscription_id: '<?php echo $subscription->get_id(); ?>',
            order_id: '<?php echo $order->get_id(); ?>',
            value: <?php echo $order->get_total(); ?>,
            currency: '<?php echo $order->get_currency(); ?>'
        });
    </script>
    <?php
}

User Account Events

Track Account Creation

// Track new customer registration
add_action('woocommerce_created_customer', 'track_customer_registration', 10, 1);
function track_customer_registration($customer_id) {
    ?>
    <script>
        gtag('event', 'sign_up', {
            method: 'woocommerce'
        });
    </script>
    <?php
}

Track Login

// Track customer login
add_action('wp_login', 'track_customer_login', 10, 2);
function track_customer_login($user_login, $user) {
    // Only track if user is a customer
    if (in_array('customer', $user->roles)) {
        ?>
        <script>
            gtag('event', 'login', {
                method: 'woocommerce'
            });
        </script>
        <?php
    }
}

Cart Abandonment Tracking

Identify Cart Abandonment Points

// Track checkout step abandonment
add_action('woocommerce_checkout_update_order_review', 'track_checkout_progress');
function track_checkout_progress($posted_data) {
    static $checkout_step = 0;
    $checkout_step++;

    // Track progress through checkout
    ?>
    <script>
        gtag('event', 'checkout_progress', {
            checkout_step: <?php echo $checkout_step; ?>,
            value: <?php echo WC()->cart->get_total('raw'); ?>,
            currency: '<?php echo get_woocommerce_currency(); ?>'
        });
    </script>
    <?php
}

Custom Event Best Practices

1. Event Naming Conventions

Follow GA4 naming standards:

  • Use lowercase with underscores: product_review, quick_view
  • Be descriptive: subscription_renewal not sub_renew
  • Match recommended events when possible

2. Parameter Consistency

Use consistent parameter names:

// Good
gtag('event', 'custom_event', {
    item_id: '123',
    item_name: 'Product Name',
    value: 99.99,
    currency: 'USD'
});

// Bad - inconsistent naming
gtag('event', 'custom_event', {
    product_id: '123',
    productName: 'Product Name',
    price: 99.99,
    curr: 'USD'
});

3. Avoid PII (Personally Identifiable Information)

Never send customer personal data:

// Bad - contains PII
gtag('event', 'purchase', {
    customer_email: 'customer@example.com',  // Don't do this
    customer_name: 'John Doe'                 // Don't do this
});

// Good - no PII
gtag('event', 'purchase', {
    customer_type: 'returning',               // ✓ OK
    customer_lifetime_value: 500              // ✓ OK
});

4. Test Events Before Production

// Add debug mode during development
if (defined('WP_DEBUG') && WP_DEBUG) {
    ?>
    <script>
        gtag('config', 'G-XXXXXXXXXX', {
            'debug_mode': true
        });
    </script>
    <?php
}

Debugging WooCommerce Events

Check Events in Console

// Add to browser console
window.dataLayer.filter(event => event[0] === 'event').forEach(console.log);

Use GA4 DebugView

  1. Enable debug mode (shown above)
  2. Navigate to GA4 → Configure → DebugView
  3. Perform WooCommerce actions
  4. Verify events and parameters

Common Issues

Event fires multiple times:

  • Check for duplicate tracking implementations
  • Ensure events are only bound once (use .one() instead of .on() for jQuery)

Parameters missing:

  • Verify product data exists before outputting
  • Check WC() object availability
  • Validate cart/order objects

AJAX events not tracked:

  • Use WooCommerce-specific AJAX events (added_to_cart, removed_from_cart)
  • Hook into cart fragments for AJAX cart updates

Next Steps