X Conversion API: the two endpoints and what differs
The X Conversion API split into web and app endpoints on 29 October 2026. Different token, different timestamp, and the app one has no deduplication key at all.
On this page · 9 sections
- Quick answer
- Why the Pixel alone undercounts
- Two routes in, and they have different entry requirements
- Event ID and Conversion ID: the two IDs people mix up
- Identifiers: what actually matches
- The GTM path, condensed
- App events got their own endpoint, with a narrower object
- What quietly fails, and the ceiling
- Is it worth the afternoon?
The short version
- ▸There are two Conversion APIs now, not one. On 29 October 2026 X added Conversion API for App Events and renamed the original to Conversion API for Web. Same host, different path, different auth header, different field names.
- ▸Since 17 September 2026 there is an official Google Tag Manager server-container tag, X Ads Conversion API (Official). It authenticates with an Events Manager Pixel token in an X-Pixel-Token header, so this route needs no Ads API access and no OAuth.
- ▸Event ID and Conversion ID are different things and mixing them up is the error that corrupts reporting. Event ID is the conversion type from Events Manager. Conversion ID is the per-occurrence deduplication key, and both channels must send the same one.
- ▸Matching needs a strong identifier: click ID (twclid), hashed email, or hashed phone. IP address and user agent are never enough on their own, and hashes must be SHA-256 with no salt.
- ▸The app endpoint has no conversion_id, no value and no twclid. You cannot deduplicate app events against a mobile measurement partner, and you cannot report purchase revenue through it. Those fields exist only on the web endpoint.
- ▸The web ceiling is 60,000 events per ad account per 15 minutes; the app page publishes no rate limit and caps a request at 500 conversions. Build retries and logging either way, because a non-2xx response means the conversion was not recorded.
Quick answer
The X Conversion API is now two endpoints. Web conversions go to ads-api.x.com/12/measurement/conversions/{pixel_id} with an X-Pixel-Token header. App installs and in-app events go to /12/accounts/{account_id}/measurement/app_conversions with an X-App-Conversion-Token header, added 29 October 2026. They take different field names, different timestamp formats, and the app one has no deduplication key.
Last updated: November 2026
Two changes in two months reshaped this product. In September 2026 X published an official Google Tag Manager server-container tag, which turned the web route from an engineering job into a configuration job. In October 2026 X split the product in half: the original endpoint was renamed Conversion API for Web and a separate Conversion API for App Events appeared next to it. Most guides describe neither.
Why the Pixel alone undercounts
Browser-side tracking misses a predictable set of conversions. The X Pixel fires in a page, so it never sees anything completed after a redirect off your domain, anything finished on a different device from the ad click, anything an extension or a tracking-prevention default blocks, and anything that happens in your backend rather than on a page. Phone orders and offline closes never had a chance.
Undercounting is not only a reporting annoyance. Campaign delivery optimizes against the conversions it is told about, so a channel that reports 60% of purchases is also training on 60% of them. That is the real argument for server-side reporting, and it is the one X leads with: measure when browser tracking is limited, and optimize delivery better.
Server-side reporting sits next to the Pixel rather than replacing it. X's recommended setup is explicitly redundant, with both channels sending the same events and a shared key so duplicates collapse.
Two routes in, and they have different entry requirements
This is the part worth getting straight before you plan the work, because the two paths are not equally hard.
| Official GTM tag | Custom server integration | |
|---|---|---|
| Auth | Conversion API access token from Events Manager, sent as X-Pixel-Token | OAuth user access token for a user with AD_MANAGER or ACCOUNT_ADMIN |
| Ads API access needed | No | Yes, a developer account plus an approved Ads API application |
| Code to write | None. Configure a tag | Build, sign and retry the request yourself |
| Where it runs | A GTM server container only | Your own backend |
| Best for | Web conversions you already send to a tagging server | Offline conversions, CRM events, batch uploads |
If you already run server-side GTM, the official tag is the short path and the only credential you need comes from Events Manager: Install Pixel → Manual → Conversion API → Generate access token. Store it in a GTM variable rather than pasting it into several tags.
One warning from X's own documentation that is easy to miss: use the template named X Ads Conversion API (Official). Community templates with similar names, including third-party "X (Twitter) Conversion API" tags, are a different integration with different authentication.
Event ID and Conversion ID: the two IDs people mix up
This is the single most expensive misunderstanding in the whole setup, and X calls it out directly.
- Event ID is the conversion type. It comes from Events Manager and identifies, for example, your Purchase event.
- Conversion ID is the per-occurrence deduplication key. An order number, a UUID, or the GA4
event_id.
To deduplicate between the Pixel and the Conversion API you need both to match on both channels: the same Event ID and the same Conversion ID for the same conversion. Matching only the Event ID tells X the two reports are the same type, not the same purchase, and you get double counting. The clean way to guarantee it is to fire the Pixel tag and the GA4 event tag from the same trigger in the web container, with one generated ID shared between them.
If the Pixel and the API send genuinely different events, skip all of this. Deduplication is only needed where the two overlap.
There is also a quiet fallback worth knowing. If you leave Event ID empty on the GTM tag, it sends the incoming event name prefixed and lowercased, so purchase arrives as gtm_purchase. Convenient for a single catch-all tag. Bad for Pixel deduplication, because those are not your Events Manager events. And if both the Event ID and the event name are missing, the conversion is not sent at all, silently.
Identifiers: what actually matches
X needs at least one identifier it can tie to an account. The rules are specific and the hashing is unforgiving.
| Identifier | Hashing | Notes |
|---|---|---|
X click ID (twclid) | None | Always send it when available. X recommends this one first |
| Hashed email | SHA-256, no salt | Trim whitespace, lowercase before hashing |
| Hashed phone | SHA-256, no salt | Normalize to E.164 first, for example +11234567890 |
| IP address | None | Must be paired with another identifier |
| User agent | None | Must be paired with another identifier |
Two failure modes account for most poor match rates. The first is hashing done wrong: a salt, a stray space, or an uppercase address produces a hash that will never match. The official GTM tag will hash plain values for you, which removes that class of bug, and it passes through any value that is already a 64-character hex string.
Second is a lost click ID. X appends twclid to the landing page URL on an ad click, and it only survives to the conversion if something stores it. With Set first-party cookies enabled, the server tag writes a _twclid cookie that lasts about 390 days. That cookie is far more durable on a first-party tagging domain than on the default one, which is why mapping a custom domain to your tagging server is not cosmetic. If you keep the Pixel installed, it also sets _twpid, which the server tag reads as another identifier.
Passing more identifiers raises the match rate. Passing only IP and user agent raises nothing, because neither counts alone.
The GTM path, condensed
Structurally it is a web container feeding a server container, with the X tag firing on the server side.
- Collect three things from Events Manager: the Pixel ID, which is your event source ID, the Event ID for each conversion you care about, and a Conversion API access token.
- Create a server container and provision a tagging server. Keep the default GA4 Client enabled, because it claims the incoming requests the X tag reads.
- Point the web container at it. In your GA4 Configuration tag, enable sending to the server container or set the
transport_urlfield to your tagging server URL. Addfirst_party_collection: trueso hashed user data reaches the server. - Install the official tag in the server container from Templates → Search Gallery.
- Configure it: Pixel ID, access token from a variable, and the Event ID for this conversion. One tag per Events Manager event is the cleaner pattern when you care about named events.
- Trigger on the event name that the GA4 Client claimed, for example
purchase, rather than on all requests. - Preview both containers before publishing. The checks that matter are that the GA4 Client claimed the request, that the X tag fired, that its outgoing POST went to
ads-api.x.com, and that the response was 2xx. Then confirm the conversion appears in Events Manager.
Set the tag's logging to debug only while testing and switch it off for production. X notes that logs can include identifiers, which is not something you want written to a console on live traffic.
App events got their own endpoint, with a narrower object
Before 29 October 2026, reporting an app install to X meant working through a mobile measurement partner. The Conversion API for App Events removes that dependency: you connect the app in Events Manager under Manage App Events → X App Conversion API, generate a token, and POST events from the app or from your server.
Connecting is the step that creates something. X creates the app's INSTALL event for you, with a 14-day post-engagement and 1-day post-view attribution window that you can change afterwards. Extra event types such as SIGN_UP and PURCHASE are added in Events Manager and then sent with the same request shape.
Side by side, they look similar and are not interchangeable:
| Conversion API for Web | Conversion API for App Events | |
|---|---|---|
| Path | /12/measurement/conversions/{pixel_id} | /12/accounts/{account_id}/measurement/app_conversions |
| Scoped to | A Pixel | An ad account |
| Auth header | X-Pixel-Token | X-App-Conversion-Token |
| Event named by | event_id from Events Manager | event_name, e.g. INSTALL |
| Timestamp | conversion_time, ISO 8601 | conversion_timestamp, Unix milliseconds |
| Batch cap | Not published | 500 conversions per request |
| Rate limit | 60,000 events per account per 15 min | Not published |
| Click ID | twclid | Not accepted |
| Revenue | value, number_items, contents | Not accepted |
| Dedup key | conversion_id | None |
Read the last three rows together, because they decide what you can do with this.
No conversion_id means no deduplication. The whole discipline described above, matching a per-occurrence key across two channels, has no equivalent on the app side. If you keep an MMP running during a migration, both will report the same install and X has no key to collapse them. Run one or the other per app, and cut over rather than overlap.
No value means no revenue optimisation through this endpoint. Web conversions carry value, number_items and an itemised contents array. An app PURCHASE event carries a name and a timestamp. You can tell X that a purchase happened, not what it was worth.
No twclid either, which follows from the medium: there is no landing-page URL to parse. App identifiers are device_id, hashed_email, hashed_phone_number, or ip_address paired with user_agent, plus an optional limit_ad_tracking flag.
One asymmetry in the hashing rules is worth noticing. Email and phone must be SHA-256 with no salt, same as the web endpoint, but device_id is the raw, unhashed IDFA or Android Advertising ID. X names device_id as the recommended identifier, and on iOS that means an App Tracking Transparency prompt in the app, so the recommended path is also the one that needs an app release and a user's consent. If you would rather not ship that change, hashed email or hashed phone works without touching the app.
Finally, two operational notes. The token is shown only once, and one token covers every app on the ad account, so treat it like an account-wide credential rather than a per-app one. And the response is the same shape as the web endpoint, conversions_processed plus a debug_id, which is the value to quote in a support thread.
What quietly fails, and the ceiling
Three things are worth writing on a sticky note.
A failed call is a lost conversion. X tells you to check the response code and build retries with logging. There is no queue on their side holding your 500s. A success returns conversions_processed and a debug_id, and that debug ID is the thing to quote if you ever open a support thread.
The web ceiling is 60,000 events per ad account per 15 minutes. Generous for most advertisers, and a real constraint for a batch backfill, which is the scenario where people hit it. X publishes no rate limit for the app endpoint, only the 500-conversion cap per request, so pace a backfill there against the web number until something tells you otherwise.
Consent is your problem, not the tag's. X states plainly that your server code may need to filter out conversions from users who exercised privacy choices, and the GTM guide repeats it. Server-side reporting removes the browser from the path, which also removes whatever consent gate lived in the browser. That logic has to be rebuilt deliberately on your side, and X's conversion tracking and custom audiences policies are the governing document for what you are allowed to send.
Is it worth the afternoon?
If you are spending enough on X ads that a 20% reporting gap changes a decision, yes, and the GTM route makes it a configuration job rather than an engineering one. Better conversion data also makes the rest of your X ads cost math honest, since cost per acquisition is only as good as the denominator. If you are running lead gen ads, the native form already reports inside X, so the Conversion API matters most for what happens on your own site afterward.
If you are not buying ads at all, none of this applies to you, and the measurement question is a different one. Organic reach on X is decided by the algorithm rather than by a pixel, which is why how an X post accumulates views and what an X ad actually is are more useful starting points than a tagging server. Our own tool, X-Autopilot, sits on that organic side: it runs on your Mac for replies and posting cadence, and it has nothing to do with ad measurement.
Honest summary of the September change: narrow, but real. The Conversion API did not get easier to understand. It got easier to install, for exactly one kind of advertiser: the one who already has a tagging server and was told, incorrectly, that they needed API credentials first.
Frequently asked
Answers indexed by Google + AI assistants.
What is the X Conversion API?+
It is an X Ads endpoint that accepts conversions from your server instead of from the browser: POST to ads-api.x.com/12/measurement/conversions/{pixel_id} with a conversion time, an Events Manager Event ID, and at least one identifier X can match to a user. It exists because browser tracking misses conversions that happen after a redirect, in an app, on a later device, or where the Pixel is blocked, and those conversions are also what campaign optimization learns from.
Do I need Ads API access to use the X Conversion API?+
Not for the Google Tag Manager route. The official tag authenticates with a Conversion API access token generated in Events Manager and sent as an X-Pixel-Token header, which X states explicitly does not require OAuth or an Ads API application. A custom code integration is the stricter path: it needs a developer account with Ads API access and user access tokens belonging to a user with AD_MANAGER or ACCOUNT_ADMIN permission on the ad account.
What is the difference between Event ID and Conversion ID?+
Event ID identifies the conversion type, for example your Purchase event, and comes from Events Manager. Conversion ID identifies one specific occurrence of it, so an order ID or a UUID. Deduplication between the Pixel and the Conversion API requires both: the same Event ID and the same Conversion ID on both channels for the same conversion. Sending matching Event IDs alone does not collapse duplicates.
Does the Conversion API replace the X Pixel?+
It can run alone, but X recommends against it. The documented setup is deliberately redundant: Pixel plus Conversion API on the same events, sharing an Event ID and a Conversion ID, so you keep coverage when either channel drops events. If the two channels report completely different events, you do not need deduplication at all.
Why are my conversions not matching?+
Usually a weak identifier. X needs at least one of click ID, hashed email or hashed phone, and it treats IP address and user agent as supporting signals that must be paired with something else. The other common causes are a salted or uppercase email hash, a phone number that was never normalized to E.164 before hashing, and a missing twclid because the landing page URL dropped the parameter or the first-party cookie was blocked on a default tagging domain.
What is the X Conversion API for App Events?+
An endpoint added on 29 October 2026 that reports app installs and in-app events to X without a mobile measurement partner: POST to ads-api.x.com/12/accounts/:account_id/measurement/app_conversions with an X-App-Conversion-Token header. Each conversion needs app_id, os_type of IOS or ANDROID, an event_name such as INSTALL or PURCHASE, a conversion_timestamp in Unix milliseconds, and at least one identifier. A request can carry up to 500 conversions. In Ads Manager the integration is labelled X App Conversion API and sits above the mobile measurement partners in the Manage App Events window.
What is the Conversion API rate limit?+
60,000 events per ad account per 15 minute interval. X also tells you to check the response code on every call and to build a retry mechanism with basic logging, because a conversion that returns an error code is simply not recorded. A successful response returns conversions_processed and a debug_id you can quote in a support thread.
- X developer docs - 'Set up the Conversion API with Google Tag Manager': the official tag name, the X-Pixel-Token authentication, the statement that no OAuth or Ads API access is needed for this route, the Event ID and Conversion ID distinction, the identifier table, the gtm_ event-name fallback, and the preview and publish checks (accessed 2026-10-12)
- X developer docs - 'Web conversions': the POST /version/measurement/conversions/:pixel_id endpoint, the Ads API access and AD_MANAGER or ACCOUNT_ADMIN token requirements for custom integrations, the SHA-256 hashing rules for email and phone, the pairing rule for IP and user agent, and the 60,000 events per account per 15 minutes rate limit (accessed 2026-10-12)
- X API changelog - 'Conversion API Google Tag Manager server-side template': the dated release of the official X Ads Conversion API tag for GTM server containers (published 17 September 2026)
- X developer docs - 'Conversion API for App Events': the POST /12/accounts/:account_id/measurement/app_conversions endpoint, the X-App-Conversion-Token header, the 500-conversion cap per request, the conversion object of app_id, os_type, event_name, conversion_timestamp and identifiers with optional limit_ad_tracking, the raw unhashed IDFA or Advertising ID as device_id, and the Install event created with a 14-day post-engagement and 1-day post-view window (accessed 6 November 2026)
- X API changelog - 'Conversion API for App Events' (29 October 2026): the launch of the app endpoint, the X-App-Conversion-Token header, the 500-events-per-request limit, and the statement that 'the website endpoint is unchanged and is now titled Conversion API for Web'
- Google Tag Manager Community Template Gallery - 'X Ads Conversion API (Official)' by twitter: the published template, server-container only (accessed 2026-10-12)
Product designer and indie hacker. Runs the agent on his own X account every day and writes up what the data shows, including when it's inconvenient.
Follow on X →