IntegrationsAdvertisingMeta Conversions API (CAPI)

Meta Conversions API (CAPI)

Datafly Signal delivers events to Meta (Facebook) server-to-server using the Conversions API (CAPI). This provides reliable event delivery that is not affected by ad blockers or browser tracking prevention.

Prerequisites

Before configuring Meta CAPI in Signal, you need a Meta Business account with an active Pixel and a system user access token. Follow the steps below to set everything up.

Step 1: Create a Meta Business Account

If you don’t already have one:

  1. Go to business.facebook.com and click Create Account.
  2. Enter your business name, your name, and business email.
  3. Complete the setup wizard.

Step 2: Create or Find Your Meta Pixel

  1. In Meta Business Suite, go to Events Manager (left sidebar, under Data Sources).
  2. If you already have a Pixel, click on it and note the Pixel ID (a numeric ID like 1234567890).
  3. To create a new Pixel:
    • Click Connect Data Sources > Web > Connect.
    • Name your Pixel (e.g. “My Website Pixel”) and enter your website URL.
    • Select Conversions API as the connection method.
    • Click Create Pixel. Note the Pixel ID.

Step 3: Create a System User

System users are the recommended way to generate long-lived access tokens for server-to-server integrations. Personal access tokens expire and should not be used in production.

  1. Go to Business Settings > Users > System Users.
  2. Click Add to create a new system user.
  3. Give it a name (e.g. “Datafly Signal”) and set the role to Admin.
  4. Click Create System User.

Step 4: Assign Permissions to the System User

  1. On the system user you just created, click Add Assets.
  2. Select Pixels from the asset type list.
  3. Find your Pixel and toggle on Manage Pixel permission.
  4. Click Save Changes.

Step 5: Generate an Access Token

  1. Still on the system user page, click Generate New Token.
  2. Select the following permissions:
    • ads_management
    • business_management
  3. Click Generate Token.
  4. Copy the token immediately — it will only be shown once.
⚠️

Store this token securely. If you lose it, you will need to generate a new one. The token does not expire unless revoked.

Domain verification improves event attribution and is required for some features:

  1. Go to Business Settings > Brand Safety > Domains.
  2. Click Add and enter your domain.
  3. Choose a verification method (DNS TXT record is recommended).
  4. Complete verification.

Configure in Signal

Now that you have your Pixel ID and access token, configure the integration in Signal.

Configuration Fields

FieldRequiredDescription
pixel_idYesYour Meta Pixel ID (numeric). Found in Meta Events Manager.
access_tokenYesSystem user access token with ads_management permission.
test_event_codeNoTest event code for validation. Events sent with this code appear in the Events Manager Test Events tab but do not affect reporting.

Management UI Setup

  1. Go to Integrations > Add Integration > Meta Conversions API.
  2. Choose a variant:
    • Retail — full e-commerce funnel (product views, cart, checkout, purchase, refunds)
    • Travel — search, booking, and cancellation events
    • B2B / SaaS — sign-up, trial, subscription, and lead events
    • Default — standard page view and conversion tracking
  3. Enter your pixel_id and access_token.
  4. Select consent categories (typically advertising or marketing).
  5. Click Save.

Management API Setup

curl -X POST http://localhost:8084/v1/admin/integrations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_id": "src_abc123",
    "vendor": "meta_capi",
    "name": "Meta CAPI Production",
    "enabled": true,
    "config": {
      "pixel_id": "1234567890",
      "access_token": "your_access_token"
    },
    "consent_categories": ["advertising"]
  }'

API Endpoint

POST https://graph.facebook.com/v25.0/{pixel_id}/events?access_token={access_token}

Events are sent as a JSON array in the data field.

Identity Signals

Meta uses multiple identity signals to match server events to user profiles. The more signals you provide, the higher your Event Match Quality (EMQ) score.

Automatic Signals

These are sent automatically by Signal — no configuration needed:

SignalFieldDescription
fbpuser_data.fbpFacebook browser ID. Signal self-generates this in the format fb.1.{timestamp}.{random} and stores it as a first-party cookie.
fbcuser_data.fbcFacebook click ID. Automatically extracted from the fbclid URL parameter and formatted as fb.1.{timestamp}.{fbclid}.
external_iduser_data.external_idSet to the Datafly anonymous_id (hashed). Provides a stable cross-session identifier.
client_ip_addressuser_data.client_ip_addressVisitor’s IP address, forwarded from the original request.
client_user_agentuser_data.client_user_agentVisitor’s User-Agent string, forwarded from the original request.

User-Provided Signals (Hashed)

When a user is identified via _df.identify() with traits, the following fields are SHA-256 hashed before sending to Meta:

SignalHashingDescription
em (email)SHA-256, lowercase, trimmedUser’s email address
ph (phone)SHA-256, digits only, with country codeUser’s phone number
fn (first name)SHA-256, lowercase, trimmedFirst name
ln (last name)SHA-256, lowercase, trimmedLast name
ct (city)SHA-256, lowercase, no spacesCity
st (state)SHA-256, lowercase, 2-letter codeState/region
zp (zip)SHA-256, trimmedPostal/zip code
countrySHA-256, lowercase, 2-letter ISO codeCountry

All PII hashing is performed server-side by the Delivery Worker before the data leaves your infrastructure. Raw PII is never sent to Meta.

How to Send User Data

Call _df.identify() when a user logs in, registers, or submits a form:

_df.identify("user-123", {
  email: "[email protected]",
  phone: "+44 7700 900123",
  firstName: "Jane",
  lastName: "Doe",
  city: "London",
  country: "GB"
});

