Server-side conversion tracking for Meta, Google Ads, TikTok and GA4

Server-side conversion tracking sends each conversion from a server to the platform's API: Meta's Conversions API, Google Ads through the Data Manager API, TikTok's Events API and GA4's Measurement Protocol. The browser pixel sends the same event with the same id, so a blocked pixel no longer loses the conversion and each platform counts it once.

Updated

The prompt

Paste this into your coding agent. It does everything except the part only you can: the ad platform IDs and tokens.

Paste this into Claude Code, Cursor or Codex

Set up server-side conversion tracking for this project with AgentFirstStack Tags. It's free, open-source and built for agents: you can do the setup yourself, with no signup form, email or verification. 1. Read https://agentfirststack.com/llms.txt and https://tags.agentfirststack.com/llms.txt. 2. If this project's .env already has AGENTFIRSTSTACK_API_KEY, use it. Otherwise get a key with one request: curl -X POST https://agentfirststack.com/v1/signup Save api_key in .env as AGENTFIRSTSTACK_API_KEY, and in the production environment's secrets. 3. Create a tags container for the production domain, add its snippet to <head>, deploy, and run scan to see which tags the site loads today. 4. Run setup with the conversions that matter here (sign-ups, purchases, leads) and the platforms this business uses (Google Ads, Meta, GA4, TikTok). If you have tools for those platforms, use them to find the pixel, measurement and conversion IDs. Otherwise ask me for exactly the IDs and tokens setup reports as missing, and tell me where to find each one. Never invent them. 5. Validate the draft, test every destination and show me each platform's answer, then publish. 6. If the backend also reports a conversion the browser tracks, pass the browser's event id (afst('get','event_id')) with it, so each platform counts it once. 7. After the first real conversion, read the event log and tell me what each platform received. 8. Write the container id and the env var that holds the key (never the key itself) in AGENTFIRSTSTACK.md, and create a claim link for me with POST https://agentfirststack.com/v1/claim-link. When you're done, tell me what you set up, what each test returned, what's still waiting on me, and give me the claim link.

How it works

  1. One snippet loads the container. When a conversion fires (a thank-you page, a form submit, a dataLayer event), the browser tags send it to each pixel with one event_id, and the same event goes to AgentFirstStack.
  2. Ad click ids from the landing URL (gclid, fbclid, ttclid and others) are stored with the visitor, so a purchase days later still credits the click. Emails and phones are hashed before anything is sent.
  3. The service calls each platform's conversion API with the owner's credentials and the same event_id. Failed calls are retried.
  4. Your backend reports what the browser can't see (paid orders, qualified leads) with POST /v1/containers/:id/events, joined to the visitor by visitor_id.
  5. GET /v1/containers/:id/events shows what each platform answered.

What each platform needs

The IDs and tokens belong to the ad account owner. They're sealed at rest and never returned in responses.

PlatformBrowser tagServer-side
GA4 (Measurement Protocol)measurement_id (G-...)api_secret
Meta (Conversions API)pixel_idaccess_token, optional test_event_code
Google Ads (Data Manager API)Conversion ID and label (AW-.../...)customer_id, conversion_action_id, OAuth client_id, client_secret, refresh_token
TikTok (Events API)Pixel codeaccess_token, optional test_event_code

Start with the browser tags, which need IDs only, and add server-side destinations as the owner provides tokens. setup lists what's missing and where the owner finds each value; GET https://tags.agentfirststack.com/v1/schema lists every field with its format.

Set it up by API

