Blog
A single shared event_id between browser and server prevents double-counting in Meta, TikTok, and LinkedIn.
When you fire the same conversion both client-side (Pixel) and server-side (CAPI), the destination needs a way to recognise that they are the same event. That mechanism is event_id. Without it, your reporting double-counts. With it, the destination keeps whichever arrives first and discards the other.
The event_id has to be the same across both sides. The cleanest pattern is to generate it on the page in JavaScript when the conversion fires, push it into the data layer, and let both the Pixel and the server-side tag read from the same data layer entry.
const eventId = crypto.randomUUID();
dataLayer.push({
event: 'purchase',
event_id: eventId,
ecommerce: { ... }
});
Open Events Manager, find the event in question, and check the deduplication summary. You should see a "Browser and server" column showing the percentage of events received from both sources. The remaining events are those that came in from only one side, which is normal: ad blockers prevent some Pixel hits, network failures lose some CAPI calls.
If the column shows zero, the event_id is not being passed correctly. Most often the issue is that the Pixel side is using eventID (camelCase) while the CAPI side is using event_id (snake_case). Both work; they just need to match.
TikTok uses the same event_id field name and same logic. The match window is 48 hours, and the matching is exact. LinkedIn calls the same field conversionId and matches on (conversionId + conversionRuleId), which means you need to also send the rule ID to deduplicate properly.
If your client-side Pixel and your server-side CAPI run on different timestamps (browser time vs server time, sometimes off by hours due to client clock drift), some destinations will fail to dedupe even with a shared event_id. The fix is to send the canonical timestamp from the server, not the browser. Your sGTM container already has this; just expose it on the outgoing event.