Fix guide · Any website · advanced · about 60 min

Meta CAPI events without a matching event ID: how to fix

For the findings “Meta server events have no event ID” and “Meta server events carry a different event ID”.

What this means

Your site sends its Meta events twice, on purpose: once from the browser through the Meta Pixel, and once more to your own server, which forwards them to Meta through the Conversions API (CAPI). Meta recommends this redundant setup, as long as both copies of an event can be recognized as one.

The server copy we saw does not carry the browser event’s ID:

  • No event ID: the request to your server has the event name but no ID.
  • A different event ID: the request carries an ID, but not the one the browser event had.

Meta merges a browser event and a server event when they have the same event name and the same event ID (eventID in the pixel, event_id in the Conversions API), within 48 hours. Without a matching ID, each conversion can be counted twice. Meta can also try to match on fbp or external_id, but its documentation says that generally works only when the browser event arrives first, so the event ID is the reliable method.

We report this as possible: we can see the request from the browser to your server, but never the request from your server to Meta, so check the server side yourself.

Why it costs you money:

  • Purchases and leads count twice in Ads Manager, so results and return on ad spend look better than they are.
  • Campaigns learn from inflated numbers and may spend on the wrong people.
  • When someone later “fixes” the double counting by switching one side off, you lose the reason you added the server copy.

How to confirm it yourself

  1. Open your page in a private (incognito) window, open developer tools (F12) and go to the Network tab. Accept cookies and trigger the conversion (for example, submit a test lead).
  2. Filter by facebook.com/tr and open the pixel request for that event: ev is the event name and eid is the event ID. No eid means the browser event has no ID (see “Meta events have no event ID”).
  3. Clear the filter and find the request your site sends to its own server at the same moment: a form submission, an /api/... call, or a request to your server-side tag manager address. Open its payload.
  4. Compare: does it contain the same ID as eid? If there is no ID, or a different one, the copies cannot be matched.
  5. In Meta Events Manager, open your pixel (dataset), click View details on the event and open Event deduplication: it shows how many events carry a deduplication key and how many arrive from both sources. The Test events tool shows, for a test action, whether the browser and server copies were deduplicated.

How to fix

The rule: one action, one ID, created in one place and used by both copies.

  1. Pick where the ID is created.

    • For purchases, the order number is ideal: the confirmation page can use it in the browser, and your backend already has it.
    • For leads, page views and clicks, create a random ID in the browser when the action happens (for example crypto.randomUUID()), or create it on your server when it renders the page or handles the form, and hand it to the browser.
  2. Pass it to the pixel as eventID, the fourth argument of fbq:

    const eventId = crypto.randomUUID();
    fbq('track', 'Lead', {}, { eventID: eventId });
  3. Send the same value to your server with the request it already receives: a hidden form field, a property in your /api/... call, or an event parameter in your server-side tag manager feed.

  4. Use it as event_id in the Conversions API event, with the same event_name:

    {
      "data": [{
        "event_name": "Lead",
        "event_time": 1792771200,
        "event_id": "4b1f0c6e-2f7d-4f6b-9a51-2d3c8e7f9a10",
        "action_source": "website",
        "event_source_url": "https://example.com/contact",
        "user_data": { "client_user_agent": "Mozilla/5.0 ...", "fbp": "fb.1.1596403881668.1116446470" }
      }]
    }
  5. Do not create a second ID on the server. A server that makes its own random ID, prefixes it, or sends a different value (a database row ID while the browser used the order number) produces a mismatch even though both copies “have an ID”.

  6. Keep the names identical. Purchase in the browser and purchase or Order on the server are different events to Meta. Custom events need exactly the same name on both sides.

  7. With server-side Google Tag Manager: generate the ID once with a variable such as Stape’s Unique Event ID, use it in the web Meta tag’s event ID field and pass it to the server container, where Meta’s Conversions API tag sends it as event_id. Check both containers in Preview mode: they must show the same value for the same event.

  8. With a plugin or app: most Conversions API tools set matching IDs for the browser events they send. If a separate, older pixel also sends browser events, those carry no matching ID; remove it.

  9. Publish and run a test conversion.

Common causes

  • The browser events have no eventID, so there is nothing for the server to copy.
  • The server-side code was added later and never received the ID from the browser.
  • Browser and server each generate their own random ID.
  • The server sends a different identifier or a different event name.
  • In server-side GTM, the web tag and the server tag read different variables.
  • A Conversions API tool deduplicates its own events, while a second, manually installed pixel sends the browser events.

How to verify the fix

  1. For one test conversion, the pixel’s eid, the ID in the request to your server and the event_id your server sends to Meta are identical, and so are the event names.
  2. In Events Manager’s Test events, the test action shows as deduplicated rather than counted twice. Regular reports can take 30 minutes or more to update.
  3. Re-run the check on IsPixelWorking. The finding should be gone.

Sources

More Meta guides