Webclat / Signals
Signals  /  QA  /  CAPI-06

What's the correct way to forward Meta Conversions API events through a server-side GTM container?

Answer in brief

Use the official Meta Conversions API tag template inside your server-side GTM container, configured to read event data from the same request your container already receives from the client-side container's Client - not a separate, hand-built HTTP request tag. That keeps event_id, event_time, and hashed user_data populated from one shared source instead of drifting between a client-side Pixel tag and a manually maintained server-side call.

Why this happens

Server-side GTM is not simply GTM running on a server - it is a separate container that receives forwarded requests from your client-side container through a Client (typically the GA4 Client, since most implementations route through GA4-shaped hits), and it needs its own configuration to extract Meta-relevant fields from that incoming request.

Teams sometimes get this partially working by building a generic HTTP Request tag that posts to Meta's Graph API endpoint directly, hand-mapping each field - which works until the input event shape changes upstream (a renamed dataLayer variable, an added parameter) and the hand-built mapping silently stops picking up the new field. There is no error, because the HTTP request still succeeds with whatever subset of fields it happened to still have.

Fix it

  1. Import the official Facebook Conversions API tag template (or Meta-published equivalent) from the server-side Community Template Gallery inside your server GTM container, rather than building a custom HTTP Request tag from scratch.
  2. Confirm your server container has a working Client actually receiving and parsing the incoming requests from the client-side container - the CAPI tag can only forward fields the Client successfully parsed.
  3. Map the template's required fields (Pixel ID, access token stored as a GTM Variable referencing a secret manager or at minimum a container-scoped variable, never hardcoded in the tag config) to the event-data variables your server container already exposes.
  4. Set event_id and event_time from the same values the client-side Pixel tag used for the same action - typically forwarded automatically if both tags read from the same original dataLayer push, but verify this explicitly rather than assuming it.
  5. Configure the tag to fire on a trigger matching your server container's event names as parsed by the Client, not on every incoming request.
  6. Publish the server container version and confirm, in server-side GTM's own Preview mode, that the CAPI tag fires with the expected field values before relying on it in production.

How to verify it worked

  • In server-side GTM Preview mode, trigger a test action end to end and inspect the CAPI tag's Fired panel to confirm every required field - Pixel ID, event_name, event_id, hashed user_data - is populated, not just that the tag fired.
  • Cross-check the resulting event in Meta Events Manager's Test Events tool, using a test_event_code passed through the same tag configuration, and confirm the source shows as Server with the expected event data.
  • Confirm deduplication against the corresponding client-side Pixel event for the same action, using a shared event_id check - a server-side GTM implementation is only correct if it still dedupes, not just if it successfully delivers.

Want This Checked On Your Own Setup?

Send us the platform and the symptom and we will tell you whether this is the fix, or whether something else in your pipeline is masquerading as it.

Talk To The Practice