Meta CAPI Event Deduplication: How event_id Stops Double Counting
Meta's Pixel + Conversions API dedup rules: event_id and event_name matching, the 48-hour window, fbp fallbacks, Events Manager debugging, plus TikTok and GA4.
In short
Meta CAPI event deduplication is how Meta collapses a browser Pixel event and a server-side Conversions API event into one counted conversion. Events pair when the Pixel eventID equals the CAPI event_id, the event_name matches, and the second arrives within 48 hours of the first; Meta generally keeps the first received. Miss any of these and each purchase counts twice.
This guide pairs Meta's official rules with a practical debugging walkthrough. It covers the exact matching logic, the fallback keys, how to generate one ID and pass it through both paths, how to read the Deduplication tab in Events Manager, the failure modes that cause double counting in the wild, and how TikTok and GA4 handle the same problem.
Why do redundant Pixel and Conversions API setups need deduplication?
Because Meta recommends sending the same events from both the browser and the server, and without a shared key it has no way to know they describe one action. The Pixel runs in the visitor's browser and is blocked by ad blockers, tracking prevention, and page abandonment. The Conversions API runs from your server and is not. Sending both gives you coverage when the browser fails and richer matching when it succeeds. Meta's April 2026 announcement stated that advertisers using the Conversions API for web events saw an average 17.8% lower cost per result than those without it.
The cost of redundancy is that a single purchase now produces two events. If Meta cannot pair them, your Purchase count doubles, your cost per purchase halves on paper, and the delivery system optimizes toward inflated signals. Deduplication is the mechanism that makes redundancy safe. For the broader case for running server-side at all, see our server-side conversion tracking guide.
How does Meta deduplicate Pixel and Conversions API events?
Meta uses two matching methods. The primary method compares event_id and event_name. The secondary method compares fbp or external_id together with event_name. Both share the same window and the same tie-break rule.
The exact matching rule: event_id plus event_name
Two events are treated as duplicates when the Pixel's eventID parameter equals the Conversions API's event_id field and the Pixel's event name equals the Conversions API's event_name. Both conditions are required. A Purchase event and a Lead event with the same event_id are not duplicates. Two Purchase events with different IDs are not duplicates. Treat the comparison as an exact string match: assume "purchase" and "Purchase" will not pair, and neither will IDs that differ by a trailing space or a prefix added by one tag but not the other.
The 48-hour window and first-received preference
Meta's developer documentation states that 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 receipt, not at the event_time you set in the payload. Within that window, Meta's wording is conditional: when the server and browser events do not differ meaningfully in their content, it generally prefers the event that was received first. In practice the browser event usually lands first. Meta does not document merging the two payloads, so do not rely on the extra customer data in a later server event being used. If the second event arrives after 48 hours, both are kept and both are counted.
Fallback keys: fbp and external_id
If event_id is missing, Meta can still deduplicate using event_name plus a consistent fbp value or external_id across the browser and server events. This fallback has two hard limitations spelled out in Meta's documentation. First, it only works when the browser event arrives first and the server event follows. A server event is never discarded if no browser event was received in the previous 48 hours. Second, it does not deduplicate events within a single source. Meta's guidance is to send deduplication keys on all events.
What is event_id in the Facebook Conversions API?
event_id is a string you choose that uniquely identifies one occurrence of one business event. It is not a Meta-generated value and it has no required format. Meta only cares that the same string appears on both the browser and server copies of the same event, and that different occurrences get different strings. Order numbers, lead-form submission IDs, and UUIDs generated at the moment of the action all work. What does not work is generating a fresh random value independently in each tag, because the two values will never match.
How do you generate one ID and pass it through both paths?
Generate the ID once, at the moment the business event happens, in whichever system knows about it first, then hand that same value to both the Pixel call and the server request. The procedure is the same whether you use a tag manager, a plugin, or custom code.
- 1Pick the source of truth for the ID. For purchases, use the order ID your commerce system already assigns, so the browser and server both have it without coordination. For events that have no natural ID, such as Lead or AddToCart, generate a UUID in the browser at the moment of the action and write it to the data layer or a hidden form field.
- 2Send the ID with the Pixel call as the fourth argument. For example: fbq('track', 'Purchase', {value: 129.00, currency: 'USD'}, {eventID: 'order_10422'}). The eventID key is case-sensitive and must sit in the options object, not the parameters object.
- 3Carry the ID to the server. On a purchase confirmation the server already has the order ID. For browser-generated UUIDs, post the ID alongside the form or cart payload, or read it from the data layer in a server-side tag manager.
- 4Send the Conversions API event with event_name set to 'Purchase' and event_id set to 'order_10422', the identical string. Include event_time, action_source set to 'website', and the hashed user_data fields you have.
- 5Fire the server event as close to the browser event as possible. Anything under a few minutes is fine. Anything approaching 48 hours is a gamble.
- 6Verify in Test Events before shipping, then confirm in the Deduplication tab after 24 to 48 hours of live traffic.
One rule of thumb prevents most incidents: the ID should be derived from the event, never from the tag. If two people on your team can each explain where the ID comes from without mentioning a specific tag or plugin, you have done it right. This is the same discipline that makes the rest of your campaign tracking setup trustworthy.
How do you check deduplication in Events Manager?
Events Manager gives you three places to look: Test Events for real-time verification, the Deduplication tab for per-event health, and dedup-key coverage percentages for how many events actually carry a usable key. Menu labels drift, so treat the paths below as a starting point rather than a script.
Test Events
Open your pixel dataset, go to Test Events, and add the test_event_code to your server payload. Trigger a conversion on the site. You should see the browser event and the server event appear as a pair, with the same event name and the same event ID shown on each. If you see two separate entries with different IDs, or one entry with no ID, the mismatch is visible before it touches reporting. Use this whenever you change a tag, a plugin, or a checkout template.
The Deduplication tab
In the Overview tab, expand a core event such as Purchase, open View Details, and select Deduplication. Meta shows how many events were received from each source and what share were deduplicated. A healthy redundant setup shows a high share of Purchase events marked as one event from two sources. A tab that shows near-zero deduplication while both sources are sending means the keys are not matching. A tab that shows no server events at all means your Conversions API integration is not sending, which is a different problem with a different fix.
Dedup-key coverage
Meta's Dataset Quality API exposes a dedup_key_feedback breakdown: the percentage of browser events carrying a given key, the percentage of server events carrying it, and the overall share of browser events deduplicated against server events using it. The same data surfaces in Events Manager diagnostics. Meta's stated guidance is to share deduplication keys for all events, and that a higher percentage is better. Various vendor guides quote target thresholds, but we could not find a specific percentage in Meta's own documentation, so treat anything short of near-complete coverage on a core event as something to investigate rather than accept.
Why is Meta counting my purchases twice?
Almost always because the two copies of the event carry different IDs, arrive too far apart, or come from three sources instead of two. These are the failure modes that show up repeatedly in Events Manager.
| Failure mode | What you see | Fix |
|---|---|---|
| Random ID generated separately in each tag | Both sources send Purchase with IDs, dedup rate near zero | Generate the ID once at the business event and read it in both tags |
| Server event delayed past 48 hours | Dedup works for most orders, fails for batch or queued sends | Send server events in near real time; never batch conversions daily |
| Clock skew or timezone bugs | event_time rejected or far from receipt time | Use Unix epoch seconds in UTC for event_time; do not localize it |
| event_name mismatch | Same ID on Purchase and on a custom event name | Use identical standard event names on both paths, exact case |
| Shopify Enhanced or Maximum plus a second CAPI source | Server events arrive twice with different IDs | Run one server-side source per pixel; disable the duplicate integration |
| eventID passed in the wrong argument | Pixel entries show no event ID in Test Events | Put eventID in the fourth options argument of fbq('track') |
| Confirmation page reload | Pixel fires twice with the same ID; server fires once | A real duplicate. Meta's doc says two consecutive browser events with the same information are both kept, so fix the tag trigger |
The last row is worth underlining because it is often waved away. Meta's deduplication pairs one browser event with one server event. Its documentation states that if it receives two consecutive browser events with the same information it does not discard either, and the same holds for two consecutive server events. A double Pixel fire on a reloaded thank-you page therefore inflates your count even when every event_id is correct. Guard the tag with a once-per-order check or a session flag.
The Shopify case deserves a closer look because it is common. Shopify's Facebook and Instagram app offers three customer data-sharing levels. Standard uses only the Pixel. Enhanced and Maximum both send the purchase event from Shopify's servers to Meta through the Conversions API alongside the Pixel. If you then add a second Conversions API source, such as a server-side tag manager container or a plugin, Meta receives two server-side copies of each purchase, each with its own ID, and only one of them can pair with the browser event. Pick one server-side path per pixel.
If you are not sure what is firing on a page, the free Tracking Pixel Inspector lists the pixels a URL loads, and the Website Tracking Audit scores the whole setup. Both are useful before you open Events Manager, because a duplicate Pixel install produces symptoms that look like a deduplication bug but are not.
Does the Meta-enabled Conversions API deduplicate automatically?
Yes, according to Meta's Business Help Center as reported by PPC Land. Meta's one-click Meta-enabled Conversions API, announced on April 15, 2026, mirrors the events your Pixel already sends through a server-side connection that Meta operates, and the help center states those events are automatically deduplicated. Because Meta controls both copies, it can pair them without you managing an ID. It is web-only, and it mirrors what the Pixel sends rather than adding events the browser never saw. That makes it a good default for teams with no developer, and a weaker fit if your goal is to capture conversions the Pixel misses or to send events with richer server-side data, both of which still need a real server-side integration with your own event_id.
How do TikTok and GA4 handle event deduplication?
The three major destinations use the same idea with different field names and slightly different rules. The table below is what matters when one business event fans out to all three.
| Platform | Dedup key | Also must match | Window | Which event is kept | Notes |
|---|---|---|---|---|---|
| Meta Pixel + Conversions API | event_id (Pixel: eventID) | event_name | 48 hours from first receipt | Generally the first received, when content does not differ meaningfully | Fallback on fbp or external_id, browser-first only |
| TikTok Pixel + Events API | event_id | Event type and event_source_id | 48 hours | First received | Per Elevar's summary of TikTok's rule; duplicates within about 5 minutes may have new data merged into the first event |
| GA4 gtag + Measurement Protocol | transaction_id (purchase only) | Event is a purchase | Same web stream; MP events should arrive within 48 hours of the client timestamp to be joined | Deduplicated, not first-vs-second | Web streams only; an empty transaction_id collapses all purchases into one |
Two practical differences stand out. GA4's mechanism is specific to purchases and keyed on transaction_id, so a duplicate Lead or Sign Up in GA4 is not deduplicated by an ID at all. And GA4 warns that sending an empty string as transaction_id causes it to deduplicate every purchase into one, which is the mirror image of the Meta failure: instead of double counting, you undercount to a single order. TikTok's rule is closest to Meta's, with the addition that the source ID must also match.
How server-side tracking tools handle event IDs
Most server-side tools solve deduplication by carrying a browser-generated or order-derived ID into their server request, and the main differences are where the ID is produced and how much configuration the marketer has to do. As of September 2026, Stape and TAGGRS are hosted server-side Google Tag Manager platforms; both offer a Meta Conversions API gateway product, and in a server GTM setup the event ID is typically read from the browser event forwarded to the container and reused in the Meta tag. Conversios sells WordPress, WooCommerce, and Shopify plugins with Conversions API support, where the plugin generates and reuses the ID on both paths. All three approaches work when configured correctly; the failure modes above are about configuration, not vendor.
How EndFrame handles event_id generation and deduplication
EndFrame owns the first-party event stream, so it assigns the event identifier at the point the tracking snippet records the action and reuses that same identifier when it forwards the conversion server-side. Each destination is a toggle in the dashboard: Meta Conversions API, GA4 Measurement Protocol, TikTok Events API, and custom webhooks. When a destination is on, the server-side forward carries the browser-to-server event ID as the deduplication key and sends hashed identifiers with it, so there is no separate server-side GTM container to host and no second place where an ID could be regenerated. Conversion goals can be defined by event match or URL match, with per-campaign and per-source breakdowns, and the raw visit, action, and conversion chain is stored so you can audit which event produced which conversion. It is one way to make the "generate once, pass through both paths" rule the default rather than a checklist item. Plans start at $49 per month with a 14-day free trial and no credit card required.
The bottom line
Meta deduplicates a Pixel event and a Conversions API event only when event_id and event_name both match and the second copy arrives within 48 hours of the first, and it generally keeps the one it received first. The fbp and external_id fallback is a safety net for browser-first traffic, not a strategy. Generate the ID once from the business event, pass the identical string through both paths, send the server event promptly, run a single server-side source per pixel, fix any tag that fires twice, and verify in Test Events and the Deduplication tab. Do that and redundancy gives you coverage without inflating your numbers.
Frequently asked questions
Does deduplication reduce my conversion count?
It reduces the count to the true number. If you added the Conversions API without deduplication, your reported purchases were inflated because each order arrived twice. Once event_id and event_name match on both paths, Meta collapses each pair into one event. Any drop you see after fixing deduplication is the removal of double counting, not lost conversions.
What if I only run the Conversions API and no Pixel?
Then there is nothing to deduplicate against, and Meta will not discard server events. Meta's fallback keys only work when a browser event arrives first, and server-only setups are never deduplicated by fbp or external_id. Still send a unique event_id on every server event so you are ready to add the Pixel later and so Test Events can trace each occurrence.
How do I test that Meta deduplication is working?
Use Test Events in Events Manager with your test_event_code in the server payload, trigger one conversion, and confirm the browser and server entries show the same event name and event ID. Then wait 24 to 48 hours of live traffic and open the Deduplication tab under the event's details, where a healthy setup shows most events as one event from two sources.
Do event_id and event_name really both have to match?
Yes. Meta's documentation requires the Pixel eventID to equal the Conversions API event_id and the Pixel event name to equal event_name. Matching IDs on differently named events are treated as two distinct events. Treat the comparison as an exact string match, so assume case differences, whitespace, or a prefix added by one integration will break the pair.
Is the 48-hour window measured from event_time or from receipt?
From receipt. Meta states that events are deduplicated only if received within 48 hours of when Meta receives the first event with that event_id. A server event with a correct event_time that is queued and sent two days later will not be paired with its browser event, and both will be counted. Send server events in near real time.
Sources
- 1.Meta for Developers: Handling Duplicate Pixel and Server Events
- 2.Meta for Developers: Conversions API overview
- 3.Meta for Developers: Dataset Quality API (dedup_key_feedback)
- 4.Meta for Business: Meta Pixel and Conversions API updates (April 15, 2026)
- 5.Meta Business Help Center: How to set up the Meta-enabled Conversions API
- 6.PPC Land: Meta's free one-click Conversions API is now live
- 7.Google Analytics Help: Minimize duplicate key events with transaction IDs
- 8.Google Analytics Measurement Protocol (GA4): Sending events
- 9.Elevar Docs: What is the Mismatched event_id Warning in TikTok?
- 10.Shopify Help Center: Facebook data sharing levels
- 11.Stape
- 12.TAGGRS
- 13.Conversios pricing
Try EndFrame
Recover the conversions iOS and ad blockers hide.
EndFrame collects events first-party and forwards conversions server-side to Meta, GA4, TikTok, and webhooks with event-ID deduplication — then shows the result in real time, with the visit-to-conversion path you can audit.
No credit card required