Conversion tracking your AI agent sets up and tests

AgentFirstStack conversion tracking sends each conversion from the browser and from our servers to GA4, Google Ads, Meta, TikTok, LinkedIn, Pinterest, Reddit, Snap and X, with one event id, so each platform counts it once. It replaces server-side GTM, Stape and Meta's Conversions API Gateway: there's no server container to build or host. It's part of AgentFirstStack Tags, free and open source. An AI agent sets it up, tests each platform in its own test mode and reads what each one answered. If your team builds tracking in Google Tag Manager and needs its template gallery, server-side GTM fits better.

Updated

Set it up with one prompt

Paste this into your coding agent. It finds out what counts as a conversion here before it changes anything, and asks you only for the ad platform IDs and tokens it can't look up.

Paste this into Claude Code, Cursor or Codex

Set up conversion tracking for this project with AgentFirstStack Tags, in the browser and server-side. It's a free, open-source tag manager built for agents that calls the ad platforms' conversion APIs itself, and you can do the setup yourself: there is no signup form. 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 and read AGENTFIRSTSTACK.md. Otherwise get a key: curl -X POST https://agentfirststack.com/v1/signup, and save api_key in .env as AGENTFIRSTSTACK_API_KEY and in the production secrets. 3. Work out what this business counts as a conversion (sign-ups, leads, purchases), which of them only the backend knows (a paid order, a qualified lead), and which ad platforms it uses. Create a tags container for the production domain, run scan, and tell me which pixels, tag managers or server-side tracking the site has today before you change anything. 4. Serve the container from our own domain: a first-party domain (POST https://agentfirststack.com/v1/first-party-domains with a neutral subdomain such as edge.<our domain>; add the one CNAME it returns if you can change our DNS, otherwise give me the record), or meanwhile the path proxy from GET /v1/containers/:id/install?proxy=1 with its proxy key kept server-side. Put the snippet in the head of every page. 5. Run setup with those conversions, the platforms this business uses, and analytics. If you have tools for the ad platforms, use them to find the IDs; otherwise ask me for exactly the IDs and tokens setup reports as missing, and where I find each. Never invent them. 6. Send the backend-only conversions with POST /v1/containers/:id/events, with the visitor_id and, when the browser also tracks the conversion, its afst('get','event_id'), so each platform counts it once. 7. Validate, test every destination and show me each platform's answer, open a preview and read its log, then publish and deploy. Run the setup test (POST https://agentfirststack.com/v1/setup/test) and its browser plan, then the setup check (GET https://agentfirststack.com/v1/setup) until it's ready. Leave any existing pixels or server-side setup in place until I say so. 8. Write the container id and the env var name (never the key) in AGENTFIRSTSTACK.md, and create a claim link for me with POST https://agentfirststack.com/v1/claim-link. Tell me what you set up, what each test returned, what's waiting on me, and give me the claim link.

What your agent does

Every step is a REST call on https://tags.agentfirststack.com (or https://agentfirststack.com for the project-wide ones) and an MCP tool on https://agentfirststack.com/mcp.

  1. Gets a key with POST /v1/signup, or reuses the one in .env.
  2. Creates a container for the domain: POST /v1/containers (tags_create_container).
  3. Looks at the site: POST /v1/containers/:id/scan (tags_scan_site) lists the GTM containers, GA4, Google Ads, Meta, TikTok, LinkedIn and other pixels already there, the forms, buttons and thank-you pages. A GTM web container comes over with draft/import (tags_import_draft), dry run first.
  4. Serves it first-party: POST /v1/first-party-domains {"hostname":"edge.example.com"} (afs_add_first_party_domain) returns one record, CNAME edge.example.com -> fp.agentfirststack.com. Once it's active, the snippet is https://edge.example.com/_t/c/<container>.js. Where DNS can't change, the path proxy configs come from GET /v1/containers/:id/install?proxy=1.
  5. Describes the conversions in plain terms: POST /v1/containers/:id/setup (tags_setup_conversion_tracking) with the platforms and conversions (a dataLayer event, a thank-you page, a form). It writes and validates the draft, adds the destinations, and lists every ID and token still missing.
  6. Tests each platform: POST /v1/containers/:id/destinations/:did/test (tags_test_destination) sends a test event in that platform's test mode and returns the platform's own answer.
  7. Previews and publishes: POST /v1/containers/:id/preview and its log (tags_create_preview, tags_get_preview_log) show which tags fired on a page and why others didn't; POST /v1/containers/:id/publish (tags_publish) makes it live, with versions to roll back to.
  8. Wires the backend for conversions only it knows: POST /v1/containers/:id/events (tags_send_server_events).
  9. Checks it end to end: the setup test (afs_test_setup), a browser visit from its plan (afs_check_test_visit), the setup check (afs_check_setup), and later the delivery log, GET /v1/containers/:id/events (tags_get_event_log).
  10. Hands over a claim link (POST /v1/claim-link) so you can sign in with Google and see the containers, deliveries and versions in a dashboard.

