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_renewalnotsub_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
- Enable debug mode (shown above)
- Navigate to GA4 → Configure → DebugView
- Perform WooCommerce actions
- 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
- Enhanced Ecommerce Tracking - Complete product analytics
- GTM Data Layer - Alternative event tracking via GTM
- Troubleshoot Events - Debug event tracking issues