How to Set Up Meta Conversions API (CAPI): Step-by-Step Guide
The Meta Pixel alone misses a growing share of conversions — blocked by ad blockers, browser privacy features, and iOS restrictions. The Conversions API (CAPI) sends events server-side to recover that data. This guide covers a clean CAPI setup that runs alongside your Pixel without double-counting.
Tools used in this guide
What is the Meta Conversions API?
The Meta Conversions API (CAPI, formerly the Facebook Conversions API) is a server-to-server connection that sends your customer events — page views, leads, add-to-carts, purchases — directly from your server to Meta, instead of relying only on the browser-based Meta Pixel. It gives Meta a second, more reliable channel of conversion data to attribute ads, optimize delivery, and build audiences.
Think of it as a backup generator for your tracking: when the Pixel gets blocked or degraded in the browser, the Conversions API keeps the signal flowing from your server, where ad blockers and browser privacy controls can't reach.
Why Meta built the Conversions API
The Pixel is a JavaScript tag that runs in the visitor's browser. That makes it fragile, because everything that blocks or restricts browser scripts also blocks your conversion data:
- Ad blockers strip the Pixel entirely — a significant share of users run them.
- Safari's Intelligent Tracking Prevention (ITP) caps client-side cookies, so returning-visitor and delayed conversions get lost.
- iOS App Tracking Transparency (ATT) limits what Meta can observe after the App Store opt-out prompt.
- Network failures, slow pages, and consent tools silently drop events before they fire.
The combined effect is real: it's common to lose 10–30% of conversions with a Pixel-only setup. Fewer observed conversions means worse attribution, weaker campaign optimization (Meta's algorithm learns from conversions it can see), and smaller retargeting audiences. The Conversions API exists to recover that lost signal by moving the source of truth server-side.
How the Conversions API works
At a high level, CAPI adds a second path for the same events:
- A customer takes an action on your site (say, a purchase).
- The Pixel fires that event from the browser, as it always did.
- Your server independently sends the same event to Meta through the Conversions API, with hashed customer data and the Meta identifiers it can gather.
- Meta receives both copies and deduplicates them using a shared event ID, counting the conversion once.
The result is resilience: if the browser copy is blocked, the server copy still arrives. If both arrive, dedup prevents double-counting.
The key concept: run CAPI and the Pixel together
CAPI is not a replacement for the Pixel — it's a complement. The recommended architecture is a redundant setup: send each important event from both the browser (Pixel) and the server (CAPI), and let Meta deduplicate. Getting dedup right is the single most important part of the whole setup — skip it and you'll double-count every conversion.
Pixel vs Conversions API — how they compare
| Dimension | Meta Pixel | Conversions API |
|---|---|---|
| Where it runs | Browser (client-side) | Your server (server-side) |
| Blocked by ad blockers / ITP | Yes | No |
| Data reliability | Degrading | High |
| Customer data | Limited, browser-only | Hashed email/phone + fbp/fbc |
| Setup effort | Low (paste a tag) | Medium (server integration) |
| Best used | As one signal | Together with the Pixel |
The takeaway: they're not either/or. The Pixel captures rich browser signals (like fbp/fbc); CAPI guarantees delivery. Together they give Meta the most complete, resilient picture.
What you need before you start
Gather these first — the setup goes smoothly when they're ready:
- A Meta Business account (Business Manager / Meta Business Suite) that owns your ad account and dataset.
- A dataset (Pixel) and its Pixel ID. If you already run the Meta Pixel, use the same Pixel ID for your server events — CAPI and the Pixel must share one dataset for deduplication to work.
- An access token. The easy path: Events Manager → your dataset → Settings → Conversions API → Generate access token (no App Review or permissions needed). For production-grade control, create a System User in Business Settings and generate a token scoped to
ads_management. - Somewhere to send events from — your backend, a server-side GTM container, a Conversions API Gateway, or a partner integration.
- Customer data you're permitted to use (email, phone, etc.), which you'll hash before sending.
How to set up the Conversions API
Step 1: Choose your integration method
There are three common ways to implement CAPI, from easiest to most flexible:
- Conversions API Gateway / partner integration (Shopify, WooCommerce, GTM Server-Side) — lowest effort, good for most businesses
- Server-Side Google Tag Manager — the practitioner's choice; full control and works across ad platforms
- Direct API integration — your developers call Meta's API from your backend; maximum control, most work
For most teams, server-side GTM is the sweet spot. The rest of this guide assumes that approach, though the concepts apply to any method.
Step 2: Generate your access token in Events Manager
In Meta Events Manager, select your dataset (Pixel), then go to Settings → Conversions API → Generate access token. Copy the token somewhere secure — it authenticates your server's events, so treat it like a password. Note your Pixel ID as well.

