Opens in a new tab
Home/Blog/Meta Conversions API deduplication: event_id explained

Meta Conversions API deduplication: event_id explained

Server-Side Tracking ExplainedPhillip StemannOctober 7, 2026

Last updated: October 19, 2026

Title card: Meta Conversions API deduplication, event_id explained
In this article
Key takeaways
  • Meta deduplicates a browser (Pixel) event and a server (Conversions API) event when the Pixel’s eventID equals the server’s event_id and the event names match.
  • Events are only deduplicated if they are received within 48 hours of the first event with that ID, and Meta generally keeps the event it received first.
  • The fallback with fbp and/or external_id only works when the browser event arrives first. Treat it as a safety net, not a plan.
  • On WordPress, the usual culprits are cached pages serving a stale ID, IDs generated separately in browser and server, mismatched event names and two plugins firing the same event.
  • Use the order ID for purchases and a UUID created once and shared for everything else. Verify in Events Manager (Test Events and the Event Deduplication tab).

You added the Conversions API (CAPI) to recover events the browser Pixel misses. Now Events Manager shows twice the purchases your shop actually took. Nothing is broken in the sense that errors appear; Meta is simply doing what you told it to, which is count two events as two events.

Deduplication is the mechanism that tells Meta “these two events are the same purchase”. It is simple in principle and easy to break in practice, especially on WordPress where caching, plugins and themes all get a say. This guide explains the rules from Meta’s own documentation, shows where they fail, and gives you a way to verify the result.

What deduplication is, and why you need it

Meta recommends running the Meta Pixel and the Conversions API together and sharing the same events through both, so that if one channel misses an event the other can supply it (Meta, Conversions API best practices). That redundancy creates a side effect: when both channels succeed, Meta receives the same purchase twice.

Deduplication is the step where Meta recognises the pair and keeps one. Without it, your reported conversions, cost per result and ROAS are inflated. With it, you get the benefit of redundancy: the Pixel covers what the server missed, the server covers what the browser missed (ad blockers, browser restrictions, closed tabs), and overlapping events are counted once. For background on why browsers lose events in the first place, see Safari ITP and WordPress cookies and why your WordPress analytics data is missing.

The matching rules, exactly

Meta’s deduplication documentation describes the recommended method: in corresponding events, the Pixel’s eventID must match the Conversions API’s event_id, and the event name must match too (Meta, Deduplicate Pixel and Server Events). In practice that gives you three checks:

  1. Same ID. Pixel eventID equals server event_id, character for character.
  2. Same event name. The Pixel event (for example Purchase) equals the server event_name.
  3. In time, and to the same Pixel. The second event must be received within 48 hours of the first (Meta’s rule). Send both to the same Pixel (dataset) ID; Meta’s pages do not spell this out, but the endpoint is per Pixel, so mixed IDs cannot pair up.

The word generally matters for the winner. Meta states that when duplicates occur it generally prefers the event that was received first. Do not build logic that depends on the server version “overriding” the browser version, because that is not how it works.

eventID versus event_id: same thing, two spellings

This trips people up more than it should. The Pixel takes a camelCase eventID in an options object, the fourth argument of fbq. The Conversions API takes a snake_case event_id inside the event. They refer to the same concept and must hold the same value. The image tag form of the Pixel uses eid. Meta’s documentation shows all three forms.

Two code panels: a Pixel fbq call with eventID order-1042 and a Conversions API JSON event with event_id order-1042, linked by a dashed line
The same value travels under two spellings. Source: Meta documentation, see Sources.

The 48-hour window and which event survives

Per Meta, events are only deduplicated if they are received within 48 hours of when Meta receives the first event with a given event_id. The clock starts at the first event, not at the order. Normally the browser event lands within seconds and the server event within seconds to minutes, so the window is rarely the problem. It becomes one when a server queue stalls, a failed delivery is retried days later, or you replay historical events.

Timeline of one purchase: Pixel event first and kept, server event with the same ID later and dropped, and a server event on day three counted twice
The first event received is kept; a late duplicate outside the 48-hour window is not recognised.

The fallback: fbp and external_id

If you cannot send an event ID, Meta describes a second method: matching on the event name plus the fbp and/or external_id parameters. The documentation is blunt about its limits: it only works for deduplicating events sent first from the browser and then through the server, and it does not deduplicate events when only one event source is used.

