The good news: deduplication failures look dramatic in reporting (doubled conversion counts, inflated ROAS, broken cost-per-result math) but the actual fixes are usually small — a misplaced hash, a casing inconsistency, a missing parameter on the server payload. The five most common causes account for roughly 90% of the failure modes we see in the field. Work through them in order.
How does Meta CAPI deduplication actually work?
Meta CAPI deduplication is a server-side process inside Meta’s ingestion layer. When Meta receives two events with the same event_id and event_name from the same Pixel ID within roughly 48 hours, it treats them as the same conversion. One event is kept for optimization, reporting, and audience-building. The other is discarded.
The selection isn’t random. Meta keeps the event with the higher match quality — the one with more customer-data parameters, correctly hashed, with valid _fbp and _fbc values. In almost every dual setup, the CAPI event wins because it carries hashed PII (email, phone, name) drawn from the server side, while the Pixel event carries only what the browser captured automatically. The Pixel event is what gets discarded.
The asymmetry has a practical implication: a well-configured CAPI integration makes the Pixel mostly redundant from a matching-data perspective. The Pixel’s remaining value is setting the _fbp cookie on first visit and view-through attribution — not most of the conversion signal.
What are the three rules for successful deduplication?
Meta’s published deduplication requirements come down to three rules. All three must hold for the events to merge.
| Rule | Requirement | Common failure mode |
|---|---|---|
1. event_id must match exactly |
Same string on Pixel and CAPI, character-for-character, case-sensitive | Pixel uses one ID format (UUID), CAPI uses another (database row ID) |
2. event_name must match exactly |
Same string, same case | Purchase on Pixel, purchase on CAPI — silent mismatch |
| 3. Events must arrive within ~48 hours of each other | First and second event seen by Meta no more than 48h apart | Server fires CAPI immediately on conversion; Pixel fires 3 days later from a cached page |
The event_id rule is the single largest failure cluster. Meta has no published “fuzzy match” logic — two events with event_id values of ord-12345 and Ord-12345 are treated as different conversions. The same applies to leading or trailing whitespace, hidden Unicode characters, and any quoting differences if the IDs were JSON-encoded by one side and not the other.
The order of arrival doesn’t matter inside the 48-hour window. CAPI can fire before the Pixel or after; Meta deduplicates either direction. What matters is that both arrive, both match, and both make it within the time window.
Why are my events duplicating? (The five most common causes, ranked)
The diagnostic tree, in descending order of frequency. Walk through each one before assuming the next.
Cause 1: The event_id doesn’t match (≈60% of cases)
By far the most common. The Pixel generates one ID; the server generates another. Meta sees two different IDs and counts two events.
Diagnostic: Open Meta Events Manager → Test Events. Trigger a single conversion. Compare the event_id on the Browser event and the Server event. Are they identical character-for-character?
Fix: Generate the event_id in one place — either the browser (which then sends it to your backend so CAPI uses the same value) or the server (which then sends it to the browser via the response, set on the Pixel call). The pattern most setups use: generate a UUID server-side at the moment of conversion, include it in the response, fire both the Pixel and CAPI with that same UUID as event_id.
// Pixel side
fbq('track', 'Purchase', {value: 49.99, currency: 'USD'}, {eventID: 'order_abc123'});
// CAPI side - SAME event_id
{
"event_name": "Purchase",
"event_id": "order_abc123",
"event_time": 1717891234,
"event_source_url": "https://example.com/checkout/success",
"action_source": "website",
"user_data": { "em": ["<sha256>"], "fbp": "fb.1.1717891000.123456789" },
"custom_data": { "currency": "USD", "value": 49.99 }
}
Cause 2: The event_name doesn’t match (≈15% of cases)
Case sensitivity is the silent killer. Meta’s standard events use PascalCase — Purchase, Lead, CompleteRegistration, AddToCart, InitiateCheckout. Sending purchase from the server or PURCHASE from a tag manager produces a mismatch.
Diagnostic: Compare the event_name field on the Browser and Server events in Test Events. They must match exactly, including case.
Fix: Standardize on Meta’s published PascalCase names for standard events. For custom events, pick a casing convention and enforce it across both Pixel and CAPI through a shared constant.
Cause 3: Missing _fbp or _fbc on the CAPI event (≈10% of cases)
The deduplication itself can succeed even without _fbp/_fbc, but the result is a Server event with low Event Match Quality (EMQ) — which Meta is less confident attributing to a real user. In some accounts the missing cookies cause the CAPI event to be counted as a separate, unmatched conversion instead of a duplicate of the Pixel event.
Diagnostic: Open the Server event payload in Test Events. Confirm user_data.fbp is present and starts with fb.1.. Confirm user_data.fbc is present when the user arrived from a Meta ad (URL contained fbclid).
Fix: Read the _fbp cookie from the request on the server, and pass it as the fbp parameter in the CAPI payload. When the user has fbclid in the URL, wrap it in Meta’s _fbc format (fb.1.<creation_time_ms>.<fbclid>) and pass as fbc. Both values must be sent unhashed — Meta explicitly does not want hashed fbp or fbc.
Cause 4: Time-stamp drift between Pixel and CAPI (≈8% of cases)
If event_time on the two events differs by more than ~5 minutes, Meta may not associate them even if event_id matches. The cause is usually a server clock that’s drifted, or a server-side queue that delays CAPI dispatch by hours.
Diagnostic: Compare event_time Unix timestamps on the Browser and Server events for a single conversion. Convert to UTC; the gap should be under 60 seconds for a real-time CAPI dispatch.
Fix: Run NTP on the server to keep the clock accurate. Send CAPI events as close to real-time as possible — queueing for batch processing is fine for offline events but adds dedup risk for online ones. If you must delay, include event_time as the conversion’s actual time, not the CAPI dispatch time.
Cause 5: Multiple Pixels firing (≈7% of cases)
A site with two Meta Pixels installed (often inherited from a tag manager migration) will fire the conversion event twice from the browser — once per Pixel. CAPI fires once. The first Pixel matches CAPI; the second Pixel has no CAPI counterpart and shows up as a separate, unmatched conversion.
Diagnostic: Use Meta’s Pixel Helper Chrome extension on the conversion page. Look for multiple Pixel IDs firing the same event. If you see more than one, that’s the cause.
Fix: Remove the duplicate Pixel or consolidate the two Pixel IDs into a single one in Events Manager. If both Pixels are needed (e.g., agency tracking + brand tracking), fire CAPI separately to both Pixel IDs so each has its server-side match.
How do I verify deduplication is working in Test Events?
Meta’s Test Events tool inside Events Manager is the right place to debug deduplication in real time. The production EMQ score updates only every ~48 hours, so production data is too slow to iterate on; Test Events shows events within seconds.
The verification steps:
- Open Events Manager → Data Sources → your Pixel → Test Events tab.
- Enter your test browser’s URL and Meta will append a
?test_event_code=parameter. Visit the conversion page through that URL. - Trigger a real conversion in the test browser — submit the form, complete the test purchase, fire whatever event you’re debugging.
- Watch the Test Events feed in Events Manager. Within 5–15 seconds you should see two entries appear: one with Source: Browser (the Pixel), one with Source: Server (CAPI).
- Confirm both rows show “Deduplicated” in the right-hand status column. If they both show “Deduplicated,” the merge worked. If one shows “Deduplicated” and the other shows “Received,” the events arrived but didn’t merge — usually an
event_idorevent_namemismatch. The Test Events tool will also show the full event payload on click. Compareevent_id,event_name, andevent_timebetween the two side-by-side; any difference is the failure cause.
Once Test Events confirms the merge, production behavior follows the same logic with the production payload — the only difference is the 48-hour EMQ refresh cadence.
What if my server fires CAPI before the browser fires the Pixel?
Order doesn’t matter inside the 48-hour window. Meta deduplicates regardless of which event arrives first.
The CAPI-first pattern is actually preferred for some setups — a server-side conversion (a backend purchase webhook, a CRM lead-creation event) fires CAPI immediately, while the browser-side Pixel fires only when the user’s confirmation page loads. If the user closes the browser tab before the confirmation page loads, the Pixel never fires at all — but CAPI already did, and the conversion is still counted.
The edge cases worth knowing:
- CAPI-only setups. If you’ve removed the Pixel entirely, there’s nothing to deduplicate against. Every CAPI event is a single conversion. This is the cleanest architecture when it works — see Meta Pixel vs Conversions API for when it’s the right choice. (TODO: live link when that piece publishes.)
- Pixel fires twice (cached form submission). Some browser back-button behavior re-fires the Pixel from cache. The duplicate Pixel hits the same
event_idand gets discarded on the second arrival — no double-counting, but the server-side log may show two browser-event lines. - CAPI retries. If your CAPI dispatch retries on transient HTTPS errors, send the retried event with the same
event_id. Meta deduplicates the duplicate CAPI calls against the original CAPI event automatically. The 48-hour window is generous enough to cover almost every real workflow. Setups that exceed it (offline conversions that close 60+ days later) need a different attribution path — see Meta’s offline-conversion documentation.
How does PartialLeads handle deduplication automatically?
The five failure modes above account for the bulk of CAPI deduplication issues in the field. Each one is a configuration detail that has to be implemented correctly and stay correct across deploys, code refactors, and tag-manager migrations. PartialLeads’ managed integration removes all five from the customer’s responsibility:
- Single source of
event_id. The PartialLeads tag generates a UUID server-side at the moment of conversion and writes it to both the Pixel call (aseventID) and the CAPI payload (asevent_id) in a single round-trip. There’s no parallel ID generation on two systems that can drift apart. - Standardized
event_nameconstants. Standard Meta events (Purchase,Lead,CompleteRegistration,AddToCart,InitiateCheckout) are mapped to the correct PascalCase string in both the Pixel call and the CAPI payload. Case mismatches don’t happen because the customer doesn’t type the event names — the tag does. - Synthetic
_fbpand_fbchandling on both sides. When a visitor lands without a_fbpcookie, the tag generates one in Meta’s format (fb.1.<creation_time_ms>.<random_number>) and writes it as a first-party cookie. The same value goes on the Pixel call and into the CAPI payload’suser_data.fbpparameter. For_fbc, the tag capturesfbclidfrom the URL, wraps it infb.1.<timestamp>.<fbclid>format, and writes the cookie. Both Pixel and CAPI see the same values. - Real-time CAPI dispatch. CAPI events are sent within seconds of the browser-side Pixel, so the
event_timevalues stay aligned. No queueing delays, no clock-drift risk on a managed backend. - Single Pixel ID per integration. The tag installs once per site and fires once per conversion. The “multiple Pixels firing” failure mode is structurally impossible. The result for the customer is a deduplication setup that just works. Test Events shows both Browser and Server entries marked “Deduplicated” within 15 seconds of the first conversion, EMQ climbs above 8 inside the first 48 hours, and the dual-source conversion counts stay accurate without the customer touching the underlying configuration.
For accounts that previously had deduplication broken (the most common symptoms: ROAS inflated by 30–80%, EMQ stuck below 5, cost-per-result figures that don’t match backend revenue), switching to a managed setup typically restores accurate reporting inside one EMQ refresh cycle.
Sources
- Meta for Developers — Deduplicate Pixel and Server events: https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events
- Meta for Developers — Conversions API documentation: https://developers.facebook.com/docs/marketing-api/conversions-api
- Meta for Developers — Test Events tool: https://developers.facebook.com/docs/marketing-api/conversions-api/payload-helper
- Meta for Developers — fbp and fbc parameters: https://developers.facebook.com/documentation/ads-commerce/conversions-api/parameters/fbp-and-fbc
- Meta for Developers — Conversions API best practices: https://developers.facebook.com/docs/marketing-api/conversions-api/best-practices
- Meta Business Help — About Event Match Quality: https://www.facebook.com/business/help/765081237991954