EventId deduplication between Pixel and Conversions API
Why duplicate Lead events distort your Meta Ads bidding, and how to deduplicate Pixel and CAPI properly. The eventID rules, common pitfalls, and a verification checklist.
The Conversions API doesn't replace the Pixel — it complements it. Meta's recommendation is to run both, then deduplicate. The mechanism is event_id (called eventID in the Pixel API, event_id in CAPI). Get this wrong and you double-count your Lead events, throwing off the optimizer that decides what to bid for.
This is what eventID actually does, why duplicates happen anyway, and how to verify you got it right.
What deduplication actually does on Meta's side
When the Pixel and CAPI both report an event with the same eventID and same event_name within 48 hours, Meta merges them into one. If only one of the two arrives, Meta keeps that one. If both arrive but the IDs don't match, both are kept — that's the failure case. You see inflated conversions; the bidder over-spends on retargeting; CPA looks worse on the report than it really is, so you might cut a winning campaign.
There are a few subtle rules:
- Same event_name matters.
Leadfrom CAPI does not dedupe againstPurchasefrom Pixel, even with the same eventID. - 48 hours is the window. If your CAPI call is delayed past that (e.g., webhook retries, queue lag), you get duplicates.
- Hash field consistency helps. Meta's docs are clear: matching
external_id,em, orphstrengthens the dedupe even if eventID alone doesn't trigger.
Where eventID should be generated
Generate it once, client-side, before either call fires. A v4 UUID is fine. Persist it through the form submission so both the Pixel call (browser) and the server-side CAPI call (your backend) use the exact same string.
A common anti-pattern: generating eventID server-side at the moment of the CAPI call, then trying to backfill it to the Pixel. That doesn't work — the Pixel call already happened. The right order is:
- User clicks Submit.
- Client generates
eventID = crypto.randomUUID(). - Client calls
fbq('track', 'Lead', {...}, { eventID }). - Client POSTs to your
/api/leadswitheventIDin the body. - Server forwards to CAPI with
event_id: eventIDin the same payload.
If you fire the Pixel only on a thank-you page redirect, the eventID must travel through the redirect (query string or sessionStorage) so the Pixel call uses the same ID the server already saw.
Idempotency: a separate problem
Deduplication is for Pixel vs CAPI. It does not protect you from a single client double-submitting the form (e.g., user clicks twice, or refreshes the success page). That's idempotency, and it belongs on your server.
Pattern: store the eventID in your database with a unique constraint. On a duplicate POST, return 200 silently with the same response — but don't forward to CAPI a second time. This is independent of Meta's dedupe and protects you regardless of what Meta does on its side.
Common pitfalls
Pitfall 1 — Two eventIDs. A frontend dev generates eventID_a for the Pixel, the backend dev generates eventID_b for CAPI. Both arrive at Meta. Both count. CPA reporting is wrong by ~2×.
Pitfall 2 — eventID truncation. Some integrations URL-encode UUIDs and truncate them at the storage layer. 9e1b6b8a-6c0e-4f8d-bce1-c4a3a6f4d2b1 becomes 9e1b6b8a-6c0e-4f8d. Same prefix, different value at Meta's end → no dedupe.
Pitfall 3 — event_time drift. If the Pixel event arrives at 14:00:00 and CAPI at 14:50:00 with the same event_id, they still dedupe (within 48h). If CAPI arrives 49 hours later (queue backed up over the weekend), they don't. Fire CAPI synchronously when possible, or with a tight retry window.
Pitfall 4 — Multiple Lead events per session. A "save my progress" event named Lead and a "submit form" event also named Lead will overlap each other unless their eventIDs are distinct. Use specific event names (Lead only for the actual submission) or generate a different eventID per phase.
Verification checklist
You can confirm dedupe is working in three places:
- Events Manager → Test Events. Send a real submission with a known eventID. You should see two events appear, both flagged "deduplicated" within ~30 seconds.
- Events Manager → Diagnostics. A "duplicate events" warning means you're not deduping. The diagnostic literally says
event_idmismatch when it sees your data. - Server-side log + browser DevTools. In DevTools, find the Pixel POST to
https://www.facebook.com/tr/. Note itseidparameter. In your server logs, find the CAPI call for the same submission. The eventID must match exactly.
If all three line up: you're deduped. If Diagnostics is silent for 24 hours after a real test and no duplicate warning appears, you're done.
How Fluenx handles this for you
In Fluenx every form submission gets a single eventID, generated client-side at submit and forwarded both to the Pixel and to your server's CAPI call. You don't write the dedupe logic — it's wired into the submission pipeline. EMQ scores stay high because the same event_id always lands on both sides of Meta's join.