That makes it weaker for three reasons:

  • Order dependent. If the server event arrives first, which happens easily with a fast server-side forwarder and a slow page, the fallback does not help.
  • Parameter dependent. It needs fbp (the browser identifier stored by the Pixel) and/or your own external_id on both sides. If a cookie is missing or blocked, there is nothing to match.
  • Less explicit. An event ID says “these two are the same purchase”. fbp says “these came from the same browser”, which is a looser claim.

Meta’s best practices recommend including both: use identical event names and either event_id or a combination of external_id and fbp, and send external_id and event_id for all events. Use event_id as the primary key and the other fields as a backup.

Matched or not matched: the truth table

Table of six scenarios showing which combinations of event_id, event name, timing and fallback parameters deduplicate
Six common cases, derived from Meta’s documented rules.

Read it as a quick lookup. If the IDs differ, nothing matches by ID. If the names differ (Purchase versus purchase, or a custom OrderComplete against the standard Purchase), nothing matches even though the IDs are identical. Treat names as exact strings.

Code: Pixel and Conversions API with a shared ID

The browser side. This is the form shown in Meta’s documentation, with the ID passed in the fourth argument:

fbq('track', 'Purchase',
  { value: 49.00, currency: 'USD' },
  { eventID: 'order-1042' }
);

The server side. The endpoint format is https://graph.facebook.com/{API_VERSION}/{PIXEL_ID}/events with an access token, and each event carries its own event_id (Meta, Using the API). The required fields are event_name, event_time, action_source, user_data and event_source_url:

{
  "data": [{
    "event_name": "Purchase",
    "event_time": 1790000000,
    "event_id": "order-1042",
    "action_source": "website",
    "event_source_url": "https://example.com/checkout/thank-you/",
    "user_data": {
      "em": ["<sha256-hashed-email>"],
      "client_ip_address": "203.0.113.7",
      "client_user_agent": "Mozilla/5.0 ..."
    },
    "custom_data": { "value": 49.00, "currency": "USD" }
  }]
}

The ID value is the only thing the two snippets must share. How you produce it is the real design question, covered below. For the full request anatomy see our complete guide to the Meta Conversions API for WordPress, and for what else belongs in user_data, Event Match Quality explained.

Why deduplication fails on WordPress

WordPress adds failure modes that a plain app does not have. These are the ones that come up repeatedly.

1. Page caching serves a stale event ID

If your server renders the ID into the page HTML (a PHP-generated UUID inside the Pixel snippet, say) and a page cache stores that HTML, every visitor receives the same ID. The first purchase is deduplicated correctly; later ones send a browser event with an ID Meta has already seen, or one that matches no server event. Thank-you pages are often excluded from caching, but not always, and fragment caches and CDNs can undo that. If an ID must change per event, generate it in the browser at event time or fetch it uncached, or derive it from something that is genuinely unique per request, such as the order ID.

2. Different ID generation in browser and server

A frequent pattern: JavaScript creates Math.random() IDs for the Pixel while PHP creates its own for CAPI. Each side is individually valid and they never match. IDs must be created once, in one place, and shared. See the strategy section.

3. Event names that differ

One tool sends Purchase, another sends purchase or a custom name such as woo_purchase. The IDs match; the names do not; nothing is deduplicated. This is also common when a form plugin maps “submitted” to Lead in the browser but CompleteRegistration on the server.

4. Double-firing plugins

Two plugins that each install a Pixel (for instance a theme option plus a marketing plugin) send the same event twice from the browser, possibly with different IDs. Deduplication cannot fix that: you now have two browser events and one server event. Remove the extra sender first.

5. Events outside the window or to a different Pixel

Failed server deliveries retried the next week and mixed Pixel IDs between environments (staging Pixel in the browser, production Pixel on the server) both look like “deduplication is broken” and are not about IDs at all.

Six-step troubleshooting checklist: names, IDs, caching, one sender per source, 48 hours, same Pixel
Work through the checks in order; most cases are caught by the first four.

For caching in particular, see also client-side versus server-side tracking in WordPress.

