Skip to content

Deduplication

Running a pixel and a server side connection together is the right setup. It also means the same conversion reaches the platform twice. Deduplication is how the platform recognizes the pair as one event.

Get it wrong and your reported conversions inflate, your cost per acquisition looks better than it is, and the platform optimizes against numbers that are not real.

Both copies of the event carry the same identifier. When the platform sees a second event with an identifier it has already recorded, it discards the duplicate instead of counting it.

Two things have to match, not one: the event ID and the event name. An event sent as Purchase from the browser and purchase from the server will not deduplicate.

This is the part most implementations get wrong, so it is worth being blunt about it. Datahash does not generate an event ID for you. You set it, on both copies, and you keep it identical.

Meta’s guidance is to use a value that already exists and is naturally unique, such as an order number or transaction ID. For events with no intrinsic identifier, a random value works, provided the same value is sent from browser and server.

The requirement is not that the value is clever. It is that both copies carry it.

PlatformKeyWindowNotes
Metaevent_id plus event_name48 hoursThe pixel eventID is the fourth argument of fbq track and must equal the Conversions API event_id.
TikTokevent_id48 hoursIdentical event plus event ID within the window is deduplicated.
SnapchatPixel client_dedup_id equal to CAPI event_id48 hoursValues must be byte identical for the same Pixel ID and event name.

Where a server event and a browser event arrive within about 5 minutes of each other, Meta favors the browser copy.

Meta also supports a fallback using fbp or external_id, but it only works for events sent first from the browser and then through the server. It is not a substitute for a shared event ID.

Two Snapchat details cause real problems.

  • Auto-generated pixel IDs prefixed @- exist only in the browser. They can never match a Conversions API event, so an implementation relying on them will never deduplicate.
  • For PURCHASE, Snapchat also accepts a pairing of the pixel transaction_id with order_id in custom_data, which gives a 30 day fallback window alongside the 48 hour event ID window.

The same rule applies across app sources. Send a unique event_id and keep it identical across every source reporting the same action, including any mobile measurement partner. Where an MMP and Signals both report a purchase, matching event names and matching event IDs are what stop it counting twice. See Set up a deduplication ID across Firebase, your MMP and Signals for where the value goes in each SDK.

Two source types deduplicate on something other than an event ID you set.

SourceKeyNotes
An offline conversions filetransaction_idThe same purchase carrying the same transaction ID resolves to one conversion however many times the file is read. Map a reference that stays stable across exports: a system that generates a new one each time makes every re-send look like a new conversion.
A CRM lead status changeAn event ID Signals derivesBuilt from the Meta lead ID and the last modified date. A lead re-synced without changing produces the same ID; a real status change produces a new one.

Resending a record more than 48 hours after the first delivery puts it outside Meta’s match window and counts it again, which is worth checking before you run a backfill.

In Meta, open Events Manager, then Event Details, then the Event Deduplication tab.

Meta’s own reading of the result: low Overlap means the implementation is either sending non-unique dedupe keys, or sending events with a dedupe key from only one source. In practice a low overlap almost always means the server copy has an event ID and the browser copy does not, or the two are generated independently.