Sync Events to the Meta Conversions API

Sync Events to the Meta Conversions API

Sync customer events to the Meta Conversions API from your CRM or database. Field mapping, SHA-256 hashing, event_id deduplication. Warehouse optional.

No credit card required

Free 100k syncs every month

The Meta Pixel was the obvious way to track conversions until iOS 14, ad blockers, and the cookie deprecation roadmap quietly broke it. Your Event Match Quality score has been sliding for two years and your retargeting audiences are smaller than they should be. The Meta Conversions API (also called the Facebook Conversions API or Facebook CAPI) is the fix, but every published guide assumes you already operate a Snowflake or BigQuery warehouse plus a reverse-ETL tool. Most teams don't, so the project sits on the backlog.

This Meta CAPI setup guide shows the direct path: sync conversion events from your CRM, Postgres, Stripe, or Shopify straight to the Meta Conversions API. Warehouse optional, no SDK, no dbt models. Setup takes about 30 minutes.

What events to send to the Meta Conversions API

Meta accepts a fixed set of standard events plus any custom event you define. Start with the events your ad campaigns optimize toward, not every event you can capture. Five carry most of the weight:

  • Purchase: completed payment. Source from Stripe charges, Shopify orders, or a subscription_payments table in Postgres.

  • Lead: qualified form fill or sales-accepted lead. Source from HubSpot or Salesforce when lifecyclestage = "lead".

  • AddToCart: cart action on your storefront. Source from Shopify or a cart events table.

  • CompleteRegistration: signup or trial start. Source from your app database users table when created_at lands in the last sync window.

  • InitiateCheckout: checkout step before payment. Source from Shopify or your storefront.

Custom events fill the gaps. If you optimize toward "trial-to-paid conversion" or "demo booked," create a custom event with that name in Meta Events Manager and map it from the matching CRM or database state. Meta's optimization treats custom events the same as standard ones once they have enough volume.

Event

Common source

Required fields

Purchase

Stripe, Shopify, Postgres

value, currency, em, fbp

Lead

HubSpot, Salesforce

em, ph, external_id

AddToCart

Shopify, storefront DB

content_ids, value, currency

CompleteRegistration

App database, Auth provider

em, external_id

InitiateCheckout

Shopify, checkout service

content_ids, value, currency

How the Meta Conversions API replaces pixel-only tracking

Pixel-only setups still work for a fraction of your traffic. Safari has restricted third-party cookies for years. Apple's App Tracking Transparency cut iOS attribution to opt-in users, roughly 25%. Chrome's cookie deprecation will close the remaining gap.

The Conversions API is server-to-server. Your backend posts the event directly to Meta with whatever first-party identifiers you have on the customer record: hashed email, hashed phone, the fbc click ID, the fbp browser ID, the customer's external_id. Meta resolves each event to a user profile using whichever identifiers match. More identifiers, higher match quality, better optimization.

Two implementation details decide whether the Conversions API actually helps:

  1. First-party identifier coverage. Email and phone are the strongest signals. If your CRM has them on every contact, your match quality lands above 7. If half your records are missing email, match quality stalls in the 4-5 range and Meta's optimizer underperforms.

  2. Pixel deduplication. Sending the same purchase from both the Pixel and the Conversions API doubles your reported conversions unless event_id matches across both. Meta dedupes on the event_id + event_name pair.

We recommend running both. The Pixel catches browser context the server doesn't see (referrer, page URL, fbc cookie). The Conversions API catches everything the browser missed. Together, with proper deduplication, they push match quality higher than either alone.

How to sync CRM or database events to the Meta Conversions API

Skip the warehouse. The CRM-to-Meta and database-to-Meta paths are direct.

1. Pick your source. For B2B Lead events, that's your CRM (HubSpot, Salesforce, Pipedrive, Attio). For Purchase events, that's your billing tool (Stripe) or storefront (Shopify). For app-side events like CompleteRegistration, that's your application database (Postgres, MySQL).

2. Connect Meta Ads as a destination. Authenticate with a Meta System User access token. Pick the Pixel ID for the ad account you want events attributed to. The same Oneprofile destination can serve multiple Pixel IDs if you run separate accounts per region or product.

3. Map your event payload. Each event needs event_name, event_time (Unix timestamp), action_source (website, app, email, chat, system_generated, physical_store, business_messaging, other), and user_data populated with as many identifiers as you have. Source-specific notes:

  • Stripe to Meta Purchase: Map charge.amount to value (divide by 100 for dollars), charge.currency to currency, customer.email to em (hashed), charge.created to event_time, charge.id to event_id. Filter on charge.status = "succeeded".

  • HubSpot to Meta Lead: Map contact.email to em (hashed), contact.phone to ph (hashed), contact.id to external_id and event_id, contact.createdate to event_time. Filter on lifecyclestage = "lead" or your qualified stage.

  • Postgres to Meta CompleteRegistration: Map users.email to em (hashed), users.id to external_id and event_id, users.created_at to event_time. Use a delta sync so only new rows since the last run get sent.

  • Shopify to Meta Purchase: Map order.total_price to value, order.currency to currency, order.email to em (hashed), order.id to event_id, line item product IDs to content_ids.

