+42%
WooCommerce + GA4: how not to lose 40% of orders
Server-side purchase delivery through Measurement Protocol with full attribution: client_id, session_id, gclid
This case study is for you if...
See yourself in this? Keep reading: this case study shows the solution.
About the project
An e-commerce store running on WordPress + WooCommerce
An e-commerce store running on WordPress + WooCommerce. GA4 was integrated through GTM and plugins, which is the standard setup for most WordPress stores.
Challenge
Analytics was missing up to 40% of orders because AdBlock, iOS Safari, and Brave were blocking trackers. Events were sent only from the frontend, users could leave before the call fired, data landed in "(not set)," and attribution was broken.
Goals
What can go wrong here
And why most contractors get it wrong
Plugins mean frontend only
Standard GA4 plugins for WooCommerce send purchase events with frontend JavaScript. AdBlock, Safari ITP, Brave, and Firefox ETP block that request, so up to 40% of orders are never recorded.
Attribution is lost between pages
client_id, session_id, and gclid have to survive from the first visit through purchase. If JS fails to read them in time or the user passes through a redirect, attribution breaks. GA4 shows "(not set)" and Google Ads misses the conversion.
Server-side purchase validation
Server-side Measurement Protocol does not give you DebugView by default. If the payload is invalid, the event is silently dropped. Without logging and validation, you can miss the problem for weeks.
What was done
PHP handler on woocommerce_thankyou
Built a custom PHP handler on the woocommerce_thankyou hook that collects all order data, including transaction_id, items, brand, and value.
JS for client_id and session_id
A JavaScript file reads client_id and session_id from GA4 via gtag("get", ...), stores them in cookies, and passes them to the server along with the order submission.
Server-side delivery to GA4
The server sends the purchase event to google-analytics.com/mp/collect with full payload data including client_id, session_id, source/medium/campaign, and gclid/gbraid.
Logging and validation
Every send is fully logged and checked in GA4 DebugView, validating that the purchase attaches to the correct session and funnel.
What I did differently
A PHP handler instead of a JS plugin
I built a custom PHP handler on the woocommerce_thankyou hook. The server sends purchase events directly to google-analytics.com/mp/collect, so no AdBlock can stop the server request.
Full attribution through a cookie bridge
JS reads client_id and session_id from GA4 and stores them in a first-party cookie. At checkout, PHP takes those values and sends them to Measurement Protocol together with gclid and gbraid. The result is 100% attribution.
Logging and validating every send
Every server-side purchase is logged with transaction_id, client_id, session_id, and the GA4 response. DebugView is then used to verify that the purchase is attached to the right session and funnel.
Numbers that speak for themselves
Before and after
In simple terms, Google Ads can finally see every purchase and optimize bids correctly. The same budget now produces more conversions.
Guide: server-side GA4 for WooCommerce without plugins
How to send purchase events from PHP through Measurement Protocol with full attribution. A step-by-step guide with code examples.
- PDF, 3 pages: architecture plus code
- PHP template for woocommerce_thankyou
- No signup, no spam
FAQ
Why does a GA4 plugin for WooCommerce lose orders?
Standard GA4 plugins send purchase events from frontend JavaScript. AdBlock, Safari ITP, Brave, and Firefox ETP block that request, so up to 40% of orders are never recorded. The fix is server-side delivery through Measurement Protocol.
How do you set up server-side purchase tracking for WooCommerce through Measurement Protocol?
You need a PHP handler on the woocommerce_thankyou hook that collects transaction_id, items, and value, then sends them to google-analytics.com/mp/collect. For attribution, JS stores client_id and session_id in a cookie, and PHP sends them together with gclid.
How do you verify that server-side purchase tracking works correctly?
Use three layers of validation: 1) log every send with the response code, 2) check in GA4 DebugView that the purchase attaches to the correct session, and 3) compare WooCommerce orders against GA4 purchases over a week.
Ready for growth?
Let's discuss your project and find the solution that works for your business.