Skip to content
Paid mediaAugust 16, 2026 · 11 min read

Meta CAPI: sending server-side conversions without double counting

Meta’s Conversions API recovers the purchases your browser pixel loses. This guide covers deduplication, the parameters that actually move match quality, and the mistakes that teach your campaign the wrong thing.


Meta’s Conversions API — CAPI — is the path where an event goes from your server straight to Meta, without passing through the person’s browser. It exists because the browser pixel loses events: ad blockers, tabs closed before the pixel fires, iOS tracking restrictions and plain network failures.

The gain is real, but it depends on three decisions almost everyone gets wrong on the first implementation.

1. Deduplication: the mistake that doubles your revenue

If you keep the browser pixel and switch on CAPI, every purchase is reported twice. Meta knows how to resolve that — as long as both sends carry the same event identifier.

both sides need the same event_id
// Browser
fbq('track', 'Purchase', { value: 1997, currency: 'USD' },
    { eventID: 'order-88213' })

// Server (CAPI) — SAME event_id
{
  "event_name": "Purchase",
  "event_id": "order-88213",
  "event_time": 1755340000,
  "action_source": "website",
  "user_data": { "em": ["<sha256>"], "ph": ["<sha256>"] },
  "custom_data": { "value": 1997, "currency": "USD" }
}

Without a matching event_id on both sides you do not have double coverage — you have double counting. The report looks great and the campaign optimizes against a number that does not exist.

The identifier has to be stable and derived from the business — an order number, a transaction id — never a random value generated at send time, which by definition would differ between the two paths.

2. The parameters that move match quality

Meta can only attribute the conversion if it can recognize the person. The user_data parameters do not carry equal weight, and it pays to know where to spend effort:

ParameterWhat it isPractical weight
emEmail, sha256 hashedHigh — the most decisive one
phPhone, sha256 hashed, with country codeHigh
fbcAd click cookieHigh when present: it is direct attribution
fbpBrowser pixel cookieMedium, helps stitch sessions
external_idYour own identifier for the personMedium, improves consistency
ct, st, zp, countryLocationLow alone, useful in combination
fn, ln, ge, dbName, gender, birth dateLow, but additive

The common mistake here is sending only what arrived in the event payload. The email usually exists in your database even when it was not in the request — which is why user_data should be assembled from the identity graph, not from the raw payload.

The fbc detail almost nobody fixes

The _fbc cookie is created by Meta’s script when someone arrives with an fbclid parameter in the URL. If that script is blocked the cookie is never born and direct attribution is lost — precisely for the visitor who is hardest to recover later. The fix is to build the cookie in first-party context from the URL’s fbclid, in the format Meta expects.

3. Filtering what goes up

This is the most expensive mistake and the quietest one. If you send every purchase event without checking status, a payment that was generated and never completed becomes a conversion. The campaign then learns to find people who start payments and never finish — and it is very good at doing what it is told.

  • Send only approved or completed status; a printed invoice or an expired payment is not a sale.
  • Separate first purchases from subscription renewals, or every monthly charge becomes a new acquisition.
  • Watch for the same order arriving through two paths (webhook and history sync) — it needs deduplication by business identity.
  • Do not send old sales during reprocessing: Meta rejects events older than seven days, and whatever slips through distorts the window.

How to know it is working

Meta’s Events Manager shows match quality, but with delay and in aggregate. The more useful signal is measured on your side: across the payloads you actually delivered, what percentage carried email, phone, fbc and external_id. If email is present in 30% of your sends, no configuration on Meta’s side will rescue matching — the problem is capture.

Parameter coverage is an engineering metric, not a media metric. It gets fixed at collection, and it is measurable before any campaign runs.

In CrazyLeads these three points are the default behavior: the event_id comes from business identity, user_data is assembled from the identity graph, and the status filter is configured against your source’s real payload and tested on recent events before publishing.

Start measuring what actually becomes revenue

Create a free account, connect your first source and see your first lead timeline today. No card required.