WooCommerce Block Checkout Silently Broke Our Tracking — How I Found and Fixed It

· 9 min read

A client's WooCommerce store was processing 80-100 orders per day. GA4 was reporting around half that. The client assumed ad blockers and cookie consent were to blame — and they were partly right — but the gap had doubled overnight. No plugins had been updated. The consent banner was untouched. The GA4 property configuration had not changed.

The only change was a WooCommerce update that migrated the checkout page from the classic [woocommerce_checkout] shortcode to the new Checkout Block. Someone on the client's team had clicked the migration prompt that WooCommerce has been showing since version 9.0.

That single click broke every tracking event in the purchase funnel except the final purchase event.

Why Block Checkout Kills jQuery-Based Tracking

The classic WooCommerce checkout is a PHP-rendered form that fires jQuery events at every stage. init_checkout fires when the page loads. updated_checkout fires when shipping recalculates. payment_method_selected fires when the customer picks how to pay. Every major tracking plugin — GTM4WP, PixelYourSite, Meta for WooCommerce — listens for these events to push data into the dataLayer or fire pixel events.

The block checkout is a React application. It does not use jQuery. None of those events fire. The checkout submits via the WooCommerce Store API (POST /wp-json/wc/store/v1/checkout), not through the traditional PHP form submission. The PHP hooks that classic checkout fires during order processing — like woocommerce_checkout_order_processed — do not fire on Store API requests either.

WooCommerce provides replacement events, but they only cover cart actions — native DOM events prefixed with wc-blocks_:

  • wc-blocks_adding_to_cart
  • wc-blocks_added_to_cart
  • wc-blocks_removed_from_cart

There are no wc-blocks_ equivalents for init_checkout, updated_checkout, payment_method_selected, or checkout_error. Those checkout-stage events simply do not exist in the block architecture.

The Tracking Gap This Creates

Here is what happens to your GA4 ecommerce funnel after switching to block checkout:

GA4 Event Classic Checkout Block Checkout
add_to_cart Fires via jQuery added_to_cart Breaks unless plugin listens for wc-blocks_added_to_cart
view_cart Fires on cart page load Breaks — no jQuery cart events
begin_checkout Fires via init_checkout Breaks — no block equivalent exists
add_shipping_info Fires on shipping selection Breaks — React internal state, not observable
add_payment_info Fires on payment selection Breaks — React internal state, not observable
purchase Fires via woocommerce_thankyou Usually survives

The purchase event often survives because the woocommerce_thankyou PHP hook still fires on the order-received page regardless of checkout type. Revenue numbers in GA4 might look roughly correct — but the entire funnel above the purchase is empty.

For Meta Pixel, the impact is worse than a data gap. AddToCart and InitiateCheckout go silent while Purchase keeps firing. Meta's Smart Bidding then optimises against an audience that, as far as the pixel knows, never added anything to a cart — they just appeared at the purchase step. Ad spend efficiency degrades and you have no visibility into why.

How to Check If You Are Affected

First, determine whether your checkout uses blocks or the classic shortcode:

wp post get $(wp option get woocommerce_checkout_page_id) --field=post_content

If the output contains <!-- wp:woocommerce/checkout -->, you are on block checkout. If it contains [woocommerce_checkout], you are on the classic shortcode.

The same check in PHP, useful inside a plugin or mu-plugin:

$checkout_page_id = wc_get_page_id('checkout');
$is_block_checkout = has_block('woocommerce/checkout', $checkout_page_id);

Then validate your dataLayer. Open your checkout page in Chrome DevTools and run:

window.dataLayer.filter(e => e.event && e.event.includes('checkout'))

If begin_checkout is missing and you are on block checkout, your tracking is broken.

Fixing It

Purchase event: hook into both checkout paths

The classic checkout fires woocommerce_checkout_order_processed (passing the order ID). The block checkout fires woocommerce_store_api_checkout_order_processed (passing the WC_Order object). If your tracking only hooks the classic version, purchase events break on block checkout.

