Measurement
How to track ChatGPT ad conversions without lying to yourself
The pixel alone is not enough, the Conversions API alone is not enough, and the failures are silent. A walkthrough of the architecture, the seven-day rule that dictates your build, and the six ways accounts quietly break.
Run the Conversions API as your system of record and the JavaScript pixel alongside it, with both surfaces sending the same deduplication ID. Build only one and you will get numbers that look confident and are wrong.
Most underperforming ChatGPT ad accounts we look at are not badly optimized. They are badly measured, and the two are indistinguishable from the dashboard. A campaign reporting zero attributed conversions and a campaign that genuinely did not work produce the same screenshot.
What makes this platform particularly unforgiving is that its tracking failures are silent. Nothing errors. No warning appears. You get a plausible number and you make decisions against it for a month.
Why you need both surfaces
OpenAI says plainly that the Conversions API is more reliable than the pixel alone, and that is the right default: server-side events do not care about ad blockers, script failures, or a browser that closed the tab too early.
The pixel still earns its place, for three specific reasons rather than out of caution. It captures the click identifier from the landing page URL automatically. It sets the browser reference cookie that the server integration needs for hybrid matching. And it handles interaction events that never touch your server at all.
So the two failure modes at the extremes are:
- Pixel only. You lose events to ad blockers and script failures, silently, and you will never know the size of the gap.
- API only. You forfeit automatic click identifier capture and the browser reference, which degrades your match rate. Match rate degradation does not announce itself. It looks like a channel that underperforms.
There is a third surface, an image tag, for locked-down systems where no script can run. Treat it as an emergency measure. It captures no click identifier, supports no customer matching, and if it runs alongside the pixel without a shared ID it double counts everything.
Deduplication is the whole ballgame
If the same conversion goes out from two surfaces, both records must carry the same ID or your client sees inflated numbers. This is where most dual-stack builds break, because the field name changes depending on where you are sending from while the value must not change at all.
Two rules make this survivable.
Use the client's own primary key. An order ID for an order. A CRM record ID for a lead. Never generate a random ID at send time, because a retry then produces a second, different ID and the same conversion counts twice.
Reuse the same ID on every retry and on every integration that sends that conversion. Same order, same ID, forever.
Consent ordering, which is unforgiving
On the pixel, consent must be set before initialization, not after. Consent defaults to granted unless you set it false or a stored denial is found, and when it is false no measurement pings are sent.
Here is the part that matters: blocked events are never replayed once consent is later granted. Get the ordering wrong on a site with European traffic and those conversions are permanently gone. There is no backfill, no reconciliation, and no way to discover it from the numbers.
The image tag has no consent API at all, so the decision has to be made before the tag renders, in your CMS or server template. On the Conversions API, consent is enforced by your own server logic before the call is made, and it needs to gate the browser reference too.
The seven-day rule that dictates your architecture
The Conversions API accepts offline outcomes. That is genuinely important, because it means a closed-won deal in your CRM can be sent back as a conversion and the platform can optimize toward revenue rather than form fills.
The constraint: event timestamps must fall within the last seven days, and no more than ten minutes in the future.
Three consequences follow, and they need to be designed in rather than discovered:
- A monthly CRM export is worthless. By the time it runs, most of its events are outside the window and will be rejected. Offline sync runs nightly, or weekly at the absolute outside.
- For sales cycles longer than a week, send the close event at close time with the close timestamp. Do not try to backdate it to the original lead date to make the attribution look tidier. It will be rejected.
- Batching needs real error handling. Up to a thousand events go per request, and if one event fails the entire batch fails. Build isolation and retry for the individual failing event rather than blindly resending.
The six silent failures
This is the list we work through before any account goes live. Each one produces confident, wrong numbers rather than an error.
- Conversions recorded, none attributed. The click identifier was stripped between the ad click and the landing page. Audit redirect chains, link shorteners, consent gateways, and geo-routers. This one gets working campaigns cancelled.
- Counts roughly doubled. Deduplication IDs not matching across surfaces, or a standalone image tag firing alongside the pixel. Your reported cost per acquisition is half of reality, so you scale into a loss.
- Match rate far below expectation. Usually a normalization error producing valid-looking hashes that match nothing. Worse than sending no data at all, because it hides the problem behind apparently functioning plumbing.
- European traffic converting but not reporting. Consent set after initialization. Those events are gone.
- An entire batch rejected. One malformed event, or a timestamp outside the seven-day window.
- Silent failure on a hardened site. A Content Security Policy missing a directive, most often the one governing script elements specifically. Zero data from your most security-conscious property, with no error anyone sees.
Normalization, briefly, because it is where the quiet damage happens
Customer matching relies on hashed identifiers, and a hash of incorrectly normalized input is still a perfectly valid hash. It just never matches anything. The rules are unglamorous and they are not optional: emails trimmed and lowercased, phone numbers reduced to international digits with the country code retained, external IDs trimmed only with case preserved, names lowercased with whitespace and ASCII punctuation removed but non-ASCII characters left intact.
That last one catches people. A name with an accent should keep the accent. Stripping it produces a hash that will never match the record it was meant to match.
What we will not put in a report
View-through conversions sit in a fixed one-day window after an ad impression, and the platform itself excludes them from its Conversions metric. Cost per acquisition, bidding, billing, and conversion optimization all remain click-based.
So in a report, view-through is directional color in a secondary section. It is never the number an engagement is judged on. We put that in writing at kickoff, before the first report lands, because the alternative is an awkward conversation in month three about why the good number was never the real number.
Validate in this order
- Run a representative Conversions API batch in validation mode and fix everything it flags before sending anything live.
- Run the pixel in debug mode in staging and inspect the activity in the browser console.
- Take a live test click from an actual ad. Confirm the click identifier is present in the landing URL, that the cookies are set, and that your server receives the browser reference.
- Put a single test purchase through and confirm it appears once. Not twice.
None of this is difficult. It is just easy to skip, and skipping it is the difference between a channel you can make decisions about and a channel you have opinions about.
Want to know where your category stands? We will check it and tell you in a business day.
Check my categoryQuick answers
The short versions
How do you track ChatGPT ad conversions?
Use a server-side Conversions API as the system of record with a JavaScript pixel alongside it, both sending the same deduplication identifier. Pixel-only builds lose events to ad blockers and script failures. API-only builds forfeit automatic click identifier capture and the browser reference used for hybrid matching, which degrades match rate without a visible error.
Why do ChatGPT ad conversions show as unattributed?
The most common cause is the click identifier being stripped from the landing page URL before the pixel can read it. Redirect chains, link shorteners, consent gateways, and geo-routers all do this. The conversion is recorded but cannot be tied back to the ad click, so the campaign appears to have failed entirely.
Can offline and CRM conversions be sent to ChatGPT Ads?
Yes. The Conversions API accepts offline, physical store, phone call, and email action sources, so closed-won CRM outcomes can be fed back. The constraint is that event timestamps must fall within the last seven days, which makes a monthly export useless and a nightly sync necessary.