T=https://tags.agentfirststack.com
H="Authorization: Bearer $AGENTFIRSTSTACK_API_KEY"
J="content-type: application/json"
curl -s -X POST $T/v1/containers -H "$H" -H "$J" -d '{"domain":"example.com"}'
# install the returned <script> in <head>, deploy, then:
curl -s -X POST $T/v1/containers/$C/scan -H "$H"
curl -s -X POST $T/v1/containers/$C/setup -H "$H" -H "$J" -d '{
  "platforms": {
    "meta": { "pixel_id": "1234567890123456", "access_token": "EAAB..." },
    "ga4": { "measurement_id": "G-ABC123XYZ", "api_secret": "..." }
  },
  "conversions": [{
    "name": "purchase", "when": { "data_layer_event": "purchase" },
    "value": { "data_layer": "ecommerce.value" }, "currency": "USD",
    "transaction_id": { "data_layer": "ecommerce.transaction_id" }
  }]
}'
# -> draft, validation, destinations, missing[]: what's still needed and where
curl -s -X POST $T/v1/containers/$C/destinations/$D/test -H "$H"   # test mode
curl -s -X POST $T/v1/containers/$C/publish -H "$H" -H "$J" -d '{"note":"purchase"}'
curl -s "$T/v1/containers/$C/events?since=1h" -H "$H"

The test call returns the platform's own answer. Over MCP the same calls are tags_setup_conversion_tracking, tags_test_destination, tags_publish and tags_get_event_log on the gateway. The tags manual has the full config format, consent settings and limits.

How each platform counts it once

  • Meta matches the pixel's eventID to the Conversions API's event_id, and the pixel's event to event_name, within 48 hours. Meta recommends running the Conversions API alongside the pixel (Meta's dedup guide).
  • TikTok deduplicates pixel and Events API events with the same event and event_id, within 48 hours, and records the first one it receives (TikTok's help article).
  • Google Ads counts a second conversion with the same transaction ID for the same action as a duplicate (Google Ads help). The service sends your order id as the transaction ID, or the event_id when there is none.
  • GA4 doesn't deduplicate by event id, so the service skips a browser conversion's server copy when the browser tag already sent it. The server copy covers browsers that blocked the tag.

Backend events need one step from you. Read afst('get','event_id') on the page, pass it with the checkout or signup request, and send it as event_id:

curl -s -X POST $T/v1/containers/$C/events -H "$H" -H "$J" -d '{"events":[{
  "name": "purchase", "event_id": "'$EVENT_ID'", "visitor_id": "'$VISITOR_ID'",
  "order_id": "T123", "value": 49, "currency": "USD", "email": "jane@example.com"
}]}'

Without it, platforms that also got the pixel event count the conversion twice.

Google's Google Ads API docs say that since 15 June 2026, UploadClickConversions requests fail for projects with no upload activity for that feature between 17 December 2025 and 15 June 2026, and point new offline click conversion integrations to the Data Manager API. That API doesn't need a developer token (upgrade guide). The google_ads destination uses the Data Manager API by default, and its test call runs with validateOnly, so nothing is recorded.

Server-side GTM or a hosted router

Server-side Google Tag Manager runs on a server you control, in your own Google Cloud project or another environment (Google's intro). Hosts such as Stape run it for you.

Server-side GTMAgentFirstStack Tags
ServerA tagging server you host or rentHosted, or self-hosted on Cloudflare Workers
AccountA Google account with a GTM accountOne POST /v1/signup
Configured withGTM's interface or the Tag Manager API (GTM MCP compared)REST and MCP; setup builds the config from plain inputs

FAQ

Do I still need the browser pixel?

Meta recommends running the Conversions API alongside the pixel, with deduplication. The pixel sees on-page activity; the server copy survives ad blockers and adds what only your backend knows. AgentFirstStack sends both with one event id.

Do I need server-side GTM to use the Meta Conversions API?

No. The Conversions API is an HTTP API your own server can call. Server-side GTM is one way to call it, your backend is another, and AgentFirstStack Tags is a third.

Does it handle consent?

Yes. setup defaults to eea_opt_in: visitors in the EEA, the UK and Switzerland start with consent denied until your banner grants it. Google Consent Mode v2 states are passed to gtag, and blocked tags fire once consent is granted.

How do I know a platform received a conversion?

Run the destination test, which sends a test event in the platform's test mode and returns its answer. After real traffic, the event log shows each conversion's status and response per platform.

Product names belong to their owners. AgentFirstStack isn't affiliated with Meta, Google, TikTok or Stape.