Skip to main content

Status-Driven Purchase Conversions

Record Facebook (and other platforms') purchase conversions only when WooCommerce confirms the order is in a paid state, using the platform's Conversion API as the single source of truth.

When you need this recipe

WooCommerce orders fall into three broad outcomes after checkout:

  1. Order fails immediately. Customer never reaches the thank-you page. Nothing fires. No action needed.
  2. Order is paid immediately (most Stripe/PayPal-style integrations). Browser pixel fires on the thank-you page, CAPI fires on the paid-status transition, both share the same event_id, Meta deduplicates them. This is the normal case. No action needed.
  3. Order goes to processing but may still fail or never get paid (bank transfer, invoice, BNPL, manual review). The browser pixel fires on the thank-you page and records the conversion, even if the order is later cancelled or never paid.

This recipe addresses case 3.

The Pixel Manager's default behavior tracks everything that does not immediately fail because most checkouts fall into case 2 and waiting on a paid status hurts attribution and Meta's optimizer for the common case. Use this recipe only when case 3 is frequent enough in your store to distort the numbers.

What CAPI is and is not

The Conversions API was built for tracking reliability: it sends events from the server directly to Meta to survive ad blockers, browser privacy controls, and network filters that suppress the browser pixel. In the standard setup, CAPI runs alongside the browser pixel as a backup, and Meta deduplicates the two via event_id. This recipe repurposes CAPI as the only sender for purchase events to take advantage of its built-in status-driven trigger.

7-day limitation

Meta's Conversions API only accepts events with an event_time within the last 7 days. If an order sits in processing longer than 7 days before transitioning to a paid status, its conversion is permanently lost. This is a hard limit on Meta's side.

How the Pixel Manager handles purchase events by default

For Facebook, the Pixel Manager fires the purchase event from two places:

  1. Browser pixel - fires on the order received (thank-you) page, regardless of the order's payment status.
  2. Conversion API (CAPI) - registered on woocommerce_payment_complete and on every woocommerce_order_status_{paid_status} transition (paid statuses come from wc_get_is_paid_statuses()). A meta-key guard on the order prevents double-fires across these hooks.

Both events share the same event_id (pmw_{order_id}), which is how Facebook deduplicates them.

This means CAPI is already status-driven: failed, cancelled, and other non-paid orders never reach Facebook through the server-side pipeline. The only thing that records non-paid orders as conversions is the browser pixel firing on the thank-you page.

Recipe

To record conversions strictly when the order reaches a paid state, do two things:

1. Enable Facebook CAPI

In the Pixel Manager settings, enable Facebook Conversion API. This is what makes CAPI the source that delivers the purchase event to Meta.

Enabling Facebook in the Pixel Manager also disables the tracking pixel from the Meta for WooCommerce plugin if it is installed. Catalog sync from Meta for WooCommerce is not affected.

2. Suppress the Facebook browser pixel for purchase events

Add a JavaScript filter that returns null for purchase events on the Facebook pixel. Returning null from a pmw_pixel_data_{pixel} filter blocks that pixel from firing for the matched event.

/wp-content/themes/child-theme/functions.php
add_action('wp_head', function() {
?>
<script>
window._pmwq = window._pmwq || [];
window._pmwq.push(function() {
pmw.hooks.addFilter(
'pmw_pixel_data_facebook',
'my-store/status-driven-purchase',
function(pixelData, eventName) {
if (eventName === 'purchase') {
return null;
}
return pixelData;
}
);
});
</script>
<?php
}, 1);

With the browser purchase event suppressed, CAPI is the only sender, dedup is no longer relevant, and conversions appear in Meta when WooCommerce transitions the order into a paid state. For most payment gateways this is essentially immediate; for offline or manually approved payments, the conversion is recorded the moment the order moves into a paid status.

Optional: stricter "paid" definition (server-side filter)

The Pixel Manager already gates CAPI on wc_get_is_paid_statuses(), which by default includes processing and completed. If your store needs a narrower definition (for example: only completed, never processing), use the server-side filter for the Facebook purchase event.

The order ID is encoded in event_id as pmw_{order_id}. Parse it and load the order:

/wp-content/themes/child-theme/functions.php
add_filter('pmw_server_event_payload_facebook_purchase', function($pixel_data, $pixel_name, $event_name) {

if (empty($pixel_data['event_id'])) {
return $pixel_data;
}

$order_id = (int) str_replace('pmw_', '', $pixel_data['event_id']);
$order = wc_get_order($order_id);

if (!$order) {
return $pixel_data;
}

// Custom rule: only completed orders count as paid.
if ($order->get_status() !== 'completed') {
return null;
}

return $pixel_data;
}, 10, 3);

Returning null from this filter blocks the CAPI event for the matched pixel and event.

Optional: manually re-fire CAPI for an order

If a custom workflow needs to push a CAPI purchase event for a specific order (for example from a custom hook), call the platform's static send_purchase_hit() method with the order object:

\SweetCode\Pixel_Manager\Pixels\Facebook\Facebook_CAPI::send_purchase_hit($order);

This is an internal method and is not part of the public Pixel Manager API. It can change between releases.

Same pattern for other platforms

The same approach works for every platform that has a server-side counterpart in the Pixel Manager. Replace the pixel slug in both filter names.

PlatformJavaScript filterPHP server-side filter
Facebook / Metapmw_pixel_data_facebookpmw_server_event_payload_facebook_purchase
TikTokpmw_pixel_data_tiktokpmw_server_event_payload_tiktok_purchase
Pinterestpmw_pixel_data_pinterestpmw_server_event_payload_pinterest_purchase
Snapchatpmw_pixel_data_snapchatpmw_server_event_payload_snapchat_purchase
Redditpmw_pixel_data_redditpmw_server_event_payload_reddit_purchase
Google Analytics 4pmw_pixel_data_google_analyticspmw_server_event_payload_google_analytics_purchase

Troubleshooting

  • Conversions still appear for failed orders. The browser pixel filter is not active. Confirm the snippet is rendered in the page source and that pmw.hooks is defined when it runs (this is what the _pmwq queue guarantees).
  • No conversions appear at all. Confirm Facebook CAPI is enabled in the Pixel Manager settings and that the access token is valid. Check the Pixel Manager logs for the CAPI request.
  • Conversions appear later than expected. That is the expected behavior. CAPI fires when WooCommerce transitions the order into a paid status, not when the customer lands on the thank-you page.

Make more money from your ads with high-precision tracking