← All posts

Every sale counted twice: broken deduplication between the Pixel and the Conversions API

When the Pixel and the Conversions API send the same purchase with different event_ids, Meta can't deduplicate it and counts it twice. How to share one ID.

Step 1 of 6 An order is confirmed. The Pixel sends Purchase from the browser, with its eventID.
  1. An order is confirmed. The Pixel sends Purchase from the browser, with its eventID.
  2. The server sends the same Purchase through the Conversions API, but with another event_id.
  3. Meta only merges a browser and a server event when the ID and the name match. Here they don't: it keeps both.
  4. The cause: each side makes up its own ID, so they never match.
  5. The fix: create the ID once, like the order number, and send it from both sides.
  6. Check it in Events Manager: deduplication goes up and purchases match the orders again.

Meta recommends sending the same events through two channels: the Pixel, from the browser, and the Conversions API (CAPI), from the server. If one of them fails (an ad blocker, a declined cookie, a confirmation page that never finishes loading), the other fills the gap. But that redundancy comes with a condition: Meta has to know that the browser Purchase and the server Purchase are the same purchase. If it can’t pair them, it keeps both.

What a duplicate purchase looks like in Meta

An order is confirmed and two Purchase events reach Meta: one through the browser connection and one through the server. Since each one carries a different identifier, Meta doesn’t merge them. The typical symptoms:

  • Purchases in Events Manager and Ads Manager are clearly above the real orders in the backend, sometimes close to double.
  • ROAS and cost per purchase suddenly improve after turning on the Conversions API, with no change in sales.
  • Campaigns optimize on conversions that never happened, and purchaser audiences fill up with duplicates.

Why Meta doesn’t deduplicate the event

Meta deduplicates a browser event and a server event when two pairs of keys match: the Pixel’s eventID with the Conversions API’s event_id, and the Pixel’s event name with the server’s event_name. They also have to reach the same Pixel within 48 hours of the first one. When they match, Meta discards the one that arrives later. If any of those conditions fails, it counts both. The most frequent causes:

  • Each side makes up its own ID. The browser creates a random identifier and the server creates another. This is the most common case: both events carry an ID, but they never match.
  • The Pixel doesn’t send the eventID, or sends it the wrong way. It goes in the fourth argument of fbq, not inside the event parameters: fbq('track', 'Purchase', {value: 49.90, currency: 'EUR'}, {eventID: 'T-10482'}). Put it in the third object and it travels as one more custom parameter, not as the deduplication key.
  • The ID gets lost on the way. In setups with a GTM web container and server-side GTM, the web container generates the ID for the Pixel but doesn’t pass it in the request to the server, and the Conversions API tag creates a new one.
  • The event name doesn’t match. For example, Purchase in the Pixel and a custom event on the server: even with the same ID, Meta sees two different events.
  • The server event arrives more than 48 hours late. Outside that window, Meta no longer deduplicates.

There is an alternative method that pairs events by fbp or external_id instead of an event ID, but it has limits: it generally only works when the browser event arrives before the server event, and it doesn’t deduplicate when there is only one source. It’s not something to rely on for purchases.

How to find the duplicate purchase

  1. In Events Manager, open the Pixel’s dataset, go to Overview and open the details of the Purchase event. In the Event Deduplication tab, look at the rate of events deduplicated and the deduplication key usage per source. Low overlap means the keys don’t match or only one source sends them; Meta shows a warning when the deduplication rate is too low.
  2. Compare one day of purchases in Events Manager with the backend orders for that day. If Meta’s figure is close to double, a duplicate is almost certain.
  3. Make a test purchase. In the developer tools, Network tab, filter by facebook.com/tr and find the eid parameter of the Purchase request: that is the Pixel’s eventID. Compare it with the event_id the server sends, in its logs or in the server-side GTM preview.
  4. If you use the Test events tool in Events Manager, check that the browser Purchase and the server Purchase carry the same ID.

How to send a single ID from the Pixel and the server

There’s one rule: the ID is created once and travels to both sides.

  • For purchases, use an identifier that already exists and both sides know: the order or transaction number. Meta’s own documentation suggests it.
  • For events without a natural identifier (a Lead, an AddToCart), generate a random value in the browser and send it to the server too: in the dataLayer, in the request to server-side GTM or in the call to your backend. Meta accepts a random value as long as it’s the same in the browser and on the server.
  • Use exactly the same event name on both sides.
  • Send the server event right away, not hours later, so you always stay inside the 48 hours.

Meta’s documentation: Handling duplicate Pixel and Conversions API events and Server event parameters.

How to check each purchase counts once

  • In a test purchase, the eid of the Pixel request and the server’s event_id are identical, and so is the event name.
  • In the Event Deduplication tab, the rate of events deduplicated and the key overlap go up over the following days.
  • Purchases in Events Manager come back to a reasonable distance from the backend orders. Events already duplicated aren’t corrected: if you compare periods, note the date of the change.

The IDs, figures and values in the example are illustrative.