Skip to content

Answer library  /  Conversion Tracking  ·  Architecture

How do I set up the Meta Conversions API the right way?

Run the Conversions API beside the pixel. Send the same events from both, give each pair the same event_id and event name so Meta keeps one, and pass hashed customer data for matching. Dedup is where builds break. On one store I audited, two CAPI builds with mismatched event IDs double-sent every purchase for six months.

What the Conversions API is

The Conversions API (CAPI) sends conversion events to Meta from your server instead of from the browser. The pixel still fires client-side. CAPI runs alongside it, server-side. The point is coverage. Browser events get blocked by ad blockers, iOS settings, and consent tools. Server events don’t, because they leave from your infrastructure, not the visitor’s device.

Treating CAPI as a switch you flip to “fix tracking” is how stores end up worse off. On one store I audited, Meta’s 2024 CAPI auto-setup was still live in GTM beside a newer server-side build. Both sent every purchase, their event IDs didn’t match, and Ads Manager carried inflated purchase counts for six months. A bad CAPI build makes reporting worse than no CAPI at all, because now you have two streams that double-count or contradict each other. The architecture is what makes it work.

The two-stream model

Run the pixel and CAPI as a matched pair. Every key event fires twice: once from the browser through the pixel, once from your server through CAPI. PageView, ViewContent, AddToCart, InitiateCheckout, Purchase. Both sides send the same event for the same user action.

That sounds like double-counting, and it would be, except for one field. You send a shared event_id on both the pixel call and the server call, with the same event name on both. When Meta receives that pair for the same pixel within 48 hours, it keeps one and discards the duplicate. Without event IDs, Meta can fall back to the event name plus fbp or external_id, but that fallback generally only works when the browser event arrives first, so don’t build on it. This is deduplication, and it’s the single most important part of the setup. Get it wrong and your Purchase count inflates, your ROAS looks better than reality, and the account optimizes toward a number that doesn’t exist.

So the build order is: pixel first, CAPI second, dedup keys wired before you trust a single number.

What CAPI needs to match

A server event with no identity is close to useless. Meta has to tie the event back to a person to attribute it and to optimize. You do that by passing customer information parameters, hashed with SHA-256 before they leave your server. The fields that move match quality the most:

  • Email (hashed)
  • Phone (hashed)
  • fbp and fbc cookies, captured from the browser and forwarded to the server
  • IP address and user agent
  • External ID, if you have a stable customer id

The fbc cookie carries the click id from the ad click. Forwarding it’s what lets a server-side Purchase get attributed back to the specific ad that drove it. Skip it and you lose attribution on a large share of conversions even though the event itself arrived.

Match quality shows up in Events Manager as the Event Match Quality score per event. Below “Good” on Purchase, fix identity before you touch anything else.

How to send the events

There are three common paths, in rough order of how much control they give you.

Direct server-to-server. Your backend posts events to the Graph API endpoint. Most control, most match potential, most engineering. This is the right call for a custom stack or a high-spend account where match quality pays for itself.

Server-side Google Tag Manager (Stape or your own container). The browser sends events to a server container you own, and that container forwards them to Meta with full data. This is what I reach for on Shopify and most lead-gen sites. You get server-side identity and dedup without writing API calls by hand, and one container can feed Meta, GA4, and TikTok from the same event stream.

Native platform integration. Shopify’s built-in Meta channel and partner connectors send CAPI for you. Fast to turn on. The catch is you give up control of dedup keys and the exact data sent, so verify in Events Manager that events deduplicate and match well before you rely on it. Auto-setup tools carry the same risk. On the store with the six-month double send, the old auto-setup had also written the CAPI access token into a GTM tag in plaintext, so every saved container version held a live token anyone with read access could copy. Keep the token in a variable, and check what any automated setup left behind before you trust it.

Verify before you trust it

Setup isn’t done when the connection turns green. It’s done when you have confirmed the numbers reconcile.

  1. Open Events Manager and check that each event shows both “Browser” and “Server” as sources.
  2. Confirm the deduplication rate is high. Low dedup means your event_id isn’t matching across the two streams.
  3. Check Event Match Quality on Purchase and Lead. Push the weak ones up with more identity fields.
  4. Compare Meta’s reported Purchase count against your real backend over the same window. Shopify orders, your CRM, your database. If Meta is meaningfully higher, you have a dedup or double-fire problem. If it’s much lower, you have a coverage or match problem.

That last step is the one people skip, and it’s the only one that tells you the truth. The platform UI will happily show you a healthy-looking setup that’s double-counting. Reconciling against the source of record is how you catch it.

Where it sits in the stack

CAPI is one layer of a tracking stack, not the whole thing. It depends on a clean event layer feeding it, consistent event names across pixel and server, and a consent setup that doesn’t strip the data you need. If your GA4 and Meta numbers already disagree, adding CAPI on top of a broken foundation just gives you a third number to reconcile. The store with the double send had the same problem underneath: it was paying for first-party loading, yet its theme still pulled GTM from googletagmanager.com, so ad blockers caught it on every visit and recovery from them read 0 percent. Safari recovery on the same server container was working, at 45 percent of events. The full audit is on the blog. Fix the event layer and identity capture first, then add the server stream, then verify it reconciles. In that order it earns its place. Out of order it adds noise.

When to bring me in

Bring me in when Google Ads, Meta and your store report different numbers for the same sales, when a purchase or lead event stopped firing after a site change, or when you can’t say which number to trust.

I'm Conner Crowe, and I write every audit myself. Send the free audit request and add me as a read-only user, and within 24 hours of access you'll have a written read on which numbers to trust and what to fix first. No call needed, and nothing in your account or store changes.

Request a free Google Ads audit

See how I fix conversion tracking.

Tools for this diagnosis

All my free tools

Related questions

Back to the full conversion tracking: the diagnosis library

Want your tracking checked?

Same check,
run on your tracking.

Add me as a read-only user and I'll write the audit myself: which of your numbers to trust and what to fix first, 5 to 7 pages, back within 24 hours of access. No call needed. If you'd rather talk first, a call is open too.