Hook into both:

add_action('woocommerce_checkout_order_processed', 'wpmp_track_purchase');
add_action('woocommerce_store_api_checkout_order_processed', 'wpmp_track_purchase');

function wpmp_track_purchase($order_or_id) {
    $order = $order_or_id instanceof WC_Order
        ? $order_or_id
        : wc_get_order($order_or_id);

    if (!$order) {
        return;
    }

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

    $tracking = [
        'event'          => 'purchase',
        'transaction_id' => (string) $order->get_id(),
        'value'          => (float) $order->get_total(),
        'currency'       => $order->get_currency(),
        'items'          => $items,
    ];

    $order->update_meta_data('_tracking_data', wp_json_encode($tracking));
    $order->save();
}

Add-to-cart: listen for the native DOM event

Replace jQuery event listeners with native DOM event listeners:

document.addEventListener('wc-blocks_added_to_cart', function() {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
        event: 'add_to_cart',
        ecommerce: {
            currency: wcSettings.currency.code,
            items: []
        }
    });
});

Begin checkout: use the block-specific script hook

No native begin_checkout event exists in block checkout. The workaround is firing it when the block checkout page loads, using WooCommerce's dedicated script enqueue hook:

add_action(
    'woocommerce_blocks_enqueue_checkout_block_scripts_after',
    function () {
        wc_enqueue_js("
            window.dataLayer = window.dataLayer || [];
            window.dataLayer.push({ event: 'begin_checkout' });
        ");
    }
);

This fires on page load rather than on form initialisation — less granular than the classic init_checkout — but it fills the funnel gap that analytics platforms need.

Which Tracking Plugins Handle This

Not all plugins have caught up:

  • GTM4WP (500,000+ installs) — incrementally adding block support. Version 1.20 fixed add_payment_info and add_shipping_info during submit. Purchase tracking still depends on PHP hooks that behave differently on block checkout.
  • GTM Kit — currently the most complete block checkout support. Ships specific compatibility fixes for popular themes.
  • Pixel Manager for WooCommerce — explicitly compatible with cart and checkout blocks. Endorsed by Google's Tag Implementation Team.
  • PixelYourSite — recent versions include block adapters. Older versions miss events entirely.
  • Meta for WooCommerce (official) — Purchase works via woocommerce_thankyou. AddToCart and InitiateCheckout remain unreliable on block checkout.

If you are running GTM4WP or a custom tracking implementation, check your version and test thoroughly after any WooCommerce update that touches the checkout.

What I Now Check on Every WooCommerce Audit

I added three checks to my standard WooCommerce maintenance audit:

  1. Block vs classic detection — run the WP-CLI check above on every site. Know which checkout type each store uses before something breaks.
  2. DataLayer validation — open the checkout in a browser, verify begin_checkout and add_to_cart events appear in the dataLayer. If they are missing, the tracking plugin needs updating or the custom fix above needs deploying.
  3. GA4 vs WooCommerce order count reconciliation — compare GA4 purchase events against WooCommerce order count weekly. A gap exceeding 15-20% on a site without aggressive cookie consent signals a tracking problem, not just ad blockers.

WooCommerce's direction is clear. The classic shortcode checkout is in maintenance-only mode — security fixes only, no new features. Every store will end up on block checkout eventually. The question is whether your tracking survives the transition or silently bleeds data for weeks before anyone notices.

If you have not verified your tracking since your last WooCommerce update, do it today. The data gap compounds daily, and every day of broken tracking is a day of ad spend optimised against incomplete data.

Stop Firefighting. Start Maintaining.

I manage 70+ WordPress sites for agencies and businesses. Whether you need ongoing maintenance, emergency support, or a one-off performance fix — I can help.

View Maintenance Plans Get in Touch

Get in Touch to Discuss Your Needs