Docs menu · WooCommerce plugin
Getting Started
Integrations
Server-side GTM
COD Order Protection
Advanced Features
Downloads
Tools & Support
Docs / COD Order Protection / Your store
COD Order Protection
WooCommerce plugin
Two settings to switch on, and one optional webhook that lets WooCommerce confirm orders for you.
Before you start
- PixelFly plugin v1.3.5 or newer — check under Plugins in WordPress.
- Your GTM container is already set up for COD — Step 2.
Everything below is on one screen: WooCommerce → PixelFly → COD Order Protection tab.
First, two settings COD depends on
These live on other tabs and are easy to miss. If either is wrong, COD looks set up but produces nothing.
| Where | Setting | What it must be |
|---|---|---|
| DataLayer Settings | Enable DataLayer | On. This is what pushes the purchase and payment_method to GTM. With it off, nothing reaches GTM and COD cannot work at all. |
| Advanced Settings | Excluded Roles | Check which roles are ticked. An excluded user gets no events — so if Administrator or Shop Manager is ticked, your own test order will produce nothing. |
Excluded Roles catches people out during testing. You place a COD test order while logged in as admin, no hold appears, and it looks like the GTM setup is broken. Either untick those roles while testing, or place the test order in a private window while logged out.
Also on the DataLayer tab: GTM Container ID, if you let the plugin inject GTM rather than installing the snippet yourself.
1. Switch it on
Tick Enable COD Order Protection, then set COD Handling Mode:
| Mode | Use it when |
|---|---|
| GTM / sGTM (recommended) | You followed any of our GTM setups. This is almost certainly you. |
| Plugin hold (PHP backup) | You cannot rely on the browser — for example orders placed by phone staff. WooCommerce posts the hold itself, and you paste the Hold URL (optional) from the Power-up. |
| Legacy delayed events | Only for stores already running it. Does not use the COD Held Orders dashboard. |
Worth turning on: Server-side hold backup
In GTM / sGTM mode, tick Also POST /cod/hold from WooCommerce (in addition to GTM). WooCommerce then posts the hold from your server as well as the browser, so an ad blocker, a JavaScript error or a customer closing the tab at checkout cannot lose the order. PixelFly keeps one hold per order ID, so the two routes do not create duplicates.
It posts to the Hold URL (optional) field if you filled one in; otherwise it works it out from your tracking domain.
In GTM / sGTM mode there is no payment-method list to tick: the plugin pushes payment_method to the dataLayer and GTM decides what counts as COD. The Payment Methods checkboxes only appear in Legacy mode.
2. Leave the plugin's API Key empty
With a PixelFly GTM container, the container sends the server-side events. An API Key here makes the plugin send them too, and every order is counted twice.
This also matters for COD specifically: the plugin's COD Order Protection switches itself off while an API Key is present, so COD orders would be counted at checkout.
3. Optional: let WooCommerce confirm orders for you
Skip this if you would rather approve each order in the PixelFly dashboard. With it on, changing an order's status in WooCommerce confirms or rejects it automatically.
| Setting | What to do |
|---|---|
| Auto-confirm webhook | Tick Fire held COD when WooCommerce order reaches selected statuses |
| Webhook Secret | Paste the secret (pfwh_…) from the PixelFly Power-up |
| Webhook on Status | Tick Completed to confirm and Cancelled to reject |
The status list shows every status your store actually has, including ones your courier plugin added. Shipped, Delivered and similar confirm the order; Refunded and Returned reject it. Tick whichever one means “this order is real” in your workflow.
Use the Webhook Secret here, not your API Key. They are different values: pf_live_ holds orders, pfwh_ confirms them.
Next
Place one prepaid and one COD test order before you go live.