Event deduplication
Event deduplication is how ad platforms count one conversion once when the same event arrives from both the browser pixel and a server-side API.
What is event deduplication?
Event deduplication is the process of recognizing that two incoming events describe the same real-world action and keeping only one. It matters most when you send a conversion from both the browser pixel and a server-side API, which is the setup Meta and TikTok recommend.
Without it, every purchase that both sources catch is counted twice, which inflates reported conversions and makes return on ad spend look better than it is.
How platforms match duplicates
The usual mechanism is a shared event id. When the pixel fires, it sends an event_id; the server event for the same action sends the identical value with the same event name. The platform sees the pair within its dedup window and drops one.
Platforms differ in the details. Meta and TikTok dedupe on event id plus event name. Google Ads uploads can carry an order or transaction id so a retried upload doesn't double count. GA4's Measurement Protocol doesn't dedupe against gtag in the same way, so a common approach is to send a given conversion from one source only.
Common ways deduplication breaks
The browser and server generate their own ids instead of sharing one. The event names differ, such as Purchase in the pixel and purchase on the server. The server event is sent long after the browser event, outside the window the platform checks. Or retries from a webhook source create a second server event with a new id.
These failures are silent. Nothing errors; the numbers are just wrong, which is why it pays to compare your own counts against what each platform reports.
How TracerKit handles it
TracerKit gives the browser pixel fire and the server-side event the same event id, so Meta and TikTok dedupe the pair. Webhook sources use an idempotency key (such as the Stripe checkout session id) so redelivered webhooks don't create new conversions, and Google Ads uploads carry the order id as the transaction id.
See how TracerKit handles this: Reconciliation
Take a look →