← All posts Attribution

Server-side conversions with Meta CAPI: what breaks and how to fix it

31 Jul 2026 · 5 min read · Twinslytics

Meta cut off third-party cookie tracking, so everyone rushed to implement Conversions API. Then ROAS numbers got weirder, not better. If you've deployed CAPI and your reported revenue still doesn't match Shopify, you're not alone — most implementations have at least one silent failure point that nobody catches until finance asks why the numbers don't reconcile.

Deduplication fails more than it works

CAPI is supposed to work alongside the browser pixel, not replace it. Meta deduplicates events using event_id and event_name matching between the two sources. When that matching breaks, you get double-counted purchases inflating your conversion volume, or Meta discarding legitimate server events because it thinks they're duplicates.

Fix this by generating the event_id once, at the earliest point in the transaction, and passing that same string through to both the browser pixel call and the server-side API call. Don't regenerate it on the backend. Log it on both ends during QA and diff the logs — if the IDs don't match 1:1, your dedup is broken and every dashboard number downstream is wrong.

Match quality quietly degrades

CAPI's entire value proposition is that it can match a server-side event to a Meta user even without third-party cookies. That matching depends on hashed customer data — email, phone, external ID — passed correctly in the user_data object. This is where most implementations bleed accuracy without anyone noticing, because Meta doesn't reject bad data outright. It just matches less of it.

Normalize every field before hashing — lowercase, trim whitespace, strip formatting on phone numbers — and always include external_id if you have a logged-in customer or a durable cookie-based ID. Check your Events Manager match quality score weekly, not once at launch. It degrades as new checkout flows, new plugins, or new agency hands touch the tracking code.

Server events arrive with stale or missing data

A lot of CAPI implementations pull event data from a webhook — Shopify's order creation webhook, for example — and fire it straight to Meta. The problem: webhooks fire on order creation, not on the actual customer action, and the payload often lacks the browser-side context Meta wants for attribution, like fbc (click ID) and fbp (browser ID) cookies.

Capture fbc and fbp client-side at the moment of purchase and store them with the order — in an order note, a custom field, whatever your platform allows — so your server-side call has them available when the webhook fires. And explicitly filter your webhook logic to exclude refunds, test orders, and duplicate order-update events, not just order-creation events.

Consent signals don't travel with the event

If you're running in markets with GDPR, CCPA, or similar frameworks, your consent management platform blocks the pixel when a user opts out. But server-side calls often bypass that same consent check because they're not running in the browser — the backend doesn't know what the user chose. This creates a compliance gap and, ironically, can also create bad data: events firing for users who explicitly opted out get sent anyway, muddying your true opted-in audience size and putting you at legal risk.

Pass consent state through to your backend as part of the event payload — store it with the session or order — and gate your server-side send logic on that same flag. Meta's Limited Data Use flag exists for exactly this reason; use it, and make sure your consent platform's opt-out status is actually reaching your server logic, not just your client-side pixel snippet.

Nobody validates after launch

The most common failure isn't technical — it's organizational. Teams stand up CAPI, check the Events Manager diagnostics tab once to confirm it's "connected," and never look again. Meanwhile a Shopify app update changes the checkout flow, a new landing page skips the tracking snippet, or an agency swaps ad platforms and forgets to update the event mapping.

CAPI isn't a set-and-forget fix for post-iOS14 tracking loss. It's a pipeline with the same failure modes as any data pipeline: bad joins, stale data, missing fields, and no monitoring. Treat it that way — validate it like you'd validate any revenue-critical data feed — and the ROAS numbers you report will actually mean something.

Further reading

283/408 sessions reattributed — Fixed attribution, returned conversions to Google Ads

Want your attribution reconciled like this?

We patch the join between clicks and closed revenue so bidding optimizes on what actually happened, not what the checkout referrer claims.