A recommended ID strategy

  • Purchases: use the order ID. It exists on both sides, is unique, and is stable if a page reloads or a webhook retries. Prefix it if you share a Pixel across stores (shopA-1042). Reloading the thank-you page then sends the same ID again rather than a new one.
  • Everything else: a UUID created once and shared. For leads, add-to-cart, page views and form submissions, generate one UUID at the moment of the action, and hand the same value to both the Pixel call and the server event. Do not generate it twice.
  • One ID per distinct event. Two different purchases must never share an ID; one purchase must never have two.
  • Keep the name map in one place. Standard event names, spelled once, used by both paths.

A short UUID snippet for the browser, which then passes the same value to your server endpoint:

const eventId = crypto.randomUUID();
fbq('track', 'Lead', {}, { eventID: eventId });
// send the same eventId with your form request so the server reuses it

How to verify in Events Manager

Do not trust a setup because it “looks right” in the code. Check it.

  1. Use Test Events. Meta’s Test Events tool in Events Manager generates a test ID that you add to server payloads as test_event_code; remove it before sending production traffic (Meta, Using the API). Trigger a real action in the browser and confirm you see both the browser and the server event with the same ID.
  2. Open the Event Deduplication tab. In Events Manager, select your Pixel, open Event Details for an event type and go to the Event Deduplication tab. It shows the rate of events deduplicated per source and the rate of deduplication key usage, including the overlap, which is the share of events with a given key received from both sources (Meta, Verifying your setup).
  3. Read the overlap. Meta notes that low overlap indicates non-unique keys or keys sent from only one source. Low overlap on event_id usually means one side does not send it, or the values differ.
  4. Compare with real orders. Count orders in WooCommerce for a day and compare with the Purchase count in Events Manager. A count near double is the classic duplicate signature. Attribution differences will move the numbers somewhat; double is not an attribution effect.

Where Traculo fits

Traculo’s WordPress plugin forwards events from its servers to Meta Conversions API and other platforms, and keeps a delivery log with the response from each integration, so you can inspect what was sent for a given event. It does not replace the checks above: the Pixel in the browser still needs to use the same ID and event name, and you should verify that in Events Manager. Traculo sends the stored event’s numeric ID as event_id, so a browser Pixel deduplicates against it only if it uses that same value. If you are weighing options, start with server-side tracking without GTM.

Frequently asked questions

Do I need event_id if I use fbp and external_id?

Not strictly, but Meta recommends event_id and includes the fbp/external_id combination as a fallback. The fallback only works when the browser event arrives first, so event_id is the more reliable choice.

Which event does Meta keep, browser or server?

Generally the one it receives first, per Meta’s documentation. It is not “server always wins”.

What happens after 48 hours?

Events are only deduplicated if received within 48 hours of the first event with that ID. A later duplicate is not recognised as one.

Is eventID the same as event_id?

Yes. eventID is the Pixel’s option name, event_id is the Conversions API field. They need the same value.

Will deduplication fix two plugins both firing the Pixel?

Not reliably. If both browser events carry different IDs, you still have two browser events. Remove the extra sender.

Related reading

Want to see exactly what was forwarded to Meta for each event? Take a look at Traculo’s server-side event tracking.

ShareLinkedInXEmail

About the author

Track what matters, without the guesswork

Traculo gives WordPress sites analytics, funnels and server-side event forwarding in one dashboard. Start on the free plan with 10,000 events a month.

Try Traculo free

Related articles

Title card reading GCLID, GBRAID and WBRAID: what they are and when each appears, on a dark slate background with an orange glow

GCLID, GBRAID and WBRAID: what they are and when each appears

What Google's click IDs are, when gclid, gbraid and wbraid appear, the upload rules, how WordPress loses them and how to capture them reliably.

Read more
Title card reading Google Ads offline conversions for WordPress leads on a dark slate background with an orange glow

Google Ads offline conversions for WordPress leads

Capture GCLIDs on WordPress, store them with each lead and upload qualified leads to Google Ads. Formats, limits, hashing and common errors explained.

Read more
Title card reading GA4 Measurement Protocol limits: the cheat sheet, on a dark slate background with an orange glow
Data Accuracy & AttributionOctober 19, 2026

GA4 Measurement Protocol limits: the cheat sheet

Every GA4 Measurement Protocol limit on one page: 25 events, 130 kB, 72 hours, reserved names, sessions, consent, validation and how to debug missing events.

Read more