What you get

PlatformServer-side APITest mode
GA4Measurement ProtocolValidation server
Google AdsData Manager API (or Google Ads API): click conversions with the gclid, gbraid or wbraid, plus hashed email and phonevalidateOnly
MetaConversions APIYour test_event_code
TikTokEvents APIYour test_event_code
LinkedInConversions APINone: test traffic is skipped
PinterestConversions API?test=true
RedditConversions APIYour test_id
SnapConversions API/events/validate
XAds API conversionsNone: test traffic is skipped
AgentFirstStack analyticsEvents APIdebug: true, kept out of reports
WebhookYour HTTPS endpoint, signed with HMAC-SHA256"test": true in the payload

Microsoft Advertising is browser-only: the UET tag fires, but server-side delivery to it isn't built.

  • One event id per conversion. The runtime creates it and uses it as Meta's eventID, TikTok's event_id, Reddit's conversionId, X's conversion_id, Pinterest's and LinkedIn's event_id and Snap's client_dedup_id, and the server copy reuses it. GA4 and analytics don't deduplicate by id, so their server copy is skipped when the browser tag already sent it. LinkedIn deduplicates only when its destination maps each Insight Tag conversion to its Conversions API rule (conversion_rules).
  • Click ids. gclid, gbraid, wbraid, dclid, fbclid, msclkid, ttclid, li_fat_id, twclid, rdt_cid, epik and ScCid are captured on landing (when consent allows) and used for 90 days, with _fbp, _fbc, _ttp and the other platforms' own cookies.
  • Backend events. POST /v1/containers/:id/events takes up to 100 events per request. Sent with the browser's visitor_id, they're joined to that visitor and go out with the stored click ids, IP and user agent that conversion APIs match on; a user_id, email or phone your backend linked to a visitor earlier joins too. Backend events are the source of truth: deduplicated only against earlier backend events (same event_id, or the same name and order_id).
  • Customer data, hashed. Emails, phones and names are normalised per platform and SHA-256 hashed in the browser before anything is sent; your backend's are hashed before they leave the service.
  • Routing rules. Per destination: which conversions it gets, conditions (only the US, only a value above 0), which parameters go out or stay back, page URLs without query strings, and lookup tables, for example to send margin per SKU as the value instead of revenue.
  • The delivery log. GET /v1/containers/:id/events shows, for 7 days, every conversion with each destination's status, HTTP status and the platform's answer, and the reason when one was skipped (no consent, no click id, test traffic with no test mode). Failed calls are retried (6 attempts over about 16 minutes), and a destination that keeps failing pauses for an hour, or until a test passes.
  • Consent. Google Consent Mode v2, IAB TCF v2, or the container's own consent banner decide which tags fire; tags waiting for consent fire once it's granted.
  • Junk traffic. Container ids are public, so anyone can post hits. A network's daily share and an attack mode for sudden spikes set suspicious hits aside, and their conversions never reach an ad platform. Conversions your backend sends with the key always flow.

What the setup check verifies

GET https://agentfirststack.com/v1/setup (afs_check_setup) reads what the services have received and reports each item as ok, missing, failing or a warning, with the call that fixes it. For conversion tracking:

  • tags.container: there is a tag container for the website.
  • tags.installed: the container snippet is on the pages.
  • tags.domain_verified: the container's domain is verified, which custom HTML and JavaScript tags need.
  • tags.published: a version is published.
  • tags.events: there is an event for each main action.
  • tags.to_analytics and tags.goals_for_events: the events reach analytics, and each has a goal there.
  • tags.firing: every tag fires, and none fails (with tag-fire reporting on).
  • tags.destinations: conversions reach every ad platform; it fails while a destination has failed deliveries.
  • tags.consent_banner: visitors from the EU, UK and Switzerland are asked before ad pixels fire.

