> For the complete documentation index, see [llms.txt](https://docs.chord.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.chord.co/activate/event-streaming/destinations/advertising/meta/meta-conversions-api.md).

# Meta Conversions API

The **Meta Conversions API** (also known as **Meta CAPI**, formerly Facebook Conversions API) is a server-side integration that sends event data directly from Chord to Meta's servers. Unlike the Meta Pixel, which runs in the browser, the Conversions API sends events from the server, so ad blockers and browser tracking restrictions don't affect them.

Meta recommends using the Conversions API alongside the [Meta Pixel](/activate/event-streaming/destinations/advertising/meta/meta-pixel.md) for maximum data coverage. When both are configured, Meta automatically deduplicates events using the `event_id` field. See [Meta](/activate/event-streaming/destinations/advertising/meta.md) for why to use both.

## Getting started

You will need:

* A Meta Pixel ID, found in Meta Events Manager under your pixel settings.
* An access token for a system user, generated in Meta Business Settings. See [Meta's documentation](https://developers.facebook.com/docs/marketing-api/conversions-api/get-started) for how to generate a server-side access token.

## Settings

* **Destination Name** (required): a name to tell this destination apart.
* **Pixel ID** (required): your Meta Pixel ID.
* **Access Token** (required): the system user access token for your pixel.
* **Action Source** (required): where the events happen. Defaults to Website. The other options are App, Phone Call, Chat, Physical Store, System Generated and Other.
* **Events** (optional): which events reach Meta. See [Events setting](#events-setting).
* **Product Content ID Field** (required): which product field to use as the content ID (`sku`, `variant_id` or `product_id`). Defaults to `sku`. It must match the content IDs of your catalog in Meta Business Suite, and it is used in the `contents.[].id` field.
* **Phone Field Name** (optional): the name of the trait that holds the phone number, in E.164 or international format. Leave it empty to skip phone matching.
* **Test Event Code** (optional): the code from the **Test Events** tab in Meta Events Manager. While it is set, events show up in Test Events. Clear it before you go live. See [Testing and validation](#testing-and-validation).
* **Consent Requirements** (optional): the consent categories a visitor must accept before Chord sends data to this destination. See [Consent](/activate/event-streaming/consent.md).

## Connect

Add **Facebook Conversions API** from the destination catalog, using the settings above. See [Connect a destination](/activate/event-streaming/connect-a-destination.md) for the full steps.

## Events setting

The **Events** field controls which events reach Meta:

* **Empty** (default): sends all events except page and screen events.
* `*`: sends everything, including page events.
* **A comma-separated list**: sends only the listed event names or types, for example `Order Completed, Subscription Created`.

An event that is not in the list is skipped. If an event you expect is missing in Meta, check this field first.

## Event mapping

| Chord event                                                                 | Meta event                                                                   | Notes |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----- |
| Page                                                                        | `PageView`                                                                   |       |
| [Checkout Started](/collect-data/tracking-plan/checkout-started.md)         | `InitiateCheckout`                                                           |       |
| [Order Completed](/collect-data/tracking-plan/order-completed.md)           | `Purchase`                                                                   |       |
| [Product Added](/collect-data/tracking-plan/product-added.md)               | `AddToCart`                                                                  |       |
| [Product Viewed](/collect-data/tracking-plan/product-viewed.md)             | `ViewContent`                                                                |       |
| [Products Searched](/collect-data/tracking-plan/products-searched.md)       | `Search`                                                                     |       |
| [Product Clicked](/collect-data/tracking-plan/product-clicked.md)           | `ViewContent`                                                                |       |
| [Subscription Created](/collect-data/tracking-plan/subscription-created.md) | `Subscribe`                                                                  |       |
| [Payment Info Entered](/collect-data/tracking-plan/payment-info-entered.md) | `AddPaymentInfo`                                                             |       |
| [Signed Up](/collect-data/tracking-plan/signed-up.md)                       | `CompleteRegistration`                                                       |       |
| [Email Captured](/collect-data/tracking-plan/email-captured.md)             | `Lead`, or the custom event `SMSSignup` when `properties.lead_type` is `sms` |       |
| *(other track events)*                                                      | Original event name passed through                                           |       |

Page, track, and screen events are forwarded. Identify events are ignored.

## Common event fields

These fields are included on every event sent to Meta.

| Chord source (priority order)                                                                                    | Meta field         | Notes                                                                                                              |
| ---------------------------------------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------ |
| *(mapped from event — see table above)*                                                                          | `event_name`       |                                                                                                                    |
| `timestamp`                                                                                                      | `event_time`       | Converted to Unix seconds                                                                                          |
| `properties.order_id` for Order Completed (Shopify GraphQL IDs reduced to the numeric ID); `messageId` otherwise | `event_id`         | Used for deduplication with the browser pixel. Falls back to `messageId` when an Order Completed has no `order_id` |
| Configured action source                                                                                         | `action_source`    | Defaults to `website`                                                                                              |
| `context.page.url`                                                                                               | `event_source_url` |                                                                                                                    |

## Deduplication

Order Completed uses the order ID as the event ID, so it matches the same order sent by the [Meta Pixel](/activate/event-streaming/destinations/advertising/meta/meta-pixel.md). Every other event uses the Chord message ID. See [Meta](/activate/event-streaming/destinations/advertising/meta.md#how-they-deduplicate) for how the two versions deduplicate.

## User data

All personally identifiable information (PII) is SHA256-hashed before being sent to Meta, in compliance with Meta's data processing requirements.

| Chord source (priority order)                                                                                                            | Meta field          | Notes                                                                                                  |
| ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------ |
| `properties.email` > `context.traits.email`                                                                                              | `em` (email)        | Lowercased and SHA256-hashed                                                                           |
| `properties.{phoneFieldName}` > `context.traits.{phoneFieldName}`                                                                        | `ph` (phone)        | Non-digits removed, leading zeros stripped, SHA256-hashed. Only sent if phone field name is configured |
| `properties.first_name` > first word of `context.traits.name`                                                                            | `fn` (first name)   | SHA256-hashed                                                                                          |
| `properties.last_name` > second word of `context.traits.name`                                                                            | `ln` (last name)    | SHA256-hashed                                                                                          |
| `properties.shipping_zipcode` > `context.traits.address.zipcode` > `context.traits.address.postalCode` > postal code from IP geolocation | `zp` (zip code)     | SHA256-hashed                                                                                          |
| `properties.shipping_city` > `context.traits.address.city` > city from IP geolocation                                                    | `ct` (city)         | SHA256-hashed                                                                                          |
| `properties.shipping_country` > `context.traits.address.country` > country code from IP geolocation                                      | `country`           | SHA256-hashed                                                                                          |
| *(IP geolocation)*                                                                                                                       | `st` (state)        | SHA256-hashed region code                                                                              |
| `userId`, `anonymousId`                                                                                                                  | `external_id`       | Array of SHA256-hashed values                                                                          |
| `context.ip`                                                                                                                             | `client_ip_address` | Not hashed                                                                                             |
| `context.userAgent`                                                                                                                      | `client_user_agent` | Not hashed                                                                                             |
| `properties.fbc` > `context.clientIds.fbc`                                                                                               | `fbc`               | Meta click ID                                                                                          |
| `properties.fbp` > `context.clientIds.fbp`                                                                                               | `fbp`               | Meta browser ID                                                                                        |

## Custom data (track events)

Track events include a `custom_data` block with the following structured schema fields. Any `properties.*` destination mappings you configure in Chord that target other fields are forwarded as custom properties alongside the structured fields.

| Chord source (priority order)                                                                                     | Meta field         | Notes                                                          |
| ----------------------------------------------------------------------------------------------------------------- | ------------------ | -------------------------------------------------------------- |
| `properties.value` > `properties.total` > `properties.price`, then the sum of each product's price times quantity | `value`            | String; defaults to `"0"`                                      |
| `properties.currency` > `properties.meta.i18n.currency`                                                           | `currency`         | Defaults to `USD`                                              |
| Each product's **Product Content ID Field**, then `sku` > `product_id` > `variant_id`                             | `content_ids`      | Array of product IDs. Read from `properties.products`          |
| Array of `{ id, quantity, item_price }` per product                                                               | `contents`         | `quantity` defaults to `1`                                     |
| *(derived)*                                                                                                       | `content_type`     | `"product"` for single product, `"product_group"` for multiple |
| First product's `name`                                                                                            | `content_name`     |                                                                |
| First product's `category`                                                                                        | `content_category` |                                                                |
| Count of products                                                                                                 | `num_items`        |                                                                |

When no `properties.products` array is present but `properties.sku` exists, `content_ids` holds that SKU alone, `num_items` is `1`, and no other product fields are sent.

## App data (App action source only)

When **Action Source** is set to `app`, an additional `app_data` block is included in the event payload. This is populated from `context.app`, `context.os`, `context.device`, and `context.screen`.

| Chord source (priority order) | Meta field                     | Notes                                                                             |
| ----------------------------- | ------------------------------ | --------------------------------------------------------------------------------- |
| *(hardcoded)* `0`             | `advertiser_tracking_enabled`  |                                                                                   |
| *(hardcoded)* `0`             | `application_tracking_enabled` |                                                                                   |
| `context.os.name`             | `extinfo[0]`                   | `"i2"` for iOS or macOS, `"a2"` for any other system                              |
| `context.app.namespace`       | `extinfo[1]`                   | App bundle ID                                                                     |
| `context.app.version`         | `extinfo[2]`                   | App version string                                                                |
| `context.app.version`         | `extinfo[3]`                   | Same value as `extinfo[2]`                                                        |
| `context.os.version`          | `extinfo[4]`                   | OS version. Falls back to the OS version parsed from the user agent, then `"1.0"` |
| `context.device.model`        | `extinfo[5]`                   | Model name of the device                                                          |
| `context.locale`              | `extinfo[6]`                   | Device locale                                                                     |
| `context.screen.width`        | `extinfo[9]`                   | Screen width in pixels                                                            |
| `context.screen.height`       | `extinfo[10]`                  | Screen height in pixels                                                           |
| `context.screen.density`      | `extinfo[11]`                  | Screen density                                                                    |
| `context.timezone`            | `extinfo[15]`                  | Device timezone                                                                   |

## Custom property forwarding

Configure destination mappings in Chord with `properties.*` destination paths to forward additional event properties into `custom_data`. Only explicitly-configured non-schema fields are forwarded — nothing flows through automatically.

**How to configure:**

1. In Chord, open the destination's connection and find **Property Mappings**. See [Property mappings](/activate/event-streaming/property-mappings.md#add-a-mapping) for the steps.
2. Add a mapping with source path `properties.loyalty_tier` and destination path `properties.loyalty_tier`.
3. On the next event, `custom_data.loyalty_tier` will appear in the payload sent to Meta.

**What is excluded:**

* Fields Chord already computes (for example `currency`, `value`, `content_ids`, `contents` and `products`)
* PII fields (`email`, `phone`, `first_name`, `last_name`) — these are handled via `user_data` with SHA-256 hashing

Some `custom_data` fields are locked, because Meta rejects the request or misreads the event if they are overwritten: `value`, `currency`, `content_ids`, `contents`, `products`, `shipping_zipcode`, `shipping_city`, `shipping_country`, `fbc`, and `fbp`. A mapping whose destination path targets one of these (e.g. `properties.foo → properties.value`) is ignored, and Chord logs a warning. The other schema fields — `content_type`, `content_name`, `content_category`, and `num_items` — can be overridden by a mapping.

To change a locked field, map into the Chord property it is computed from instead. For example, to send a different conversion value, map your source property to `properties.value`, which feeds `value` first.

## Testing and validation

After connecting the destination:

1. Use the **Diagnostics** tab in Meta Events Manager to confirm events are being received
2. Use the **Test Events** tab to validate event payloads in real time. Copy the test code from that tab into the destination's **Test Event Code** setting, and clear it once you're done
3. Verify match rates — higher rates indicate user identifiers are being sent correctly
4. Confirm revenue values and order counts align with your expectations
5. Check the Meta developer console for any API errors or authentication issues

If you are running both CAPI and the Meta Pixel, the `event_id` values must match across both to prevent duplicate counting. Chord sets them for you. See [Deduplication](#deduplication) above.

If events still don't show up or look wrong, see the [Meta Conversions API diagnostic guide](/activate/event-streaming/destinations/advertising/meta/meta-conversions-api/diagnostic-guide.md).

## Best practices

* **Use CAPI alongside the Meta Pixel** — provides redundancy and better coverage
* **Enable Automatic Advanced Matching** — increases match quality without compromising privacy
* **Send rich user data** — the more hashed identifiers (email, phone, name, address) you provide, the higher your match rates

## Expected results

After enabling CAPI, you should see:

* **Higher match rates** in Meta Events Manager, as server-side events are not blocked by browsers
* **Extended cookie lifespan** for attribution, since `fbc`/`fbp` identifiers are sent server-side

## Property mappings

Use custom property mappings if the default field resolution does not match your data model:

| Destination Path                  | Description                 |
| --------------------------------- | --------------------------- |
| `properties.email`                | Email for user matching     |
| `properties.total`                | Conversion value            |
| `properties.currency`             | Currency code (e.g., `USD`) |
| `properties.products.[].sku`      | Product content IDs         |
| `properties.products.[].price`    | Per-item price              |
| `properties.products.[].quantity` | Per-item quantity           |

Any destination path of the form `properties.<field>` that does not match a schema field listed above is treated as a custom property and promoted into `custom_data`. See [custom property forwarding](#custom-property-forwarding).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.chord.co/activate/event-streaming/destinations/advertising/meta/meta-conversions-api.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
