Skip to main content

Status-Driven Meta (Facebook) Conversion Tracking with the Conversions API

· 7 min read
Aleksandar Vucenovic
Chief Growth Officer

How to configure the Pixel Manager so Facebook (Meta) conversions are recorded only when WooCommerce confirms the order is in a paid state, using the Conversions API as the single source of truth.

When you actually need this

WooCommerce orders move through three broad outcomes after checkout. Each one is handled differently by the standard tracking setup:

  1. Order fails immediately. The payment gateway rejects the charge during checkout and the order goes straight to failed. The customer never reaches the thank-you page, the browser pixel does not fire, and CAPI is not triggered (it only listens to paid-status transitions). Nothing is sent to Meta. No action needed.
  2. Order is paid immediately. Most stripe-style and PayPal-style integrations finalize payment during checkout. The order lands on the thank-you page already in processing (or completed), the browser pixel fires, CAPI fires, both share the same event_id, Meta deduplicates them, and the conversion is recorded once. This is the normal, ideal case. No action needed.
  3. Order goes to processing but may still fail or never get paid. Bank transfers, invoices, BNPL, manual review flows, and some local payment methods land the order on the thank-you page in a state that looks successful but has not been confirmed by the gateway. The browser pixel fires immediately, so the conversion is recorded in Meta, even if the order is later cancelled or never gets paid.

The industry-standard behavior, including the Pixel Manager's default, is to track everything that does not immediately fail. The reason is simple: most stores' checkouts fall into category 2, and the small leakage from category 3 is usually outweighed by the cost of waiting (lost attribution, missed view-through windows, broken click-to-conversion paths in Meta's optimizer). Tracking on the thank-you page is fast, accurate for the common case, and matches what Meta expects.

The configuration in this article is for stores where category 3 is significant enough to distort their numbers and ad optimization, and they are willing to accept the tradeoffs to fix it.

What the Conversions API is, and what it is not

The Conversions API was not built to enable status-driven conversion tracking. Its primary purpose is tracking reliability: it sends events from your server directly to Meta, bypassing ad blockers, browser extensions, network-level filters, and increasingly aggressive browser privacy controls 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.

For this niche scenario, we repurpose CAPI: instead of running it as a backup to the browser pixel, we make it the only sender for purchase events, and rely on its built-in status-driven trigger to delay the conversion until the order is actually paid.

Important limitation: the 7-day window

Meta's Conversions API only accepts events with an event_time within the last 7 days. If an order sits in processing for longer than 7 days before it is marked paid (or cancelled), the conversion can no longer be sent to Meta and is permanently lost from a tracking perspective. This is a hard cutoff on Meta's side, not something the Pixel Manager can work around.

For most payment methods this is a non-issue. For bank transfers, invoices, or other slow-confirming payments, it is a real constraint to weigh against the benefit of cleaner data.

How the Pixel Manager handles purchase events by default

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

  1. Browser pixel 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 WooCommerce's wc_get_is_paid_statuses() (typically processing and completed). 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 the browser and server-side hits.

The implication is important: CAPI is already status-driven. Failed, cancelled, pending, or otherwise non-paid orders never reach Facebook through the CAPI pipeline. The only path that records non-paid orders as conversions is the browser pixel firing on the thank-you page.

So a "status-driven" setup reduces to one technical change: stop the browser pixel from firing the purchase event, and let CAPI deliver it instead.

Required configuration

1. Enable Facebook CAPI

In the Pixel Manager settings, enable Facebook Conversion API. CAPI is what delivers the purchase event to Meta in this setup.

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, so product feeds keep working.

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. See the Event Filters reference for the full filter pipeline.

/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);

That is the entire required change.

With the browser purchase event suppressed:

  • CAPI is the only sender for purchase events, so browser/server deduplication is no longer a concern.
  • All other Facebook events (page_view, add_to_cart, view_item, begin_checkout, etc.) continue to fire from the browser as normal.
  • Conversions appear in Meta when WooCommerce transitions the order into a paid status. For most payment gateways this is essentially immediate. For offline or manually approved payments, the conversion is recorded when the order moves into a paid state.

Optional: stricter "paid" definition

The Pixel Manager 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, use the server-side filter pmw_server_event_payload_facebook_purchase.

The order ID is encoded in the payload's 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. See PHP Filters for the full server-side pipeline.

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 not part of the public Pixel Manager API. It can change between releases.

Same pattern for other platforms

Every platform with a server-side counterpart in the Pixel Manager follows the same filter naming pattern. 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

For a condensed reference of these snippets, see the Status-Driven Purchase Conversions recipe.

Interested to get updates?

Sign up to our monthly newsletter today.