Signal normalises and hashes these fields automatically before sending to Meta.

Event Mapping

Datafly EventMeta EventNotes
page (page view)PageViewSent for every page view
Order Completed / Product PurchasedPurchaseRequires value, currency
Product AddedAddToCartIncludes content_ids, content_type
Checkout StartedInitiateCheckoutIncludes value, currency, num_items
Product ViewedViewContentIncludes content_ids, content_type
Lead GeneratedLeadLead form submission
Signed UpCompleteRegistrationUser registration
Products SearchedSearchIncludes search_string
Product Added to WishlistAddToWishlistIncludes content_ids
Custom eventsPassed throughSent as custom event name

Example: Purchase Event

Datafly.js call:

_df.track("Order Completed", {
  order_id: "ORD-001",
  total: 129.99,
  currency: "USD",
  products: [
    { product_id: "SKU-A", name: "Widget", price: 49.99, quantity: 2 },
    { product_id: "SKU-B", name: "Gadget", price: 30.01, quantity: 1 }
  ]
});

Meta CAPI payload sent by Signal:

{
  "data": [
    {
      "event_name": "Purchase",
      "event_time": 1706540000,
      "event_id": "evt_abc123def456",
      "event_source_url": "https://example.com/checkout/confirmation",
      "action_source": "website",  // or "app" for mobile SDK events
      "user_data": {
        "client_ip_address": "203.0.113.50",
        "client_user_agent": "Mozilla/5.0 ...",
        "fbp": "fb.1.1706540000.1234567890",
        "fbc": "fb.1.1706539000.AbCdEfGhIjKl",
        "external_id": "a1b2c3d4e5f6..."
      },
      "custom_data": {
        "currency": "USD",
        "value": 129.99,
        "order_id": "ORD-001",
        "content_ids": ["SKU-A", "SKU-B"],
        "content_type": "product",
        "contents": [
          { "id": "SKU-A", "quantity": 2, "item_price": 49.99 },
          { "id": "SKU-B", "quantity": 1, "item_price": 30.01 }
        ],
        "num_items": 3
      }
    }
  ]
}

Event Match Quality (EMQ)

Event Match Quality is Meta’s score (out of 10) indicating how well your server events can be matched to Meta user profiles. A higher EMQ means better ad optimisation and attribution.

How to Improve EMQ

  1. Send fbp and fbc: Signal handles this automatically. The fbp cookie is self-generated and fbc is extracted from the fbclid URL parameter.
  2. Include user data: Pass email and phone via _df.identify() when users log in or submit forms. These are hashed before delivery.
  3. Send IP and User-Agent: Signal forwards these automatically from the original browser request.
  4. Use external_id: Enabled by default — the hashed anonymous_id is sent as external_id.

A typical Signal integration achieves an EMQ of 6-8 with automatic signals alone, and 8-10 when user-provided data (email, phone) is available.

Testing Your Integration

Step 1: Use Test Event Code

  1. In Meta Events Manager, go to your Pixel > Test Events tab.
  2. Copy the test event code (e.g. TEST12345).
  3. Add it to your Signal integration config:
{
  "config": {
    "pixel_id": "1234567890",
    "access_token": "your_access_token",
    "test_event_code": "TEST12345"
  }
}
  1. Trigger events on your website — they will appear in the Test Events tab within seconds.

Step 2: Verify in Events Manager

  1. Go to Events Manager > your Pixel > Overview.
  2. You should see events arriving with the “Server” badge (indicating server-side delivery).
  3. Click on individual events to inspect the payload and match quality.

Step 3: Check Event Match Quality

  1. In Events Manager, go to Data Sources > your Pixel > Event Match Quality.
  2. Review the EMQ score and recommendations.
  3. If the score is below 6, add more user identity signals via _df.identify().
⚠️

Remove the test_event_code before going to production. Events sent with a test code are not used for ad optimisation or reporting.

Deduplication

If you are running both Signal server-side delivery and the Meta Pixel client-side (during a migration period), you must deduplicate events to prevent double-counting.

Signal includes a unique event_id with every event. To deduplicate:

  1. Pass the same event_id to both the client-side Meta Pixel and Datafly.js.
  2. Meta will automatically deduplicate events with matching event_name and event_id received within a 48-hour window.
// Generate a shared event ID
const eventId = crypto.randomUUID();
 
// Send via Meta Pixel (client-side)
fbq('track', 'Purchase', { value: 129.99, currency: 'USD' }, { eventID: eventId });
 
// Send via Datafly.js (server-side)
_df.track("Order Completed", {
  event_id: eventId,
  total: 129.99,
  currency: "USD"
});

Once you have validated that server-side events are arriving correctly and your EMQ score is healthy, you can remove the client-side Meta Pixel entirely. This eliminates the client-side tag, improves page performance, and removes the deduplication requirement.

Troubleshooting

ProblemSolution
Events not appearing in Events ManagerCheck the access token has ads_management permission. Verify the Pixel ID is correct.
Low Event Match QualityAdd user identity signals via _df.identify(). Ensure fbp and fbc cookies are being set.
OAuthException errorsThe access token may have been revoked or the system user lacks permissions. Regenerate the token.
Duplicate eventsIf running both client-side and server-side, ensure matching event_id values for deduplication.
Invalid parameter errorsCheck that required fields (event_name, event_time, action_source) are present. Review the payload in Signal’s event debugger.

Rate Limits

Meta’s Conversions API supports high throughput:

LimitValue
Events per API call1,000 (batched)
Sustained rate~1,000 events/second

Signal batches events automatically when batching is enabled for the integration. For most deployments, the default settings are sufficient.