Tracking & Attribution

Should a WooCommerce Bank Transfer Order Fire a Purchase Event Before It's Paid?

WooCommerce bank transfer orders fire Purchase before they're paid. Why it happens, what it costs, and how to send the event only once the order is paid.

Quick answer

No. A bank transfer order is a promise to pay, not a sale, so the Purchase event should fire when the order moves from On hold to Processing — the moment you confirm the money arrived. WooCommerce puts bank-transfer orders on hold and shows the thank-you page straight away, which is why a thank-you-page pixel counts them early. Fire Purchase server-side on the status change, and send payment inside Meta's 7-day event window.

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

No. A WooCommerce bank transfer order should fire its Purchase event when the order is marked paid — when it moves from On hold to Processing — not when the shopper clicks Place order. Until the transfer lands, the order is a promise. Counting it as a sale inflates your purchase count and teaches Meta to find people who order but never pay.

The early fire isn’t a bug in your pixel. WooCommerce’s built-in bank transfer method puts the order on hold and sends the shopper to the order-received page immediately, with your bank details on it. Any pixel on that page sees a finished checkout.

Why does the pixel fire before a bank transfer is paid?

Because WooCommerce shows the thank-you page as soon as the order is placed, and the payment happens later, outside your site. The built-in “Direct bank transfer” gateway (called BACS in the code) sets the order to On hold, empties the cart and redirects to the order-received page. A Purchase fired on that page fires for every order, paid or not.

You can see it in WooCommerce’s own source. In the bank transfer gateway’s process_payment() function, an order with a total above zero is set to On hold with the note “Awaiting BACS payment”, then the shopper is sent to the thank-you page. The gateway also hooks the thank-you page to print your account details. The cheque gateway does the same with “Awaiting check payment.”

So the sequence is:

  1. Shopper places the order. Status: On hold.
  2. Thank-you page loads with your bank details. Your pixel fires Purchase here.
  3. Days pass. Some shoppers transfer the money. Some never do.
  4. You see the money in your bank and change the order to Processing. This is the actual sale.

A server-side setup that fires when the order is created has the same problem, just on the server. The trigger is what matters, not the channel.

What about boleto and Pix?

Boleto and Pix are Brazilian payment methods, and WooCommerce supports them through third-party gateway plugins, not the core. Most leave the order in Pending payment or On hold until the gateway confirms the payment. A boleto has to be paid at a bank or app before its due date, so the gap can run days. Check your gateway’s settings to see which status it uses before payment and which it sets after.

What does firing Purchase at order placement cost you?

It costs you accurate numbers and a clean optimisation signal. Every unpaid bank transfer order becomes a Purchase in Events Manager, so reported purchases and ROAS sit above what you were paid. Worse, Meta’s delivery system learns from those events, so it looks for more people who place an order and walk away from the payment.

Two things make it worse with bank transfers specifically:

  • On-hold orders don’t clean themselves up. WooCommerce’s automatic cancellation of unpaid orders only looks at orders in Pending payment, and only runs when stock management is on and a hold-stock time is set (the option defaults to 60 minutes). Bank transfer orders sit in On hold, so they stay there until you cancel them. Your order list quietly fills with unpaid orders that Meta already counted.
  • Meta doesn’t un-count them. Cancelling the order in WooCommerce doesn’t remove a Purchase Meta already received. Sending another event to “correct” it just adds a second purchase.

If your checkout offers only cards, this barely matters. If bank transfer is a meaningful share of your orders — as it is in some markets and in many B2B stores — it can skew every campaign decision you make off Ads Manager.

What does waiting for payment cost you?

It costs you speed. A Purchase sent at payment reaches Meta hours or days after the click, and Meta optimises on fewer, later events. Meta also enforces a limit: a server event’s event_time can’t be more than seven days in the past when you send it. A transfer that clears after a week needs handling.

The delay matters less than it sounds. Meta compares the event’s time with the click’s time, so a sale two days late still lands against the right ad if it falls inside your attribution window. What you lose is fast feedback: results fill in over days, not hours.

