Facebook CAPI deduplication prevents one real conversion from being counted twice when the browser Pixel and the server-side Conversions API both report it. The core contract is simple: the browser and server copies of the same event need the same event name and the same event_id.
The implementation becomes difficult when teams confuse four separate identities:
fbclid/fbc: Meta click context;fbp: browser context;- internal
click_id: your tracker’s visit key; event_id: the identity of one conversion event sent through two channels.
They should be connected in one click record, but they should not be collapsed into one generic ID.
What deduplication does—and does not do
| Problem | Correct mechanism |
|---|---|
| Pixel and CAPI send the same Purchase | Matching event name + matching event_id |
| A network retries one postback | Stable network transaction ID / tracker idempotency |
| Registration and deposit happen on one click | Different event types and usually different event IDs |
| Meta must match the event to an ad click | fbc/fbclid, fbp and other permitted match keys |
| Tracker must attach revenue to a visit | Internal click ID returned in the postback |
Meta’s official deduplication documentation should remain the source of truth for the current API contract. Operationally, do not use match keys as a substitute for event identity.
A correct browser and server pair
Browser Pixel example:
<script>
fbq("track", "Purchase", {
value: 42.50,
currency: "USD"
}, {
eventID: "purchase_conv_98211"
});
</script>
Server CAPI event for the same purchase:
{
"event_name": "Purchase",
"event_time": 1786957000,
"event_id": "purchase_conv_98211",
"action_source": "website",
"custom_data": {
"value": 42.50,
"currency": "USD"
}
}
The browser SDK spells the option eventID; the Conversions API payload uses event_id. The values must match exactly for the same business event.
How to generate event IDs
An event ID needs two properties:
- stable for retries or multiple delivery copies of one event;
- unique across different business events.
A network conversion ID is often the best seed because it already identifies the transaction:
Purchase:network_conv_98211
If no transaction ID exists, generate the ID once at the event source, persist it with the conversion record and reuse it for both browser and server delivery. Do not let the browser and server independently generate random IDs after the event occurs.
Avoid these patterns:
- one
event_idper user for their entire lifetime; - one
event_idequal to the campaign ID; - timestamp-only IDs created independently on browser and server;
- using the internal click ID for registration, deposit and every later purchase without an event-specific suffix.
Event name must match too
Matching IDs do not repair a semantic mismatch such as:
browser: Purchase / purchase_conv_98211
server: Lead / purchase_conv_98211
Define one conversion registry before implementation. Decide which raw postback status becomes Lead, CompleteRegistration, Purchase or a custom event, and use the same mapping on every delivery path.
If browser and server are intentionally reporting different funnel moments, they should not be deduplicated. Give them different event names and IDs.
Where fbclid, fbc and fbp fit
fbclid is appended to a landing URL after a Meta click when available. Integrations can preserve it and construct the expected fbc click context for server-side delivery. fbp carries browser context.
These values help Meta match the server event to an ad interaction. They do not tell Meta whether the browser and server payloads are duplicates. That is the job of the shared event identity.
Keep the model explicit:
click_id → our exact visit
fbc/fbp → Meta matching context
event_id → one conversion delivered through one or more channels
tx_id → one partner/business transaction
The Click ID vs Sub ID guide maps these identifiers in more detail.
The postback-to-CAPI boundary
In affiliate traffic, the decisive conversion often happens on the advertiser or network side. The browser may never see the deposit. A postback returns the event to the tracker:
https://tracker.example/postback?click_id={aff_sub}&status=deposit&payout={payout}&transaction_id={conversion_id}
Only after the tracker validates the click, status and transaction should it construct the server event for Meta. This order prevents an unknown or duplicate callback from becoming a false advertising signal.
Read how affiliate conversions return to Facebook for the complete delayed-conversion path and Pixel vs CAPI vs postback for the ownership boundary.
Pass/fail verification table
| Test | Pass condition |
|---|---|
| Browser payload | Correct event name and a non-empty event ID are visible |
| Server payload | Same business event uses the same name and exact ID |
| Event data | Value and currency agree across duplicate copies |
| Click context | fbc/fbp are present when legitimately captured |
| Tracker event | Server event originates from a known conversion and click |
| Partner retry | Same transaction does not create another tracker conversion |
| Meta diagnostics | Event is accepted and not reported as an unresolved duplicate |
| Final count | One business conversion remains one counted Meta event |
Do not sign off from Ads Manager totals alone. Use a controlled event whose browser payload, server request, platform response and tracker conversion can all be inspected.
Common failure modes
Same event, different IDs
Pixel and CAPI both count because each channel generated its own identifier. Generate once and transport the value.
Same ID, different event names
One copy is Purchase, the other CompleteRegistration. Fix the event registry, not the identifier.
One click ID reused as every event ID
Real repeat purchases can collapse or diagnostics become ambiguous. Add transaction or event scope.
CAPI fires before the postback is validated
An unknown click, unmapped status or partner retry reaches Meta as a real conversion. Validate and deduplicate at the tracker boundary first.
Match quality is confused with deduplication
Good fbc, fbp, IP, user agent or permitted hashed customer data can improve matching, but duplicate copies still need coordinated event identity.
Durable implementation rule
Model the business conversion first, then deliver it:
validated conversion record
├── browser Pixel copy (when applicable)
└── server CAPI copy
Both copies reference the same event record and therefore share one identity. This design is easier to test than trying to infer duplicates after two independent pipelines have already fired.