Your store did 100 orders yesterday. Meta Events Manager shows 195 purchases. The cause in almost every case I audit: the browser pixel and the Conversions API both send a Purchase event for the same order, and they carry no shared event_id, so Meta has no way to know it is one sale and counts it twice.
This is not a display bug. The doubled events feed campaign optimization and reported ROAS. Your ads look twice as profitable as they are, and budget decisions get made on that number. Here is how the deduplication mechanism works, how to confirm it is broken, and how to fix it.
Running the pixel and the Conversions API together is the correct setup. Meta recommends it because the server event survives ad blockers and browser restrictions. The system is designed to receive the same purchase twice and merge it. The merge has one rule:
The match is a literal string comparison. order_10471 does not match 10471. Note the naming difference: in the browser pixel the parameter is eventID (an option on the fbq call), in the Conversions API payload it is event_id. Different spelling, but the values must be identical.
If the IDs never match, or one side sends no ID at all, Meta treats every order as two independent purchases. There is no reliable fallback you control. The event_id is the whole mechanism.
Open Events Manager, select your pixel dataset, and click into the Purchase event details. Three things to check:
Then run a live check in the Test Events tab: place a test order and watch. You should see two Purchase events arrive within seconds, event IDs visible on both, and the second one labeled Deduplicated. If both show up and neither carries that label, you have your confirmation.
I see the same handful of broken configurations on repeat:
Common thread: both sides sending is fine, both sides inventing their own ID is not.
Derive the event_id from the order itself, deterministically, and use the identical string on both channels. Order number or order ID is the right key: both the browser and the server already know it, and it never changes on retries.
fbq('track', 'Purchase',
{ value: 89.00, currency: 'EUR' },
{ eventID: 'order_10471' }
);Conversions API payload for the same order:
{
"data": [{
"event_name": "Purchase",
"event_id": "order_10471",
"event_time": 1767800000,
"action_source": "website",
...
}]
}In a server GTM setup, push the order ID into the dataLayer on the purchase page, map it into the web Meta pixel tag's event ID field, and make sure the same value rides to the server container and into the Event ID field of the Conversions API tag there. One value, one source, two destinations.
If your plugin does not let you control the event_id, replace it or disable one of its channels. Do not run two full pixel-plus-CAPI stacks side by side and hope.
Do not declare this fixed until you have watched a real event travel both paths with the same ID. My verification pass:
Your browser pixel and your Conversions API integration are both reporting each order as a separate Purchase event. Without a matching event_id on both events, Meta cannot deduplicate them, so every order counts twice. A ratio near 2x almost always means dedup is fully broken rather than a tracking gap.
Yes. Meta deduplicates only when event_name and event_id both match as literal strings, within a 48-hour window. The browser parameter is spelled eventID and the server parameter event_id, but the values must be character-for-character the same.
No. The redundant setup exists for a reason: the server event survives ad blockers and browser privacy restrictions, while the browser event contributes signals the server often lacks. Fix the shared event_id instead of amputating a channel.
Only if it is generated once and passed to both the pixel and the server event. Two sides independently generating random IDs will never match. An ID derived from the order number is safer because both sides already know it and webhook retries produce the same ID instead of a new duplicate.
I set up and repair pixel plus Conversions API deduplication for stores most weeks, usually in a day. If you would rather have it checked and fixed than debug it yourself, email work@rytisbalys.com with your store URL.
work@rytisbalys.com