Elido
11 min readtutorials

Forwarding conversions to Meta CAPI through Elido short links

How to recover the 30-40% of conversion events Meta Pixel loses to ITP — CAPI setup, match keys, dedup discipline, and the validation checklist

Ana Kowalska
Marketing solutions engineering
Diagram showing browser Meta Pixel losing events with strikethrough on one side and Elido server-side CAPI forwarding recovering them on the other

Meta's own guidance, published on the Conversions API getting started page (accessed 2026-05-12), frames the browser pixel as a complement to CAPI, not the other way around. That shift happened around iOS 14.5: App Tracking Transparency cut Meta's signal quality, ITP ate another slice, and ad-blocker installs kept climbing. By 2026, teams running Meta ads against iOS-heavy audiences are routinely seeing 30-40% of conversion events disappear before they reach reporting.

CAPI is the server-side channel that bypasses all of it. Your server talks directly to Meta's graph API. ITP doesn't apply. Ad-blockers don't intercept it. Match rate goes up because you can send hashed email and phone alongside the click identifier; because both browser and server events share a dedup key, Meta counts the conversion once even when both paths fire.

This is the step-by-step for wiring CAPI through Elido's short links. The server-side conversion tracking overview covers the broader architecture (GA4, TikTok, Mixpanel, retry semantics). The end-to-end UTM tutorial is worth reading first if your campaign tagging is still informal.

TL;DR#

  • Meta Pixel loses 30-40% of conversion events on iOS-heavy traffic to ITP and ad-blockers; CAPI sends those events directly from your server, recovering most of the gap.
  • The deduplication key — event_id — must be identical between your browser-side pixel and your CAPI event. Missing this causes double-counting, which breaks Meta's optimisation budget allocation.
  • Higher match-key density (hashed email, phone, fbc click ID, fbp cookie) directly improves attribution match rate; Elido captures fbclid at click time and associates it with every downstream conversion.
  • Validation takes about 10 minutes: Meta Events Manager has a Test Events panel that shows CAPI events arriving within 30 seconds, well before the 24-hour match-rate dashboard populates.

What you need before starting#

Three things, all from Meta Business Manager.

Pixel ID. Every Meta ad account has at least one pixel. Find it in Events Manager under Data Sources. The numeric string — something like 1234567890 — is what you'll paste into Elido's integration settings.

System User access token. This is the credential that authorises Elido to write events to your pixel. Navigate to Business Settings, then Users, then System Users. Create a system user with Standard access, assign it to the pixel (Manage permissions), and generate a token with the ads_management and business_management scopes. The token is long-lived; rotate it when you rotate other service credentials, not on a schedule. Store it as a workspace secret — not in source code, not in a spreadsheet.

Event source URL pattern. Every CAPI event carries an event_source_url that tells Meta which page the conversion occurred on. For purchase events, this is typically your checkout confirmation URL. For lead events, it's the form submission page. You don't hard-code these; they come from your order webhook or your backend's request context at conversion time.

The match keys: why density matters#

Meta deduplicates and matches server events to browser sessions using a set of customer information parameters. The more of them you send, the higher the match rate. Higher match rate means more conversions attributed to your campaigns, which means the optimisation algorithm has better signal, which means better ROAS. The relationship is direct.

The four keys that matter most:

em (SHA-256 hashed email). The single highest-value signal. If you have the customer's email at conversion time (you almost always do for ecommerce), send it. The Meta customer information parameters reference (accessed 2026-05-12) specifies the normalisation rules: lowercase, trimmed of leading/trailing whitespace, no modifications to the domain. Hash the normalised string. Sending Alice@Example.com hashed directly produces the wrong value; alice@example.com is what to hash.

ph (SHA-256 hashed phone). Same normalisation discipline. E.164 format: country code, no spaces, no dashes, no parentheses. +4915123456789 hashes to something Meta can match; 015123456789 does not.

fbc (Facebook click ID). When a user clicks a Meta ad, the destination URL receives a fbclid query parameter. Your landing page or the Elido redirect handler reads it and stores it. The fbc field is constructed from this: fb.{version}.{creationTime}.{fbclid}, where version is 1 and creation time is the Unix timestamp in milliseconds. Elido captures the fbclid from the redirect URL at click time and stores it against the click record. When you POST a conversion with a click_id, the fbc value is already attached and gets forwarded automatically.

fbp (Facebook browser pixel cookie). This is the _fbp cookie that the Meta Pixel JS sets on your domain. It's a first-party cookie from your domain's perspective. Your server reads it from the request headers at checkout time and includes it in the conversion payload. Without it, Meta's match rate for the browser-side fallback path degrades.

The practical priority order: em first (almost always available), fbc second (Elido provides it for click-sourced conversions), fbp third (read from cookie on the confirmation page), ph last (often not captured). A payload with em + fbc will match significantly better than one with nothing.