Step 3: Send events with a shared event ID
This is where deduplication is won or lost. When you fire an event, generate a single event ID and send it through both the Pixel and CAPI. Meta matches on event_name + event_id and drops the duplicate.
On the browser side (Pixel):
const eventId = crypto.randomUUID();
fbq('track', 'Purchase', {
value: 59.99,
currency: 'USD'
}, { eventID: eventId });On the server side (CAPI), send the same event_id for the same user action:
{
"event_name": "Purchase",
"event_time": 1735689600,
"event_id": "the-same-uuid-from-the-browser",
"action_source": "website",
"user_data": {
"em": "<sha256-hashed-email>",
"ph": "<sha256-hashed-phone>"
},
"custom_data": {
"value": 59.99,
"currency": "USD"
}
}The event_id must be identical across both channels for the same event. This is the mechanism that prevents double-counting.
Step 4: Hash your customer data
CAPI improves match rates by sending customer information (email, phone, name), but this data must be hashed with SHA-256 before it leaves your server. Never send raw email addresses or phone numbers. Normalize first — lowercase and trim the email, strip formatting from the phone number — then hash. Most server-side GTM CAPI tags handle hashing automatically; if you build a direct integration, this is on you.
Step 5: Include strong match parameters
The more identifying signals you send (hashed), the better Meta can attribute the conversion. High-value parameters include hashed email, hashed phone, and the Meta browser identifiers fbp (from the _fbp cookie) and fbc (from the _fbc cookie, derived from the fbclid click ID). Passing fbp and fbc from the browser to your server dramatically improves match quality.
Step 6: Test in Events Manager
Open Events Manager → Test Events and complete a real action on your site. You should see the event arrive from both "Browser" and "Server". Then check the event's details:
- The deduplication status should confirm the browser and server events were matched
- The Event Match Quality score reflects how many identifying parameters you're sending — aim to improve it with more hashed match keys
If you see two separate conversions instead of one deduplicated event, your event_id values don't match between Pixel and CAPI — go back to Step 3.

