Pixel tracking for cash-on-delivery Shopify stores

Updated

Cash on delivery breaks the one assumption every pixel makes: that an order is a sale. On a COD store the Purchase event fires when the order is placed, days or weeks before anyone hands over money, and a substantial share of those orders will be refused at the door. Meta optimises against what you tell it, so a store reporting every COD order as revenue is actively training its ads to find more customers who will refuse delivery.

What changes on a cash on delivery store

Pixel tracking differences on a cash on delivery Shopify store
WhatHow it differs
PurchaseFires at order creation, not payment. Reported revenue includes orders that will never be paid.
ValueShould be discounted by your acceptance rate, or sent on delivery confirmation instead.
Attribution windowDelivery confirmation can fall outside the window if you delay the event.
Server-sideEffectively required — a delivery-time event has no browser session to fire from.

Why COD breaks the Purchase event’s meaning

Every pixel on the market fires Purchase when a Shopify order is created. On a card store that is the same moment money changes hands, so the event and the revenue are the same thing. On a cash-on-delivery store they are weeks and a delivery attempt apart, and somewhere between a fifth and a half of those orders will never be paid for at all.

Meta does not know this. It receives a Purchase with a value, treats it as revenue, and optimises delivery toward whoever produces more of them. If refused orders cluster in a particular audience — and they reliably do — the algorithm learns to find more of exactly the customers who will refuse the parcel, because from its point of view those customers converted.

Three ways to fix it, in order of preference

The cleanest fix is to move the Purchase event to the moment of delivery confirmation rather than order creation. Server-side tracking makes this possible because the event no longer depends on the shopper having a browser open — you send it when your fulfilment status says delivered. The cost is a delay of days, which pushes some conversions outside the attribution window.

The pragmatic middle option is to keep firing Purchase at order creation but discount the value by your historical acceptance rate. A store confirming 65% of COD orders sends 65% of the order value, which keeps the event timely and makes reported ROAS approximately honest. The third option, sending Purchase only on confirmation while firing a custom event at order creation, gives you both signals and the most work to maintain.

Setup checklist

  1. 1Measure your true COD acceptance rate over at least 90 days before choosing a value convention.
  2. 2Decide once whether Purchase fires at order creation or delivery, and document it.
  3. 3If firing at creation, discount the value by the acceptance rate rather than sending the full order total.
  4. 4Keep a custom event for the other moment, so you retain both signals for analysis.
  5. 5Re-check the acceptance rate quarterly — it moves with geography, creative and offer.

Questions

Should I stop sending Purchase on COD orders entirely?
No. Meta needs conversion volume to optimise at all, and suppressing Purchase leaves it with nothing. Send it with a corrected value, or send it later at delivery confirmation.
What acceptance rate is normal for COD?
It varies enormously by market, offer and delivery partner — commonly anywhere from 50% to 85%. Use your own measured figure, never a benchmark.
Does deduplication still work if I delay the event?
Yes, as long as both copies carry the same event ID derived from the order. The delay does not affect the deduplication key.

Read next

Other store setups