Wiring it in Elido#

The integration lives in Workspace Settings, under /integrations, then Meta CAPI.

Paste your Pixel ID and System User access token. Elido validates the token against the Meta graph API immediately — a 400 here means the token is malformed or lacks the required scopes; check the system user permissions before proceeding. Once validated, the integration is active for the workspace. All tracked links in the workspace participate; there's no per-link toggle.

When a tracked link is clicked, Elido's edge handler reads the fbclid from the query string (if present) and writes it to the click record. This happens at the redirect layer, before the user reaches your site, so the capture is reliable regardless of whether your destination site's JavaScript runs.

When a conversion event fires, POST it to /v1/conversions:

curl -X POST \
  https://api.elido.app/v1/conversions \
  -H "Authorization: Bearer $ELIDO_TOKEN" \
  -d '{
    "click_id":   "clk_01HYZ7T8WV6KQX3M",
    "event_name": "Purchase",
    "event_id":   "ord_98231",
    "value":      89.50,
    "currency":   "EUR",
    "user": {
      "email":  "shopper@example.com",
      "phone":  "+4915123456789"
    }
  }'

On receipt, Elido looks up the click record, reads the stored fbclid to construct fbc, normalises and hashes email and phone, assembles the full CAPI payload, and POSTs to https://graph.facebook.com/v21.0/{pixel_id}/events. The API call returns a conversion ID immediately; fan-out to Meta is background and observable via GET /v1/conversions/{id}.

The raw CAPI payload Elido constructs looks like this:

{
  "data": [
    {
      "event_name": "Purchase",
      "event_time": 1747047600,
      "event_id": "ord_98231",
      "action_source": "website",
      "event_source_url": "https://shop.example.com/checkout/thanks?order=98231",
      "user_data": {
        "em": ["a3b6e2f4...sha256 of alice@example.com"],
        "ph": ["c7d9f1a3...sha256 of +4915123456789"],
        "fbc": "fb.1.1747040000.AbCdEfGhIj",
        "fbp": "fb.1.1747040000.987654321",
        "client_user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 ...)",
        "client_ip_address": "203.0.113.42"
      },
      "custom_data": {
        "currency": "EUR",
        "value": 89.50,
        "content_ids": ["sku-spring-jeans-32-blue"],
        "content_type": "product",
        "num_items": 1
      }
    }
  ],
  "access_token": "EAAxxxxxxx"
}

The event_source_url and action_source fields are derived from the click record's destination URL and the conversion request's source parameter (defaults to website). If you're forwarding app-side conversions, pass "source": "app" in the POST body.

Deduplication discipline#

Read Meta's event deduplication documentation (accessed 2026-05-12) before you touch production traffic. The short version is this: Meta matches browser pixel events and CAPI events using event_id + event_name within a 48-hour window. If both events carry the same pair, the second one is silently discarded.

The operational requirement that follows: your browser-side pixel's Purchase event and your server-side CAPI event must share the same event_id. The most reliable choice is your order ID: both sides see it, it's stable, it's not regenerated on retry.

Where this breaks in practice: the server generates a UUID at forward time instead of using the order ID. Or the browser pixel uses one ID scheme (ord_98231) and the backend uses another (order-98231). Both events ingest. Neither is deduped. Your reported conversions double. Meta's algorithm over-allocates budget to the campaign based on inflated numbers. The budget review three weeks later reveals "our ROAS is somehow 2.5× our actual revenue" and the forensics are unpleasant.

The sequence diagram below shows how the event_id travels through the system:

Event sequence from user click through Elido edge capture to merchant conversion POST to Meta CAPI — fbclid captured at edge, event_id shared for dedup

The browser-side pixel call happens client-side when the confirmation page loads. The server-side CAPI forward happens when your order webhook fires. Both must emit event_id: ord_98231 (or whatever your order identifier is). The timing gap between the two is irrelevant as long as both arrive within 48 hours.

If you're not running a browser-side pixel (removed for GDPR consent reasons, or because your audience is entirely ad-blocker-heavy), deduplication is moot. Send CAPI-only. But most teams run both; the browser pixel provides fallback signal for users where CAPI events can't carry match keys (no email captured, no fbclid).

Validation#

The validation loop is short and should happen before any production traffic flows through.

Step one: set a test event code. In Elido's Meta CAPI integration settings, there's a test event code field. Get a code from Meta Events Manager under Test Events. Paste it. While this code is set, every CAPI event Elido sends is routed to the test panel — it never enters production reporting.

Step two: fire a test conversion. Click one of your tracked links from a browser (this captures the fbclid if the link URL came from a Meta ad, or from a link with fbclid manually appended for testing). POST a conversion against that click_id with a realistic order ID, value, and email address.

