Fundusze Europejskie Województwo Łódzkie Unia Europejska
WooCommerce

WooCommerce conversion tracking: why it breaks and how to test it

In short

WooCommerce loses conversions for five reasons, and four of them are properties of running measurement in the browser: the pixel is blocked, the thank-you page is skipped, a plugin broke the event, or the tracker was written for the classic checkout and the store uses Blocks. Server-side capture removes those four. The fifth is consent, which nothing fixes.

Why WooCommerce underreports conversions

Five mechanisms, and every one of them is a property of running the measurement in the visitor's browser rather than on your server.

  • The pixel is blocked. Content blockers and tracking protection in Safari and

Firefox stop the request before it leaves. The order completes; the event never does.

  • The thank-you page is skipped. Payment gateways that redirect back

asynchronously, or customers who close the tab once the bank confirms, never load the page the conversion script lives on. The order is in your database regardless.

  • A plugin broke the event. WooCommerce checkout is a plugin surface. Anything

touching the order flow can suppress the script or change the DOM it reads from, and nothing warns you.

  • The Block checkout is not the classic checkout. Trackers written against

woocommerce_checkout_create_order fire on the classic flow and silently do not fire on the Block one, which is now the default on new installs.

  • Consent was refused. No script fires and none should. This is the only one on

the list that is a decision rather than a defect.

The first four are recoverable. The fifth is not, and no vendor claiming otherwise should be believed.

Five ways a WooCommerce conversion goes missing

Five ways a WooCommerce conversion goes missingProportion bar dividing the five failure mechanisms into four that server-side capture removes and one, consent refusal, that no technical measure addresses.5 failure mechanisms480%120%Removed by server-side capture — blocked pixel, skipped thank-you page, broken by a plugin, Block checkoutNot fixable by any tracking method — consent refused
Four of the five are properties of the browser, not of WooCommerce. Moving capture to the server removes them together. The fifth is a decision the visitor made.

How to tell which one is hitting you

A diagnostic you can run this afternoon, on your own store, without buying anything. It answers a narrower question than "is my tracking broken" — it tells you *where*.

  1. Count orders in the database. WooCommerce → Orders, filtered to one closed

month, status processing or completed. This is truth. Write the number down.

  1. Count purchases in the ad platform for the same month, on the same attribution

window your reporting uses. Write that down too.

  1. Count events the pixel actually sent. In Meta's Events Manager, the count for

the Purchase event, same window. This is the number people skip, and it is the one that separates a tracking problem from an attribution problem.

Now read the three:

PatternWhat it means
Pixel count below store ordersA tracking problem. One of mechanisms 1–4.
Pixel count ≈ store orders, platform attribution higherNot a tracking problem. This is view-through, modelling and window overlap — a different article.
Pixel count above store ordersDouble-firing, usually a page that loads the event twice or a refresh on the thank-you page.

To narrow a tracking problem further, repeat step 3 with the Block checkout enabled and disabled. A count that changes tells you it is mechanism four.

What moving capture to the server actually fixes

Capture on the server runs before anything reaches the browser, so blockers, tab closures and DOM changes cannot reach it. In our own WooCommerce plugin the capture runs on template_redirect at priority 5 — that is Loyalz_Tracking::capture() in public/class-loyalz-tracking.php, hooked in includes/class-loyalz.php — and it writes to a first-party cookie, loyalz_tp, set httponly, secure and SameSite=Lax, holding at most 20 touchpoints for 90 days.

What gets recorded per touchpoint: the ad id, the five utm parameters, and the four click identifiers gclid, fbclid, ttclid and msclkid, plus referrer, landing URL and an ISO-8601 UTC timestamp.

A visit carrying none of those is not discarded. derive_channel() classifies it from the referrer into direct, organic or referral, so those channels appear in the path instead of being invisible — and returns null for same-host referrers, so internal navigation does not spawn a touchpoint on every page view.

At checkout the chain moves onto the order. Both flows are hooked: woocommerce_checkout_create_order for the classic checkout and woocommerce_store_api_checkout_order_processed for the Block one, in admin/class-loyalz-woocommerce.php. The chain is read, the cookie is cleared, and the result is written to the order as _loyalz_touchpoints. Hooking only the first of those two is mechanism four, and it is the single most common way a WooCommerce tracking integration is quietly half-broken.

Here is the failure mode that survives a correct server-side implementation, because we hit it ourselves.

On the very first visit from an ad, the consent cookie does not exist yet. The banner has not been answered. Server-side capture runs on template_redirect, checks consent, finds none, and correctly skips — and by the time the visitor accepts, the request carrying the utm parameters is over.

That is the visit most worth recording, and a naive server-side implementation loses every one of them.

The fix is not more server-side code. It is a small listener that, on acceptance, posts the landing parameters still sitting in the URL to an endpoint that captures with consent now verified — loyalz_tp_capture, registered for logged-out visitors too. Any server-side setup that does not handle this is losing its first touchpoint on every consented ad visit, which is the touchpoint that names the campaign.

What none of this fixes

Consent refusal. If a visitor declines the advertising category, there is no touchpoint, no chain, and no attribution, and that is the correct outcome. Our own gate reads CookieYes's cookieyes-consent cookie for advertisement:yes and returns false for anything else, with a filter for other consent platforms.

This is worth being blunt about, because the category of vendor claiming to recover conversions from non-consenting visitors is selling either a misunderstanding or a liability. The honest ceiling on what any tool can measure is the consented share of your traffic, and the way to raise that number is banner design, not tracking architecture. The rest of what survives a refusal is covered across measurement for WooCommerce.

Two further limits, since a page that only lists strengths is an advert:

  • Twenty touchpoints and ninety days are the limits above. A purchase cycle longer

than ninety days loses its earliest touches, and a path longer than twenty entries drops its oldest.

  • A first-party cookie is per browser and per device. A visitor who first sees the ad

on a phone and buys on a laptop presents as two visitors, and no cookie-based method resolves that. Identity stitching at login is a different mechanism with different trade-offs, discussed under ad measurement.

If you want the arithmetic on what to do with the spend once you can attribute it, dividing by margin rather than revenue is the next step.

Common questions

Why does my WooCommerce store show fewer conversions than Meta?

Two different causes look identical from the dashboard. Either the pixel is not firing on every order, which is a tracking problem, or it is firing correctly and Meta is attributing more orders to itself than your store agrees with, which is an attribution problem. The three-count diagnostic above separates them, and they need opposite fixes.

Do I need the Conversions API or server-side tracking?

They are related but not the same thing. The Conversions API is one destination you can send server-side events to. Server-side capture is recording the event on your own infrastructure in the first place. Do the second first: without it, the Conversions API has nothing reliable to send.

Does the WooCommerce Block checkout break conversion tracking?

It breaks any tracker hooked only to the classic checkout flow. The Block checkout fires woocommerce_store_api_checkout_order_processed rather than woocommerce_checkout_create_order, and an integration listening only for the latter records nothing while appearing to work.

Can I track conversions without consent?

No, and you should not want to. If a visitor declines the advertising category there is no lawful basis for the touchpoint, and any tool promising to recover those conversions is describing a liability. The measurable ceiling is your consented traffic share.

How long is a touchpoint kept?

In our plugin, ninety days and at most twenty touchpoints per visitor. Those are limits, not guarantees: a purchase cycle longer than ninety days loses its earliest touches, and a path longer than twenty entries drops its oldest ones.

KM

Karol Majewski

Founder, Loyalz · 12 years running paid acquisition at zest.agency

See it on your data

Loyalz joins ad spend to settled order lines, so POAS is a column rather than a spreadsheet you rebuild every month.

Book a demo