Pixel and server API: don't count every sale twice
Published on by the Oriva team.
When a sale goes out both from the browser (the pixel) and from the server (the API), each platform counts it only once if both copies carry the same event name and the same identifier. The field name changes from one platform to the next: eventID and event_id at Meta, event_id on both sides at TikTok, transaction_id and transactionId at Google Ads, event_id and id at ChatGPT Ads. Each platform also applies a deduplication window and a rule about which copy it keeps: Meta and TikTok compare over 48 hours and usually keep the first one received, Google Ads gives no time limit but discards the second one, and ChatGPT Ads keeps the first one without stating a window either. The rule is the same everywhere: give your order reference to both. Without a shared identifier, each platform counts the sale twice.
Why is a sale counted twice?
One sale can arrive by two paths: the browser pixel, when the confirmation page displays, and the server API, when the order is confirmed. Each copy is legitimate. It is counting them that creates a duplicate if the platform cannot recognize them as the same sale.
How does each platform deduplicate?
| Meta | TikTok | Google Ads | ChatGPT Ads | |
|---|---|---|---|---|
| Browser-side field | eventID | event_id | transaction_id | event_id |
| Server-side field | event_id | event_id | transactionId | id |
| Must also match | The event name | The event name | The same conversion action | The Pixel ID and the event name |
| Window | 48 hours | 48 hours | Not specified | Not specified |
| Copy kept | Usually the first one received | The first one received | The second one is discarded | The first one received |
Three details written by the platforms:
- Meta keeps “in general” the event received first, when the two do not differ significantly;
- TikTok requires sharing
event_idon both sides: “You must share Event ID (event_id) as a parameter through both Pixel and Events API to ensure deduplication takes place.” - ChatGPT Ads: for a custom event, the
custom_event_namemust also be the same on both sides.
Which identifier should I use?
Your order reference: a unique number, generated by your site or your platform for each purchase. Google asks for it in these terms: a unique identifier, “such as an order confirmation number”, generated dynamically by the back office. A fixed or hard-coded value makes far fewer conversions count than actually happened.
Give the pixel and the API exactly the same value. For a lead, use the contact or request identifier.
What breaks deduplication?
- A random identifier on the browser side. If the pixel does not have your order reference, it generates one at random, which the API cannot know;
- A different event name. Meta and TikTok require the same name on both sides, and so does ChatGPT Ads;
- One side that does not send the identifier. TikTok requires it on both sides;
- An integration that sends a copy with its own identifier, which you do not choose. That is the case of Shopify's Facebook & Instagram app set to “Maximum”: read our Shopify guide.
Same order reference on both sides
- Sale on your sitethe visitor buys
- Pixelsends order-1001
- Server APIsends order-1001
Counted onceThe pixel does not have your order reference
- Sale on your sitethe visitor buys
- Pixelgenerates a random identifier
- Server APIsends order-1001
Counted twice
What if I have no identifier on the pixel side?
Meta offers a fallback: it compares fbp or external_id, with the same event name. This fallback only works for an event sent first by the browser, then by the server: a server event is not discarded if no browser event arrived within the 48 hours before it. It does not deduplicate either when only one source sends.
It is a fallback, not a method: a shared order reference remains more reliable.
How do I check?
On a few real orders, compare the number of sales your ad platform reports with the number of orders in your store. A gap that points to a duplicate (twice as many sales on the platform side) is the signal.
Oriva's Health tab looks for it for you, over the last 7 days:
- browser purchases whose identifier looks like an automatically generated one;
- orders seen on both the browser side and the server side with different identifiers;
- a Meta, TikTok or OpenAI pixel detected next to an active Oriva destination, with a reminder to check that both use the same identifier.
What Oriva does for you
- Oriva sends the same identifier to each platform as the deduplication key:
event_idat Meta and TikTok,transactionIdat Google Ads,idat ChatGPT Ads; - Shopify: Oriva's custom pixel builds the identifier from the order number, so a page refresh does not count twice, and your Meta pixel can deduplicate against the same identifier;
- WooCommerce: Oriva's snippet uses the order number as the identifier;
- Any other site: pass your order reference to
oriva("track", "purchase", { event_id: … })and to the server call. If you leave it out on the browser side, the snippet generates one at random and the sale will be counted twice; - Oriva deduplicates on its own side first: two events with the same
event_idon one domain count only once.
Who doesn't need Oriva?
- You send each sale by one path only, the pixel alone or the API alone. There is nothing to deduplicate: TikTok writes it (“Deduplication is not required if you share different events separately between the Pixel and the Events API, without event overlap”), if you share different events without overlap.
- You can give your order reference to the pixel and the API yourself, in your tag or your code. Each platform's rule is in the table: it is a question of identifier, not of tool.
Oriva is useful when you send to several platforms and want one identifier to serve everywhere, with a log that shows what went out.
The detail of each send: Meta, TikTok, Google Ads, ChatGPT Ads.