What if the transfer arrives more than seven days later?

Then an event stamped with the original order time can’t be sent as-is. Use the time of payment as the event time — that’s when the sale actually happened — or clamp it to the edge of the window. The 7-day event time window in Meta CAPI explains the rule and the options. The simplest fix is operational: reconcile your bank account daily, not monthly.

So when should the Purchase event fire?

Fire Purchase when the order reaches Processing or Completed, and nothing earlier. If you want an earlier signal for Meta to learn from, send a different event at order placement — AddPaymentInfo or a custom “order placed” event — never a second Purchase. That keeps your purchase count equal to money received, and gives the algorithm something to work with in the meantime.

Timeline of a WooCommerce bank transfer order: the order is placed and set to On hold, the thank-you page loads with bank details, and nothing is sent; two days later the store marks the order Processing and a server-side Purchase is delivered to Meta with its event_id, inside the 7-day event window

Here’s how the options compare:

Setup Purchase count Signal speed Risk
Purchase on thank-you page Inflated by unpaid orders Immediate Meta optimises toward non-payers
Purchase on order created (server) Inflated by unpaid orders Immediate Same problem, harder to spot
Purchase on Processing Matches money received Delayed until marked paid Late sends past 7 days
Early non-Purchase event + Purchase on Processing Matches money received Early proxy, true sale later Two events to maintain

What about cash on delivery?

Cash on delivery works differently, and it catches people out. WooCommerce’s built-in COD gateway sets the order to Processing at checkout by default (On hold only if the order contains a downloadable item). So any setup that sends Purchase on Processing sends a COD order when it’s placed, before the courier collects. If you want COD to wait, the core exposes a filter, woocommerce_cod_process_payment_order_status, to start those orders On hold instead.

How do you move the Purchase to the moment of payment?

Stop firing Purchase on the thank-you page, and send it from the order record when the status changes to Processing. A server event triggered by that status change carries the payment decision with it, and it doesn’t depend on the shopper’s browser. Then test it with one real bank transfer order.

  1. Check your pixel plugin’s status options. Some plugins let you choose which order statuses fire Purchase. Limit it to Processing and Completed.
  2. Switch off the thank-you page Purchase. A pixel on the order-received page can’t know if the transfer will arrive. Turn its Purchase off or make it conditional on a paid status.
  3. Send Purchase server-side on the status change. This is the architecture in the guide to tracking WooCommerce purchases server-side to Meta, delivered through the Conversions API. It also fixes orders whose buyers never see the thank-you page, like WooCommerce orders paid with PayPal.
  4. Keep one source per event. If two tools send Purchase with different event ids, Meta counts both.
  5. Test it. Place a bank transfer order and watch Events Manager’s test events tool — the same check used to confirm your Meta CAPI is working. Nothing should arrive. Mark it Processing; one Purchase should.

Because the sale may come days after the click, attribution has to survive the gap. The buyer’s email on the order is what ties it back to the session — the same problem as attributing a purchase weeks after the ad click.

How does PartialLeads handle WooCommerce bank transfer orders?

PartialLeads sends a Purchase only when a WooCommerce order is paid — Processing or Completed. It receives the store’s order webhooks, including later status updates, so a bank transfer order sits On hold and is not sent, then is sent when you mark it Processing. The order record, not a page visit, decides when the conversion goes out.

Nothing fires on the thank-you page. The PartialLeads WooCommerce plugin forwards view product, add to cart and begin checkout server-side to Meta, Pinterest and TikTok. The Purchase is owned by the order webhooks. An on-hold order produces no Purchase however many times the order-received page is loaded.

What it sends when the order is paid. One Purchase per paid order, at the full order total including tax and shipping after discounts, with hashed email and phone from the order. It goes to each connected platform — Meta, Pinterest, TikTok — and as a row in the Google Sheet you import into Google Ads. Each event has a deterministic event_id, so a redelivered webhook can’t send the same order twice. If a transfer is marked paid late enough that the event would fall outside Meta’s seven-day window, the event time is clamped into the window rather than rejected.

