Meta conversion tracking end to end: pixel, CAPI, and events that dedup
Meta conversion tracking is one pipeline, not three products. Install the pixel, add the Conversions API on whichever of three paths fits your stack, and make sure Meta counts each sale once instead of twice. Includes the four reasons that count quietly doubles.

You turn on the Conversions API and your Meta conversions jump overnight. The
ads didn't get better: every purchase is now counted twice, once from the
browser pixel and once from your server, and nothing is telling Meta they're
the same sale. Meta conversion tracking is really one pipeline with three
layers: the pixel (browser events), the Conversions API (CAPI) (the
same events from your server), and the shared event_id + event_name
that lets Meta collapse the pair into one count. Skip a layer and you either
lose signal or double it.
The advice you'll usually find covers one layer at a time: a pixel install here, a CAPI integration there, a one-line "remember to dedup." But you're not assembling three products, you're honoring one contract, and the contract is the only place it breaks. This guide runs the pipeline end to end, then spends its best sections on the layer that actually fails: getting the two transports to match.
#The three layers, one pipeline
The pixel and CAPI are redundant transports for the same events, and that
redundancy is deliberate. Browsers running ITP, ad blockers, and
consent-restricted sessions drop
pixel events; server events don't have that problem but lack browser
context. Meta's answer is: send both, tag both with the same event_id,
and let Events Manager collapse them.
#Layer 1: install the Meta pixel
The pixel is the browser half: the base code sitewide, standard events
(Purchase, Lead, CompleteRegistration) on the moments that matter,
with value and currency on anything money-shaped. Install directly or
via GTM; on Shopify, use the native integration rather than pasting code (the
store-specific path is Shopify pixel setup: native web pixels and the Meta Pixel, done right). What the pixel is (and
its post-cookie limits) gets full treatment in The Meta Pixel: what it is, what it sees, where to find your ID; what matters
here is one rule: every event you'll also send server-side must carry an
eventID from the moment it fires. Retrofitting IDs later means a window of
double counting.
#Layer 2: stand up CAPI on one of three realistic paths
Pick by who maintains it, because CAPI is infrastructure, not a checkbox:
- Partner integration (Shopify, WooCommerce, and other platform-native CAPI). Least control, least maintenance, dedup handled for you: the correct default for standard ecom stacks.
- Server-side GTM: your own tagging server forwards events to Meta, so you get full control over what's sent and one place to manage every platform. Setup and tradeoffs live in Server-side tagging with sGTM: setup, costs, and when it's not worth it.
- Direct API integration: your backend calls the Conversions API. Maximum control and the only path that cleanly sends CRM-stage events, at the cost of owning the code.
If you're still deciding whether CAPI is worth standing up at all, Conversions API vs the Meta Pixel: what actually changes is the decision page; the short version is that "pixel or CAPI" is the wrong question. The choice is which CAPI path, not whether.
#Layer 3: dedup, the contract and the four ways it breaks
Dedup is exact-match on two fields: when a browser event and a server event
arrive with the same event_name and the same event_id, Meta keeps one,
per its
deduplication documentation.
No match, no dedup, and every miss inflates your conversions. Running
Buron's first-party pixel alongside Meta's, these are the four misses we
actually hit:
- Missing
event_idon one side. The pixel fires with an ID, the server event ships without one (or vice versa). Both count. Detection: Events Manager → your event → the dedup/"event overlap" view, where server events should show as deduplicated against browser events. - Mismatched ID formats or casing.
Order-1234vsorder-1234, a UUID regenerated per transport instead of shared. Exact string match means "almost identical" is "different". Detection: Test Events tool, fire one conversion and read both raw payloads side by side. - Late server events. The server batch lands hours later (queue backlog, cron cadence); dedup works within Meta's matching window, but late-arriving events degrade matching and make daily counts wobble, and events later than the window count separately. Detection: compare event timestamps browser-vs-server in Test Events; keep server sends near-real-time.
- Missing browser event. The pixel is consent-blocked or ad-blocked, so the server event stands alone. That's dedup working as designed (CAPI recovering signal), but if you expected both, your pixel-based numbers (and any platform comparing against them) drift. Detection: browser/server event ratio per event in Events Manager; sudden ratio shifts mean a banner or blocker change, not a sales change.
#Verify in Events Manager
Verification is three surfaces, in order. Test Events: fire a conversion with the test code active and watch both events arrive with matching IDs. The event detail view: deduplication status healthy, browser/server overlap where you expect it, and EMQ (event match quality) not sitting in the red. Low EMQ means your server events are shipping without enough hashed customer parameters. Ads Manager sanity: conversion counts within a plausible band of your store or CRM truth. If Meta and Shopify disagree hard, that has its own diagnosis in Why Facebook Ads conversions don't match Shopify, and the recurring version of all these checks is The conversion tracking QA checklist: test it like you'd test code.
Here's the part the setup guides leave out: dedup isn't a launch-day property. It holds the day you verify it, then drifts the next time a theme changes, a consent banner updates, or an app regenerates IDs. And it drifts silently. The break has an unmistakable shape (illustrative numbers): browser/server pairing holding around 95% for months, then dropping to 60% overnight the day a theme update ships, while both individual event counts still look perfectly healthy. Nothing in Events Manager waves a flag, because nothing there is technically broken.
Which is exactly why verifying dedup once isn't the finish line. The hard part is catching the day it silently slips, and that's the part worth handing off. Buron runs a first-party pixel next to Meta's and watches the browser/server/order ratios continuously, so the day the pairing drops you get a dated finding instead of three weeks of double-counted conversions steering Advantage+. [Connect your store →]
Frequently asked questions
Why is Meta counting my conversions twice?
Almost always a deduplication miss: the pixel and the Conversions API both report the same purchase, but the two events don't carry a matching event_id and event_name, so Meta counts them as two conversions. Fix the IDs so both sides send identical values, then confirm the dedup status in Events Manager.
Do I need both the Meta pixel and the Conversions API?
Yes: they're layers, not alternatives. The pixel captures browser context and covers users the server path can't see; CAPI recovers the events browsers block or drop and improves match quality. Meta's guidance and observed delivery both favor running both with deduplication, not choosing one.
What is event match quality (EMQ) in Events Manager?
A 0 to 10 score per event estimating how well the customer information you send (hashed email, phone, click ID like fbclid/fbp) lets Meta match events to accounts. Higher EMQ means more attributed conversions and better optimization; raising it means sending more, and better-formatted, matching parameters server-side.