Step three: check Test Events. In Meta Events Manager, the test event should appear within 30 seconds. Verify that the event_name matches what your browser pixel is sending. Verify the event_id is the order ID, not a UUID. Verify that em, fbc, or fbp appear in the user_data section — at least one match key should be present.

Step four: remove the test event code. Once validated, clear the test event code field and save. Production events start flowing. The match-rate dashboard in Events Manager takes 24 hours to populate with meaningful data.

What to look for at the 24-hour mark: match rate above 60% is workable; above 75% is good; above 85% means your match-key density is high and attribution will be reliable. If you're below 60%, the most likely cause is missing fbc (the fbclid wasn't on the landing URL) or a hashing normalisation error.

Common failure modes#

Missing event_source_url. CAPI events without this field are accepted but penalised in Meta's matching logic. The field should be the URL of the page where the conversion occurred — your checkout confirmation URL, your lead form landing page, your app's equivalent. Elido derives it from the click record's destination URL when not overridden; pass it explicitly in the conversion POST if your confirmation URL differs from the redirect destination.

Hashed key not lowercase-trimmed. Alice@Example.com and alice@example.com produce different SHA-256 values. Meta's servers hash the canonical form stored in their user graph. If your hash doesn't match, the event lands as unmatched. The normalisation requirement applies to phone numbers too: strip country code formatting variations, force E.164. Routing through Elido's /v1/conversions endpoint means the normalisation is handled on your behalf; you pass the raw email and phone, Elido hashes per spec.

action_source mismatch. Web-originated conversions use "action_source": "website". Mobile app conversions use "app". If you're forwarding a purchase that happened in your iOS app but send action_source: "website", Meta's attribution model may degrade the signal. Pass "source": "app" in the Elido conversion POST for app-side events.

fbc absent because fbclid wasn't on the URL. This happens when the ad's destination URL doesn't include fbclid — either because the campaign doesn't have "Auto-advanced matching" enabled, or because the URL was hand-built without it, or because the user arrived via a retargeting path that didn't carry the parameter. When fbc is missing, the conversion still forwards, but match rate drops to email/phone-only. Check campaign settings in Meta Ads Manager; fbclid should appear on destination URLs for standard traffic campaigns.

Double event_id schemes. The browser pixel and the CAPI event use different formats for the same order ID. This almost always happens when different teams own the frontend tag manager config and the backend order webhook integration. Agree on a canonical format before launch. Order ID as a string (ord_98231) works. Numeric-only also works. The pixel emitting "ord_98231" and the server emitting "98231" are treated as different events: neither is deduped.

A worked outcome#

An EU-based ecommerce brand running Meta ads into Germany and Austria reported a 38% match rate with pixel-only tracking. Safari on iOS accounted for roughly 45% of site traffic; ATT opt-out rates in the 25-44 demographic ran around 72%.

After wiring CAPI through Elido with em + fbc as the primary match keys, match rate climbed to 76% within the first week. fbc was now present on every conversion that originated from a Meta ad click (Elido captures fbclid at the redirect layer, not at the browser level), and the hashed email forwarding provided a second match path for conversions where the _fbp cookie had expired.

CPA dropped 18% over the following four weeks. Reported ROAS moved from 2.1 to 2.6. The 18% CPA reduction reflects better attribution, not better campaign performance: the campaigns were always performing at 2.6 ROAS; the pixel alone was under-reporting.

Where this sits in the attribution pipeline#

CAPI is one channel in a broader server-side forwarding setup. The server-side conversion tracking overview covers GA4 Measurement Protocol and TikTok Events API with the same depth this post applies to Meta. Cookieless attribution explained is worth reading if you want the underlying why — ITP, link tracking protection, and the attribution model shifts that followed.

For the product surface: conversion tracking features documents the full API, including refund events, multi-touch attribution modes, and the retry/backoff semantics. Solutions for marketers shows how the pieces fit together in a campaign workflow.

The setup described above is achievable in a morning. The main investment is time at validation — 30 minutes in Meta Test Events before flipping production traffic. That 30 minutes is worth it; the alternative is discovering a misconfiguration three days later when the algorithm has already acted on the wrong numbers.


Sources

  • Meta Conversions API: Getting Started. developers.facebook.com/docs/marketing-api/conversions-api/get-started/ (accessed 2026-05-12)
  • Meta Conversions API: Deduplicate Pixel and Server Events. developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events/ (accessed 2026-05-12)
  • Meta Conversions API: Customer Information Parameters. developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters/ (accessed 2026-05-12)

Try Elido

EU-hosted URL shortener with custom domains, deep analytics, and an open API. Free tier — no credit card.

Tags
meta capi conversion
meta conversions api
capi server side
facebook capi tutorial
server side tracking
elido conversions

Continue reading

Forwarding conversions to Meta CAPI through Elido short links · Elido