Tying the late sale back to the click. The order’s email and phone are matched to the visitor’s earlier sessions, so a Purchase marked paid three days later still carries the campaign that brought the buyer in.

PartialLeads dashboard after a week of bank transfer orders: the Purchases ledger lists only the paid orders with source, session match and order total, and the Meta CAPI activity log beside it shows one Purchase per order, each sent at the time the order was marked Processing, days after it was placed

Where you see it working. The Purchases ledger lists each paid order with its value, source and session match; its count should equal your Processing plus Completed orders for the same days. The Meta CAPI activity log shows each server Purchase with its status and timestamp, so you can see it went out when the order was marked paid, not when it was placed. The Attribution report’s Time to Purchase shows how long buyers take from first touch to paid order.

The honest constraints. PartialLeads follows WooCommerce’s status: a COD order your store sets to Processing at checkout is sent then. An order is recorded once, so editing a paid order later doesn’t update or re-send it. Event ids are PartialLeads’ own and don’t deduplicate against another plugin’s browser pixel — if Meta for WooCommerce or PixelYourSite still fires Purchase on the thank-you page, switch theirs off or unpaid orders keep counting through them. WooCommerce Subscriptions renewals are recorded but not sent. PartialLeads controls which orders are sent and when; how Meta matches and attributes them is Meta’s half.

What breaks The mechanism Where you see it in the dashboard
Thank-you page fires Purchase before payment Plugin fires nothing on order-received; Purchase comes from order webhooks Meta CAPI activity log
On-hold bank transfer orders counted as sales Purchase sent only at Processing or Completed Purchases ledger
Transfer paid days after the order Status-update webhook triggers the send; event time clamped to Meta’s 7-day window CAPI activity log timestamps
Late sale loses its campaign Order email and phone matched to earlier sessions Attribution report, Time to Purchase
Another plugin still fires Purchase No cross-tool dedup — keep one source per event Leads-list API column vs Events Manager

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Sources


Frequently asked questions

QShould the Meta Purchase event fire when a bank transfer order is placed?
No. At placement the order is On hold and no money has moved. Fire Purchase when you mark the order Processing after the transfer arrives. If you want an earlier signal, send a different event at placement, such as AddPaymentInfo, so your purchase count still matches money received.
QWhy does WooCommerce show the thank-you page before a bank transfer is paid?
Because the payment happens outside your site. The built-in bank transfer gateway sets the order to On hold, empties the cart and sends the shopper to the order-received page to show your account details. The page means "order received", not "paid", but a pixel on it can't tell the difference.
QDo unpaid bank transfer orders get cancelled automatically in WooCommerce?
Not by default. WooCommerce's automatic cancellation only targets orders in Pending payment, and only when stock management and a hold-stock time are set. Bank transfer orders sit in On hold, so they stay until you cancel them by hand or with a plugin.
QWhat happens if the transfer arrives more than seven days after the order?
Meta won't accept a server event whose event_time is more than seven days in the past. Send the Purchase with the payment time, which is when the sale actually happened, or clamp the timestamp into the window. Reconciling your bank account daily avoids the problem in most cases.
QWill a delayed Purchase still be credited to the right Meta ad?
Usually, if it lands inside your attribution window. Meta compares the event time with the click time, so a sale two days later is still credited. It helps a lot to send the buyer's hashed email and phone, and the click identifiers captured at the visit, so Meta can match the late event to the person who clicked.
QShould cash on delivery orders fire Purchase at checkout?
That's your call, but know the default. WooCommerce's cash on delivery gateway puts orders straight into Processing unless they contain a downloadable item, so a tool that sends on Processing sends COD orders at checkout. If many COD orders are refused at the door, start them On hold with the gateway's status filter.

Find the qualified leads your forms are currently throwing away.

Install PartialLeads on one landing page, send traffic, and compare what your CRM captured against what PartialLeads recovered and qualified.