The setup test (POST /v1/setup/test) goes further and sends each conversion to each ad platform in its test mode, one result per destination.

Compared with

ToolWhat it isThe difference
Server-side GTMA GTM server container you run on a server you control; Google puts each Cloud Run server at about $45 a month (Cloud Run setup guide, as of 7 Nov 2026)No server container to build, host or update: the service calls the APIs
StapeHosting for server-side GTM, free up to 10K requests a month, then from $17 a month (stape.io/price, as of 7 Nov 2026)Set up and tested over an API by your agent, instead of built in GTM
Meta Conversions API GatewayMeta's gateway for Meta Pixel events, run in your AWS or Google Cloud account or by a partner (Meta's docs, as of 7 Nov 2026)Nine ad platforms, and nothing to host

Limits

  • 10 tag containers per project (3 until a person claims it), and 5 conversion APIs per container.
  • Delivery log: 7 days. Click ids: used for 90 days. Visitors: kept 180 days after they were last seen, for backend joins.
  • Backend events: up to 100 per request. Daily budgets for browser events, backend events and deliveries apply per container and account; GET /v1/usage shows each with what's used.

Every limit, with the ones for analytics, mail and replay: fair-use limits.

When it isn't the right fit

  • A platform we don't send server-side. Microsoft Advertising is browser-only, and there are no destinations for affiliate networks or email tools. GTM's server templates cover those; a signed webhook can forward conversions to your own code.
  • A visual editor for people. There's no tag editor in the dashboard: changes are API or MCP calls your agent makes. The dashboard shows containers, deliveries and versions.
  • Testing LinkedIn and X before going live. They have no test mode, so test traffic is never sent to them; the first real conversions are the test, in the delivery log.
  • Cookies set from the server on a subdomain. Through a first-party domain, the container's own cookies are set by its script in the page. They're set from the server too only through the path proxy, where the page and the collector share one host.
  • Your own AWS or Google Cloud account. Self-hosting runs on Cloudflare Workers, not on AWS or Google Cloud.

FAQ

Do I still need the browser pixels?

The container fires them for you. Each conversion goes out as the browser pixel and as a server-side call with the same event id, so a platform that receives both counts it once. The server copy reaches the platform when an ad blocker stops its pixel, and your backend can report conversions the browser never sees.

How does each platform count a conversion only once?

The runtime creates one event_id per conversion and uses it as Meta's eventID, TikTok's event_id, Reddit's conversionId, X's conversion_id, Pinterest's and LinkedIn's event_id and Snap's client_dedup_id; the server copy reuses it. GA4 doesn't deduplicate by id, so the service skips GA4's server copy when the browser tag already sent it. A conversion your backend reports needs the browser's id: read afst('get','event_id') on the page and send it as event_id.

Which platforms can be tested without recording a real conversion?

GA4 (validation server), Google Ads (validateOnly), Meta and TikTok (a test event code), Reddit (a test id), Pinterest (test=true) and Snap (its validate endpoint). LinkedIn and X have no test mode, so test traffic is never sent to them; check their first real deliveries in the event log.

Can my backend report conversions the browser doesn't see?

Yes. POST /v1/containers/:id/events takes up to 100 events per request. Pass the visitor_id the browser had (afst('get','visitor_id')) through your checkout or sign-up, and the event is joined to that visitor's stored ad click ids, so a purchase reported days later still credits the click. They go server to server, so no browser can block them.

Does it work when visitors use ad blockers?

Serve it from your own domain. A first-party domain is one CNAME from a subdomain such as edge.example.com to fp.agentfirststack.com; the container then loads from /_t/ on it, with no server code. A path proxy on your own server does the same where DNS can't change. Without either, the snippet loads from tags.agentfirststack.com, which ad blockers can block. Backend events can't be blocked.

What does it cost?

The hosted service is free within fair-use limits: 10 tag containers per project and 5 conversion APIs per container. The code is AGPL-3.0 (the browser runtime is MIT), and you can self-host it on your own Cloudflare account.

Product names belong to their owners. AgentFirstStack isn't affiliated with Google, Meta, Stape or the other platforms named here.