Blog · Conversions API
Conversions API deduplication with event_id: a practical guide
When you run the Meta Pixel and the Conversions API side by side, every conversion can reach Meta twice: once from the visitor's browser and once from your server. Deduplication is how Meta recognises the two copies as one event. The method Meta recommends is simple: send the same event name and the same event ID from both sides. In the browser the ID is called eventID; on the server it is event_id. If the pair matches and both reach the same Pixel within 48 hours, Meta keeps one and discards the other.
Most broken setups fail on the ID, not the name. The browser and server generate their own random IDs, or one side doesn't send an ID at all, so nothing matches and every lead counts double. This guide covers how the matching works, where the ID should come from, how to wire it through Google Tag Manager and the API, and how to check the result in Events Manager.
Checked against Meta's developer documentation on 20 October 2026. Sources are linked in each section and listed at the end.
How Meta deduplicates
Meta's guide to deduplicating Pixel and server events describes two methods.
1. Event name + event ID (recommended). Two rules: the Pixel's eventID must match the Conversions API's event_id, and the Pixel's event name must match the API's event_name. When the same pair is sent to the same Pixel ID within 48 hours, Meta discards the later copies. The 48 hours are counted from when Meta receives the first event with that ID. The order doesn't matter for this method: browser first or server first both work.
2. Event name + fbp and/or external_id. If you can't pass an event ID, Meta can match on the browser ID (fbp) or your own external_id, used consistently on both sides. This method has real limits:
- it only works when the browser event arrives first and the server event after it,
- a server event is not discarded if no matching browser event arrived in the previous 48 hours, even if an identical browser event shows up later,
- it never deduplicates two browser events or two server events with each other.
Server events often arrive first, for example when the Pixel loads late or is blocked, so method 2 leaks duplicates. Use the event ID and treat fbp and external_id as matching signals, not as your deduplication key.
Which copy is kept? Meta says it "generally" prefers the event received first, as long as the two copies don't differ meaningfully in content. The server event parameters reference adds one detail: when a server event and a browser event arrive at about the same time (within 5 minutes of each other), Meta favours the browser event. In practice it doesn't matter which copy wins if both carry the same data. Make sure they do.
Where the event ID should come from
The ID must be created once and shared by both sides. Meta asks for a unique string and suggests an order number or transaction ID. For events that have neither, a random number works, as long as the same number is sent from the browser and the server. Meta gives no format or length rules beyond "string".
Two patterns work well:
- The server creates the ID. The form posts to your backend, the backend saves the lead and returns its record ID, and the browser fires the Pixel event with that ID. For leads this is usually the cleanest pattern: the ID is the lead's own ID in your database, so you can trace any event back to a record.
- The browser creates the ID. The page generates a random ID (a UUID, for example), uses it in the Pixel call and sends it along with the form data, and the server reuses it in the API call.
Patterns that break deduplication:
- separate random IDs on each side,
- one fixed ID for every event (
"lead", the page URL, the visitor's cookie ID). Meta then discards real, separate leads that arrive within 48 hours as "duplicates", - an ID created on page load and reused for several different conversions on that page.
Browser side: the Pixel call
The event ID goes in the fourth argument of fbq('track', …), not in the event parameters. From Meta's examples:
fbq('track', 'Lead', {}, {eventID: 'EVENT_ID'});
fbq('track', 'Purchase', {value: 12, currency: 'USD'}, {eventID: 'EVENT_ID'});
If you call a specific Pixel with trackSingle, the ID goes in the same position after the parameters. The image pixel takes it as eid: https://www.facebook.com/tr?id=PIXEL_ID&ev=Lead&eid=EVENT_ID.
In Google Tag Manager
When the site pushes the conversion to the data layer, put the ID in the push:
// after the form endpoint has saved the lead and returned its id
dataLayer.push({ event: 'generate_lead', event_id: leadId });
Then in GTM:
- Create a Data Layer Variable for
event_id(for exampleDLV - event_id). - Create a Custom Event trigger for
generate_lead. - In the Pixel event tag, whether it's a Custom HTML tag or a template, fire
Leadon that trigger with the event ID set to{{DLV - event_id}}. In Custom HTML that isfbq('track', 'Lead', {}, {eventID: '{{DLV - event_id}}'});. - Under Consent Settings, require the advertising consent types your banner uses. Meta's Pixel has no built-in Google consent checks, so without this it fires whatever the visitor chose. The Consent Mode v2 guide covers the setup.
Fire the tag on the confirmed conversion, not on a button click: a click that fails validation, or a double click, would send a Lead that never happened.
Server side: the Conversions API call
The server sends the same conversion to https://graph.facebook.com/v26.0/{PIXEL_ID}/events (v26.0 is the version in Meta's current examples, see Using the API). A minimal website Lead:
{
"data": [{
"event_name": "Lead",
"event_time": 1792454400,
"event_id": "8f1c2e7a-4b1d-4c6a-9e7f-2d3b5a6c7e8f",
"action_source": "website",
"event_source_url": "https://example.com/contact",
"user_data": {
"em": ["<SHA-256 hash of the normalised email>"],
"client_user_agent": "Mozilla/5.0 …",
"fbp": "fb.1.1596403881668.1116446470",
"fbc": "fb.1.1554763741205.<fbclid>"
}
}]
}
Rules from the parameters reference that affect deduplication and acceptance:
event_namemust be the same string the Pixel sends:Leadon both sides, notLeadin the browser andSubmitFormon the server.event_timeis a Unix timestamp in seconds, in GMT. It can be up to 7 days old. If any event in a request is older, Meta rejects the entire request.event_source_urlis required for website events.fbpandfbccome from the_fbpand_fbccookies when the visitor has them. If you buildfbcon the server from afbclidURL parameter, the format isfb.1.<creationTime>.<fbclid>.creationTimeis in milliseconds, set to when you first received thatfbclid, and thefbclidkeeps its exact case (fbp and fbc parameters).
Deduplication also protects retries: if the same event_id and event_name arrive more than once, Meta keeps only the first copy, so resending a failed batch doesn't double count what was already stored.
Send both only when both are allowed
The server event must follow the same consent decision as the browser event. If a visitor refuses advertising cookies and your server still sends the Lead, the banner has been bypassed, and the event no longer has a browser copy to deduplicate against. Pass the visitor's advertising choice with the form data and send the server event only when it allows it. On restricted datasets, such as health and wellness, also keep to standard event names and only the fields your dataset accepts, the same rules as in the guide to sending lead quality back to Meta.
How to check it in Events Manager
Test Events. In Events Manager open your dataset → Test Events, copy the test code and add it to the server request as test_event_code, next to data. Submit one test conversion with the browser open on the same screen and you should see the browser and server events arrive. One warning from Meta's own docs: test events "are not dropped". They flow into Events Manager and are used for targeting and ads measurement. Keep testing to a handful of events, and remove the test code from production when you're done.
Event deduplication tab. After real traffic has flowed, open Overview → the event → Event details → Event Deduplication (Verifying your setup). Two numbers matter:
- Rate of Events Deduplicated. Higher is better. Events Manager shows a warning when it is too low.
- Rate of Deduplication Key Usage, with an Overlap figure. Low overlap means the keys aren't unique, or only one source is sending them.
Meta says server events can usually be verified within about 20 minutes of sending. For a slower check, compare a week of leads in your CRM with Meta's count of Lead. After deduplication they should be close, not double.
Common mistakes
- No
event_idon one side. Usually the server, becauseevent_idis marked optional in the API reference. Meta still recommends it for deduplication. - Two IDs for one lead. The browser and the server each generate their own.
- A static or reused ID. Real leads get discarded as duplicates within the 48-hour window.
- Different event names. A custom name on one side and a standard event on the other.
- The ID in the wrong
fbqargument. Placed inside the parameters object (the third argument) instead of the fourth. - Milliseconds in
event_time. Seconds are required;fbccreation time is the one in milliseconds. - Relying on
fbpmatching. It only works when the browser event arrives first. - The test code left in production. Every live event keeps going to Test Events.
FAQ
Do I need deduplication if I only use the Conversions API? Not for browser vs server copies, because there is only one source. The event ID is still worth sending: it makes retries safe and lets Events Manager show key usage.
Can I use the same event ID for PageView and Lead?
Deduplication uses the event name and the ID together, so different events don't collide. But one ID per conversion is easier to trace and harder to get wrong.
Does the Conversions API Gateway or a partner integration handle this for me? Don't assume it does. Check that the integration sends the same event ID from both sides, then confirm it in the Event Deduplication tab; the numbers show whether the keys match.
How long can the server wait before sending?
Deduplication works within 48 hours of the first copy, and event_time can be up to 7 days old. Meta recommends sending server events as close to real time as possible, ideally within an hour of the event.
To have the Pixel, the Conversions API and deduplication set up and checked in your account, see the Meta Pixel and Conversions API service.
Sources
- Meta for Developers: Deduplicate Pixel and server events
- Meta for Developers: Server event parameters
- Meta for Developers: fbp and fbc parameters
- Meta for Developers: Using the Conversions API
- Meta for Developers: Verifying your setup
- Meta for Developers: Meta Pixel reference
Free first look
Stuck on this in your own account?
Send a short note with what you see. A reply arrives within 1 business day. No payment is requested before a written proposal.