4. Set the schedule. Use real-time sync for Stripe and Shopify so purchases reach Meta within seconds of the charge. Use a 15-minute schedule for CRM sources where leads change state in batches. Anything slower than hourly hurts optimization quality because Meta favors fresh events when training the bidder.

Field mapping and PII hashing for the Meta Conversions API

Meta requires SHA-256 hashing on every personal identifier before it leaves your server. The hash must be lowercase hex, applied to the lowercased and trimmed value (no whitespace, no formatting). Phone numbers must be E.164 without the leading plus.

Field

Source value

Hashed?

Notes

em

Email

Yes (SHA-256)

Lowercase, trim whitespace

ph

Phone

Yes (SHA-256)

Digits only, E.164 minus "+"

fn

First name

Yes (SHA-256)

Lowercase, no punctuation

ln

Last name

Yes (SHA-256)

Lowercase, no punctuation

external_id

Your customer ID

Yes (SHA-256)

Stable across the customer

fbc

Click ID cookie

No

Format: fb.1.timestamp.fbclid

fbp

Browser ID cookie

No

Format: fb.1.timestamp.random

client_ip_address

Server-captured IP

No

Hashed by Meta on receipt

client_user_agent

Browser user agent

No

Hashed by Meta on receipt

In Oneprofile, toggle SHA-256 on each PII field in the mapping interface. The hash runs in the destination layer so the source value never leaves your account in plaintext. If your source already stores hashed emails, set the field to "pass through unhashed" so Oneprofile doesn't double-hash.

The fbc and fbp cookies are the trickiest part. They live in the browser, set by the Meta Pixel. To include them in server-side events, your frontend has to read them and pass them to your backend on form submit or purchase confirmation. Store them on the contact, lead, or order record so they flow through with the rest of the payload. Without fbc, Meta can't match the conversion back to the original ad click.

Event deduplication: Meta Pixel vs Conversions API using event_id

Run the Pixel and the Conversions API together or you leave match quality on the table. The catch: both will report the same purchase unless you tell Meta they're the same event.

Meta dedupes on the event_id + event_name pair. If both sources send a Purchase with event_id = "order_8745", Meta keeps one copy and discards the duplicate. If event_id is missing or different, Meta counts both.

Three rules make this work:

  • Use the source record ID as event_id. For purchases, the order or charge ID. For leads, the CRM contact ID. For registrations, the user ID. Stable, unique, and available on both client and server.

  • Set the same event_id on the Pixel. Your client-side Pixel fire needs eventID in the parameters object. Pull it from a hidden field, a server-rendered variable, or the response of the action that created the record.

  • Send the Pixel event first when possible. The browser fires immediately on page load; the server fires when the sync runs. With a 15-minute schedule, the Pixel reliably arrives first. With real-time sync, Meta still dedupes but the order can flip.

Verify deduplication in Events Manager > Overview. Look at the "Server" and "Browser" columns. If both show similar daily counts but the deduplicated total is roughly the higher of the two, deduplication is working.

Scheduling, testing, and monitoring Meta Conversions API sync

The Conversions API silently accepts requests with mismatched fields. The events arrive, but match quality stays low because Meta couldn't resolve the user. Test before you trust the dashboard.

Test Events. Meta Events Manager has a Test Events tab with a unique test code. Add test_event_code to your payload (Oneprofile has a per-sync test mode) and confirm the event appears within 60 seconds. Watch the Test Events panel for warnings: missing required fields, malformed timestamps, unhashed PII.

Diagnostics tab. After events flow to production for a few hours, check Events Manager > Diagnostics. Meta surfaces issues like "Event match quality below threshold" or "Duplicate events detected" with concrete counts. Fix what you can, ignore what's expected (some pixel-only Cookie warnings are unavoidable).

Event Match Quality (EMQ) score. EMQ runs from 0 to 10 per event type. Above 6.0 is solid; above 8.0 is excellent. The fastest way to raise EMQ is to add more identifiers to the payload. Phone often moves the score by a full point if you weren't sending it before.

Failed events in Oneprofile. When the Conversions API rejects an event (expired token, malformed payload, rate limit), the record gets captured for review instead of disappearing. Common rejections:

  • Access token expired. System User tokens can be set to never expire; use that.

  • event_time more than 7 days old. Meta rejects stale events. Filter your initial backfill to the last 7 days.

  • Missing action_source. Default it to "website" or "system_generated" depending on origin.

Extending to other platforms. The same source feeds Google Ads, LinkedIn, and TikTok server-side APIs. Add a destination for each, map the platform-specific click ID (gclid, li_fat_id, ttclid) and the same hashed identifiers, and you have offline conversion tracking across every paid channel without a second integration project.

The hardest part of the Meta Conversions API isn't the API. It's getting your conversion events out of the systems they live in without standing up a warehouse first.

Ready to get started?

No credit card required

Free 100k syncs every month

Ready to get started?

No credit card required

Free 100k syncs every month

Ready to get started?

No credit card required

Free 100k syncs every month

Do I need a data warehouse to use the Meta Conversions API?

What's the difference between the Meta Pixel and the Conversions API?

Which PII fields does the Meta Conversions API require to be hashed?

How does event_id deduplication work between the Meta Pixel and Conversions API?

How fresh do events need to be when sent to the Meta Conversions API?

Can the same setup push events to Google, LinkedIn, and TikTok Conversions APIs?