- WooCommerce server-side tracking sends each paid order from the shop's own order data to Meta, TikTok and other ad platforms, so a purchase counts even when the browser pixel never fires.
- ROASaurus counts a WooCommerce order as paid when its status is processing or completed, which includes cash on delivery orders and bank transfers once you confirm them.
- The ROASaurus plugin saves the visitor id and the ad click cookies on each order at checkout, so the order is linked to its ad click exactly.
- Without the plugin, webhooks still deliver every paid order, but there is no thank-you page matching: orders are linked only by an email given earlier on the site or by a unique IP address and browser.
- On WooCommerce the ROASaurus script follows consent plugins that use the WP Consent API, such as Complianz and CookieYes, and Cookiebot, OneTrust and IAB TCF banners.
WooCommerce server-side tracking sends each paid order from your shop's order data to Meta, TikTok and other ad platforms, instead of relying only on a pixel in the shopper's browser. The purchase is reported even when an ad blocker stops the pixel or the shopper never reaches the thank-you page.
This guide covers why WooCommerce stores lose conversions, the order data WooCommerce gives you, and the two ways to connect ROASaurus: the WordPress plugin or webhooks. Then matching, consent, setup and testing. For the general idea, read what server-side tracking is.
Why do WooCommerce stores lose conversions?
A browser pixel reports a purchase only when the pixel script loads, the shopper reaches the thank-you page and the browser sends the event. Each step can fail. The order itself is still in your database, because WooCommerce saves it on the server.
| What happens | Browser pixel | Order data in WooCommerce |
|---|---|---|
| The shopper pays by redirect (for example PayPal or a bank app) and closes the tab | No thank-you page, no purchase event | Paid order, status processing |
| An ad blocker or privacy setting blocks the pixel script | No purchase event | Paid order |
| The visitor declines marketing cookies | The pixel must not load | Paid order |
| A bank transfer is confirmed three days later | No browser is open at that moment | Status changes from on hold to processing |
| A caching or script optimization plugin delays the pixel | The event can be late or missing | Paid order |
Missing purchases do two kinds of damage. The ad platform optimizes on fewer conversions, and your reports show a lower return than you really get. Here is the second effect in numbers, for an example store with a break-even ROAS of 2.2:
| Example store, one month | Pixel only | Every paid order |
|---|---|---|
| Meta ad spend | $8,000 | $8,000 |
| Purchases from Meta clicks | 260 | 320 |
| Revenue at $60 per order | $15,600 | $19,200 |
| ROAS | 15,600 ÷ 8,000 = 1.95 | 19,200 ÷ 8,000 = 2.40 |
| Against break-even (2.2) | Looks like a loss | Profitable |
What WooCommerce gives you: orders, webhooks and the REST API
Which order statuses count as paid?
WooCommerce describes processing as payment received, with the order waiting to be fulfilled. ROASaurus sends orders with the status processing or completed and skips pending payment, on hold, failed, cancelled and refunded orders. Two payment methods need attention:
- Cash on delivery. WooCommerce sets these orders to processing until the payment is collected, so ROASaurus sends them when they are placed. Orders with a downloadable product are the exception: they go on hold. See tracking cash on delivery orders for what that means for returns and refusals.
- Bank transfer. WooCommerce puts these orders on hold while you verify the payment. ROASaurus sends them when you move them to processing.
Webhooks
A webhook is a message WooCommerce sends to another system when something changes. You create it under WooCommerce › Settings › Advanced › Webhooks. For an order topic, the payload is the same order object the REST API returns. Each delivery carries an X-WC-Webhook-Signature header: a base64 HMAC-SHA256 hash of the payload, made with the secret you choose. ROASaurus checks that signature before it accepts an order.
Two details matter in practice. WooCommerce delivers webhooks in the background, with WP-Cron by default, so a delivery can be delayed when that queue runs late. And WooCommerce disables a webhook after more than five failed deliveries in a row.
REST API
The REST API lets ROASaurus ask for orders itself. With a read-only API key, ROASaurus asks every 5 minutes for processing and completed orders changed since its last check, with 30 minutes of overlap. Orders it already has are ignored. This catches any order a webhook missed.
| Order field | What ROASaurus does with it |
|---|---|
id | Becomes the event id order-1042, shared by the server and browser events |
total | The purchase value: the grand total, including tax and shipping |
| Billing email, phone, name, city, state, postcode, country | Hashed with SHA-256 and sent as customer data |
customer_ip_address, customer_user_agent | Sent with the event and used to match the order to a visitor |
line_items | Product ids (the variation id when there is one), quantities and prices |
date_paid_gmt | The event time for orders from a webhook or the REST API (the creation date when there is no paid date) |
meta_data | With the plugin: the visitor id and the Meta and TikTok cookies |
Plugin or webhooks: two ways to connect
Both connections send every paid order. They differ in how well each order is linked to the ad click that brought the shopper in.
| ROASaurus plugin | Webhooks only | |
|---|---|---|
| What you install | A WordPress plugin (PHP 7.4 and WooCommerce 6.0 or newer) | Nothing: a webhook in the WooCommerce settings |
| How orders arrive | The plugin posts each paid order to the ROASaurus orders API | WooCommerce posts Order updated; optional REST API check every 5 minutes |
| Tracking script | Loaded by the plugin on every page | You add it, for example with the WPCode plugin or in your theme |
| Visitor id and click cookies on the order | Yes, saved at checkout (classic and block checkout) | No |
| Browser purchase on the thank-you page | Yes, with the same event id as the server event | No |
| Thank-you page matching | Yes | No |
You can use both at once. The plugin saves the visitor id on the order as order meta data, and the webhook payload carries it along. ROASaurus stores each order once, by its WooCommerce order id, so the plugin and the webhook never create two purchases. The plugin also declares support for WooCommerce's High-Performance Order Storage.
How is a WooCommerce order matched to the ad click?
An ad platform can only credit a purchase to an ad when it can connect the two. ROASaurus does this by linking the order to the visitor who clicked the ad, and that visitor carries the click ids (such as fbclid and ttclid) and UTM parameters from the landing. It tries these methods in order and stops at the first one that works:
- The visitor id saved on the order. Only with the plugin. This is an exact link.
- The browser purchase on the thank-you page, which carries the same order id. Only with the plugin.
- A hashed email the visitor gave earlier on your site, for example in a Klaviyo, Attentive or Wisepops popup form, or through an Identify call.
- The same IP address and browser, seen from 3 hours before to 15 minutes after the order, but only when exactly one visitor fits. On shared networks, such as offices and mobile carriers, several visitors often share one IP address, and then ROASaurus does not guess.
ROASaurus waits briefly before it sends each purchase, so the thank-you page event can arrive first. If the order is still unmatched, it tries again at send time. The Orders page shows the result per order in the Matched by column. Orders linked by the plugin's visitor id show cart, the same label Shopify orders get.
| Sent to Meta for order 1042 | Matched (plugin) | Not matched (webhooks only) |
|---|---|---|
Event id order-1042 | Yes | Yes |
| Hashed email, phone, name and address | Yes | Yes |
| IP address and browser of the order | Yes | Yes |
Meta click id and browser id (fbc, fbp) | Yes | No |
Hashed visitor id (external_id) | Yes | No |
| The ad click in ROASaurus attribution | Campaign and ad of the click | Shown as direct or unknown |
Those click identifiers raise Meta's match rate for the event. Event Match Quality explains how Meta scores them.
Consent on WooCommerce
Each store in ROASaurus has the setting Respect visitor consent, which is on by default. On WooCommerce, the ROASaurus script reads the visitor's choice from the WP Consent API, which consent plugins such as Complianz and CookieYes fill in. It also reads Cookiebot, OneTrust, IAB TCF banners and Google consent mode. Until the visitor accepts marketing cookies, the script sets no visitor id and loads no browser pixels.
When a visitor declines, the script sets no visitor id, keeps no click ids and fires no browser pixels, and the plugin stores no tracking cookies on the order. The paid order is still sent from the server to your connected ad platforms with hashed customer data from the order and the order's IP address and browser. If your legal advice says purchase events also need prior consent, contact ROASaurus before you switch on server-side purchases. The consent help page has the details, and the post on Consent Mode v2 and GDPR covers the legal background.
How to set up WooCommerce server-side tracking
These are the steps for the plugin route:
- Add the store
In ROASaurus, go to Add a store, pick WooCommerce and enter the domain your customers visit.
- Create an API key
Open Store settings and, under Orders API, click Create API key. Copy the key right away: it is shown only once, next to your store key. The endpoint is the address in front of
/api/v1/orderson that page. - Install the plugin
Download the plugin and upload the zip in WordPress under Plugins › Add New Plugin › Upload Plugin, then activate it.
- Enter the keys
Under WooCommerce › ROASaurus, enter the endpoint, the store key and the API key, and save.
- Connect your ad platforms
On Tracking & platforms, use Connect with Facebook or Add pixel for Meta, TikTok and the others. Tick the option to also load the browser pixel, so the thank-you page purchase is deduplicated with the server event.
- Set up consent and test
Block the script in your consent tool until the visitor accepts marketing cookies, then place a test order.
Without the plugin, add the script tag from Tracking & platforms to every page, then create the webhook. The Connection tab of your store shows your webhook URL. Keep it private: anyone with the URL can send orders to your store.
WooCommerce › Settings › Advanced › Webhooks › Add webhook Status Active Topic Order updated Delivery URL (your webhook URL from the Connection tab) Secret (a secret of your choice; paste the same one in ROASaurus) API version WP REST API Integration v3
For the backup, create a key under WooCommerce › Settings › Advanced › REST API with read access. Paste the consumer key and secret on the Connection tab, save, and press Test connection. Fetch orders now pulls recent paid orders straight away. The WooCommerce integration page lists every option in one place.
How do you test WooCommerce server-side tracking?
Test the browser side first, then place an order and follow it to the ad platforms.
- Open your shop with
?roasaurus=connectedin the address. An alert confirms that the script runs. With?roasaurus=debug, the script logs what it sends to the browser console. - In the Event log, under Collected events, page views should show a visitor id.
- Place a test order. Cash on delivery is the quickest, because the order is processing straight away.
- On the Connection tab, Last order received shows the time of the latest order.
- In the Event log, under Server deliveries, each connected platform gets a line with the status sent and the platform's response.
PageView visitor 3f9c2a1eScript loaded with consentPurchase order-1042Thank-you page, browser pixels firedorder 1042 processingReceived from the pluginMeta Purchase sentSame event id, deduplicatedTikTok CompletePayment sentSame event id, deduplicatedTo see the event in Meta, paste the code from Events Manager › Test events into the Test event code field of your Meta pixel in ROASaurus. Remove it when you are done, because the code is meant for testing only. If the plugin cannot deliver an order, it adds an order note in WooCommerce that starts with "ROASaurus: order not sent", followed by the error.
Mistakes to avoid
- Using the topic Order created. Orders paid by redirect are created as pending payment. ROASaurus ignores unpaid orders, and no second "created" message follows when the payment arrives. Use Order updated.
- A secret that does not match. ROASaurus rejects a delivery whose signature does not match the secret it has. After more than five failures in a row, WooCommerce disables the webhook. Fix the secret, set the webhook back to Active and add the REST API key, so orders from the gap are fetched.
- Two tools sending the same pixel. If another plugin also sends your Meta or TikTok pixel, it uses its own event ids and the platform counts each sale twice. Switch it off for that pixel. See preventing double counting and duplicate purchase events.
- Expecting add-to-cart events. On WooCommerce the script tracks page views by itself. Product views and adds to cart are detected automatically on Shopify only. A developer can send them with a
tlqtrack call. - Expecting Google Ads conversions. ROASaurus sends Google Ads purchase conversions from the Shopify checkout only. From WooCommerce it sends purchases to Meta, TikTok, Snapchat, Pinterest, Reddit, X, Microsoft Ads, Taboola, LinkedIn and the other ad platforms you connect.
- Late bank transfers. Meta accepts server events up to 7 days after the event time. The plugin sends the order with the date it was created, so Meta rejects a transfer confirmed more than 7 days after checkout. Orders that arrive by webhook or the REST API use the paid date instead. Also note that the thank-you page fires the browser purchase at checkout, before the transfer is paid. If the payment is confirmed more than 48 hours later, Meta and TikTok cannot merge the browser and server copies, and a transfer that is never paid keeps its browser purchase.
Once orders flow, the attribution reports show which campaigns and ads they came from.
Sources
- WooCommerce: Webhooks Documentation
- WooCommerce REST API Documentation - WP REST API v3
- WooCommerce: Order Statuses Documentation
- WooCommerce: Cash on Delivery Documentation
- Meta for Developers: Server Event Parameters