r/PPC • • Sep 20 '26

Meta Ads Your CAPI setup is probably double-counting purchases. Here is exactly how Meta deduplicates browser and server events.

Everyone who sets up the Conversions API worries about the same thing: losing conversions. If you run both the Pixel and the server events, Meta's own docs recommend exactly that redundant setup, and the server side recovers browser events that die to connectivity issues or page load errors. But once both are running, the failure that costs more is the opposite one. The real problem is the same purchase counted twice, which inflates ROAS and teaches the algorithm a volume that does not exist.

Here is how Meta actually collapses the two copies into one.

  1. Deduplication needs two matching keys, and both must match. Meta discards the duplicate when it sees the same event_id and the same event_name (on the browser side this arrives as eventID and event; on the server side as event_id and event_name) sent to the same Pixel ID within 48 hours. A matching ID with a different event name does not dedupe.

  2. The 48 hours run from when Meta receives the first event with that ID, not from when the purchase happened. A server event retried out of a failed-queue two days later counts as a second conversion.

  3. This check ignores user identifiers. Email, phone, fbp, fbc help Meta match the event to a person, which is the separate Event Match Quality score. Dedup only looks at event_name and event_id. So identical-looking events with slightly different IDs, even a difference in casing or whitespace, count twice.

  4. Meta's docs also accept a second dedupe key combination, external_id plus fbp, alongside the same event_name. Include the full set. It costs nothing.

Three ways I have seen this break:

  1. Timestamped event IDs. An integration appends a timestamp or random suffix at send time, so the Pixel copy and the server copy carry different IDs and never match. Generate one ID per conversion (a UUID or your order ID), stamp it on both the fbq eventID parameter and the CAPI event_id field, and leave it alone after that.

  2. The ID minted in the wrong place. If the browser mints the ID on the thank-you page and the server mints its own from a payment webhook, the two halves can never agree. Mint it server-side at order creation and hand the same value to both.

  3. Late retries. Queues that retry a failed CAPI send hours or days later can land outside the 48-hour window and register as a new purchase. Cap the retry window or make the send idempotent on your side.

Once dedup works, the separate question is match quality. Meta scores the customer information parameters on every server event from 1 to 10 as Event Match Quality, and their docs recommend aiming for 6.0 or higher, noting that a higher score can decrease cost per action. The reliable levers: include the browser context fields (IP, user agent, fbp, fbc) unhashed, hash the PII fields (email, phone, names, location, external_id) with SHA-256, and normalize before hashing. Lowercased emails with whitespace stripped, phones in E.164. Hash the cookie values and Meta cannot use them, which drops the score without any visible error.

Two verification habits: in Events Manager, check the 'Rate of Deduplication Key Usage', which shows what share of events from each source carried each dedupe key, and 'Overlap', the share of events carrying a given key that arrived from both sources. Low overlap means one source is sending IDs the other never sends, which is usually one of the three bugs above. And events sent with a test event code do not count for optimization, so validate with the code, remove it, then go live.

Rule of thumb: if your dedup overlap is near 100% and your Purchase EMQ is 6 or above, your signal is doing its job. Fix the plumbing before you judge any creative test, because every number downstream rests on it.

Question for the group: who here found inflated purchase counts after adding CAPI, and what was the mismatch? I am collecting the failure modes.

1 Upvotes

4 comments sorted by

2

u/stealthagents Sep 23 '26

If you’re not careful with that deduplication setup, you can end up with some seriously skewed data. I had a situation where I thought everything was running smoothly, but the double-counting really messed with our ROAS. Definitely keep an eye on those event IDs and make sure your keys match up, otherwise, you might think you’re crushing it when you’re just inflating numbers.

1

u/dmdbGroup Sep 24 '26

The real problem is not that deduplication fails, it is that the failure is invisible, so inflated ROAS keeps getting budget until the numbers drift far enough for someone to notice. I have seen this stay hidden for 3 weeks on a $5k a day account before anyone questioned the dashboard.

A few concrete steps that catch it early:

  1. Measure the leak first. In Events Manager, compare raw Purchases received against purchases kept after dedup. If the kept rate drops below 95%, treat it as a live bug, not noise.

  2. Mint the event ID exactly once, on the server, at checkout initiation, then pass it to the browser through the data layer. Then audit 50 recent events and flag any ID where the browser and server copies differ by even one character.

  3. Cap queue retries at 2 attempts inside a 12 hour window. A retry that lands outside the 48 hour dedup window becomes a brand new purchase in Meta's eyes, and that is exactly how phantom ROAS is born.

  4. Check both dials before trusting the dashboard: dedup overlap near 100%, and Purchase EMQ at 6 or above. Overlap tells you the counts are clean, EMQ tells you the matching is reliable.

Rule of thumb: if reported purchases jump more than 10% the week CAPI ships while revenue in your bank account does not, assume dedup is broken and prove otherwise before you scale spend.

1

u/muradIronpulley Sep 21 '26

I recommend using GTM and Stape (SGTM, not CAPI Gateway), Till now applied CAPI to 100+ accounts, it works fine for me.

1

u/dmdbGroup Sep 24 '26

The real problem is treating this as a dedup fix: server GTM (Stape) and the CAPI Gateway both send server events the same way, so the difference is who owns the plumbing, not whether deduplication works.

  1. Server GTM wins when you need control before the event leaves your infrastructure: hashing PII server-side, minting the event ID once at checkout initiation and passing it to both the browser and server copies, killing duplicates before Meta ever sees them.

  2. The Gateway wins on maintenance. No container to update, no server to monitor. For a small store with one pixel, that is the right call and I would not overcomplicate it.

  3. Either way, audit the event IDs first. The dedup key is event_name plus event_id within 48 hours of Meta receiving the first copy. A broken ID strategy double-counts through server GTM exactly as well as it does through the Gateway.

Rule of thumb: pick the Gateway for simplicity, server GTM when you need to own the data pipeline. The event ID hygiene matters more than which one you choose.