Webclat / GTM Practice

Why does my Facebook Pixel purchase event fire twice, and how do I deduplicate it?

Quick answer

Double-firing usually comes from having both a client-side Pixel purchase event and a server-side Conversions API purchase event sending the same conversion without a shared event_id, or from a tag configured to fire on both a page-level trigger and a duplicate custom-event trigger. Give both the Pixel call and the CAPI call the exact same event_id for the same real-world purchase - Meta deduplicates using that field specifically, not by inferring duplicates from timing or value.

Why this happens

Running both browser-side Pixel and server-side Conversions API for the same event is Meta's own recommended pattern for coverage and accuracy - but the two are separate sends with no automatic knowledge of each other, so unless you explicitly connect them, Meta counts both as independent purchases. The mechanism connecting them is a shared event_id: a string you generate once per real conversion and pass to both the Pixel call and the matching server-side send.

Fix it

  1. Confirm whether you are running both client-side Pixel and server-side CAPI for the same event - if so, this is the most likely cause, and the fix is a shared event_id, not a trigger change.
  2. Generate one identifier per real conversion (your own order ID is the natural choice, since it is already unique and available on both the client confirmation page and your backend).
  3. On the client-side Pixel call, pass it as the eventID option: fbq('track', 'Purchase', {value: 129.00, currency: 'USD'}, {eventID: 'order_12345'});
  4. On the server-side CAPI payload sent from your backend, include the identical value in the event_id field of that event object - Meta matches events with the same event_id within the same window and deduplicates them into one.
  5. Separately, rule out the simpler client-side-only cause: check GTM Preview for the Pixel tag firing twice from a single trigger evaluation - a tag with both a page-level trigger and a redundant custom-event trigger both matching the same page load will double-fire with no CAPI involved at all.

How to verify it worked

Use Meta's Test Events tool (Events Manager > Test Events) with Pixel and CAPI both sending to the same test event code - a correctly deduplicated pair shows as one event with a "Browser + Server" source badge, not two separate rows. If you see two separate rows with the same order value and no shared event_id visible in either payload's details, the field is not actually being passed through on one side.

Still stuck after working through this?

Send us what you are seeing in Preview and the Network tab. We trace GTM containers for a living and can usually tell you what is actually happening in one look.

Ask a GTM Engineer