Anatomy of a Conversions API request
Whichever method you use, under the hood every server event is an HTTP POST to the Graph API:
POST https://graph.facebook.com/v21.0/{PIXEL_ID}/events?access_token={ACCESS_TOKEN}
Content-Type: application/jsonThe body carries a data array of events (up to 1,000 events per request), plus an optional test_event_code while testing:
{
"data": [
{
"event_name": "Purchase",
"event_time": 1735689600,
"event_id": "a1b2c3-shared-with-the-pixel",
"action_source": "website",
"event_source_url": "https://example.com/checkout/success",
"user_data": {
"em": ["<sha256 of normalized email>"],
"ph": ["<sha256 of normalized phone>"],
"client_ip_address": "203.0.113.1",
"client_user_agent": "Mozilla/5.0 ...",
"fbp": "fb.1.1735680000.1234567890",
"fbc": "fb.1.1735680000.PAxxxxxx"
},
"custom_data": {
"value": 59.99,
"currency": "USD",
"content_ids": ["SKU_12345"],
"content_type": "product",
"order_id": "T_10042"
}
}
],
"test_event_code": "TEST12345"
}Server-event parameters
| Parameter | Required? | What it is |
|---|---|---|
event_name | Required | A standard event (Purchase, Lead, AddToCart, CompleteRegistration…) or a custom name. |
event_time | Required | Unix timestamp of the action. Must be within the last 7 days or it's rejected. |
action_source | Required | Where it happened: website, app, phone_call, chat, email, physical_store, system_generated, other. |
user_data | Required | Customer identifiers used to match the event to a person — at least one. See below. |
event_id | Recommended | Your dedup key — must equal the Pixel's eventID for the same action. |
event_source_url | Recommended | The page URL where a web event occurred. |
custom_data | Recommended | Event details: value, currency, content_ids, contents, content_type, order_id. |
data_processing_options | Optional | Consent / Limited Data Use signals (e.g. CCPA). |
Customer-data (user_data) fields
The more of these you send, the better Meta matches the event — which lifts Event Match Quality. Identity fields are SHA-256 hashed; the technical identifiers are sent in the clear.
| Field | Meaning | Hashed? |
|---|---|---|
em | Yes | |
ph | Phone (digits + country code, no +) | Yes |
fn / ln | First / last name | Yes |
ct / st / zp / country | City / state / zip / country | Yes |
external_id | Your own user/customer ID | Yes |
fbp | Browser _fbp cookie value | No |
fbc | From the fbclid click ID (_fbc cookie) | No |
client_ip_address / client_user_agent | Request IP + user agent | No |
Hashing and normalizing customer data
Meta requires PII to be SHA-256 hashed before it leaves your server — but you must normalize first, or your hash won't match Meta's and the identifier is wasted. The order is always: normalize → hash → send.
| Field | Normalize to | Example |
|---|---|---|
| lowercase, trim whitespace | Jane@Site.com → jane@site.com | |
| Phone | digits only, country code, no + or symbols | +1 (415) 555-0172 → 14155550172 |
| First / last name | lowercase, trim, strip punctuation | O'Brien → obrien |
| Zip | lowercase, first 5 digits (US) | 94107-1234 → 94107 |
| State / country | lowercase 2-letter code | California → ca |
Never hash fbp, fbc, client_ip_address, or client_user_agent — Meta needs those raw. Most server-side GTM CAPI tags and partner integrations normalize and hash for you; if you build a direct integration, this is on you.
Standard events, batching, and errors
- Use standard event names where possible:
Purchase,Lead,AddToCart,InitiateCheckout,CompleteRegistration,ViewContent,Search,Subscribe. Meta maps these to optimization goals and reporting automatically; custom names don't get that treatment. - Batch up to 1,000 events in one
dataarray to cut request volume — handy for offline/CRM uploads. - Handle errors. The Graph API returns descriptive errors (invalid token, malformed
user_data, event older than 7 days, badcurrency). After events start flowing, Events Manager → Diagnostics flags issues like unhashed data or missing parameters so you can fix them.
Using the Conversions API across the funnel
Better signal isn't just about counting purchases — it strengthens every stage of your Meta advertising:
- Prospecting (top of funnel): cleaner event data means Meta's algorithm learns faster who converts, so cold-audience delivery improves and your cost per result drops as the pixel "warms up" on real signal instead of a blocked, partial one.
- Optimization (mid funnel): Meta optimizes toward the conversions it can see. Recovering the 10–30% of events lost client-side gives the delivery system more conversion examples to optimize on, which is often the difference between an ad set exiting the learning phase or stalling.
- Re-engagement (bottom of funnel): server-side events feed more complete retargeting and lookalike audiences. Abandoners and past purchasers that ITP would have dropped stay in your audiences, so remarketing reaches the people most likely to convert.
Best practices for the Conversions API
- Send both Pixel and CAPI for every key event — redundancy is the whole point. Server-only loses the browser's rich signals; browser-only loses the blocked ones.
- Maximize Event Match Quality (EMQ). Send as many hashed match keys as you legitimately have — email, phone, name, city, and the
fbp/fbcidentifiers. Aim for an EMQ of 6.0+ in Events Manager. - Send events in near-real-time. Meta rewards fresh events; server events older than 7 days are rejected outright.
- Include
fbcfrom the click. Capture thefbclidURL parameter on landing and persist it — it's the strongest attribution signal you can pass server-side. - Use recommended/standard event names (Purchase, Lead, CompleteRegistration) so Meta maps them to the right optimization goals.
- Monitor deduplication weekly in Events Manager — a drift in event IDs silently reintroduces double-counting.
Security and privacy
The Conversions API sends customer data to Meta, so treat it as a privacy-sensitive integration:
- Always SHA-256 hash PII (email, phone, name) before it leaves your server. Normalize first — lowercase and trim email, strip formatting from phone. Raw PII is a policy violation and gets rejected.
- Keep your access token server-side only. It authenticates all your events — treat it like a password, never expose it in the browser.
- Respect consent. Only send events for users who have consented under your region's rules (GDPR/CCPA). Wire CAPI into your consent management platform so non-consented events are suppressed at the source.
- Disclose the data flow in your privacy policy — that customer data is shared with Meta as a processor.
Common mistakes to avoid
- Mismatched event IDs → double-counted conversions. The Pixel and CAPI event IDs must be identical.
- Sending unhashed PII → policy violation and rejected events. Always SHA-256 customer data.
- Forgetting fbp/fbc → poor match quality and weak attribution.
- Only sending server events → you lose the browser signal and deduplication safety net. Send both.
- Wrong event_time → events older than 7 days are rejected; use the actual Unix timestamp of the action.