ChatGPT Ads gives you aggregated data and not a word of what the user typed: there is no report of conversations or queries. If you don't measure on your side from the first click, you are flying blind. And in Europe, the pixel comes with a trap built in.
Pixel or sending from your server
| Pixel | Sending from your server | |
|---|---|---|
| Where it lives | In your website's <head> |
On your server |
| When | You convert on the site with the pixel | You convert on another domain or on the server |
The oppref |
Captured automatically | You capture and send it |
The pixel loads from bzrcdn.openai.com and is initialised with
your pixel ID. Watch out: it doesn't measure page views on its own;
you have to ask for them with oaiq("measure", "page_viewed"). To test
it, turn on debug: true.
Sending from your server is set up by whoever handles your development, using OpenAI's documentation, and it is more reliable than the pixel alone. If you use both, deduplication requires the same pixel, the same event name and the same identifier, which you decide. And the event must be dated within the last 7 days: older than that, it gets rejected.
Our case: sign-up is completed in our panel, a different domain with no pixel, so the conversion is sent from the server.
The oppref: the thread between click and conversion
It is the click identifier: it arrives in the URL, and the pixel stores
it in the first-party cookie __oppref. If you go server-side,
capture it on arrival and carry it through unchanged to the event.
We store it on the website when the visitor lands and send it with the
sign-up, together with the SHA-256-hashed email.
⚠️ Pitfall: a SHA-256-hashed email is still personal data, and our privacy policy says so. And watch the pixel's automatic advanced matching: it detects customer data on your site and hashes it in the browser; the documentation doesn't explain how to turn it off.
The events that matter
| Event | What it measures |
|---|---|
registration_completed |
Sign-up |
lead_created |
Lead |
appointment_scheduled |
Appointment |
order_created |
Purchase |
subscription_created / trial_started |
Subscription / trial |
page_viewed |
Page view (you trigger it) |
Three rules: value and currency go together; a custom event (custom)
needs a name of 1 to 64 letters, numbers, hyphens or underscores that
starts and ends with a letter or number and doesn't match a standard
event's name; and each event requires its own data type. We sent a
sign-up with a purchase's data type, copied from the official example,
and the whole submission was rejected, not just that event (more in
the measurement module of the Advanced level).
A Conversions campaign needs exactly one active standard event (custom events don't count) and enough volume.
💡 Ninja trick: even if you start with Clicks, measure the event you would use for Conversions right away: when you want to make the jump, you'll know whether you have the volume (and it will be a new campaign).
Consent: in Europe, start at "no"
The pixel starts with consent set to true. In Europe, call
oaiq("consent", false) before initialising it and change it when the
user accepts in your cookie banner. With false nothing is sent, and
whatever was blocked is not resent later: some clicks will never
show up in your measurement.
One UTM per ad
Static UTMs in the URL carry through on the click: give each ad its own
utm_content and your analytics will tell you which ad brings which
visits and conversions. Two warnings from our own account:
- During the review we were visited by OAI-AdsBot, OAI-SearchBot and ChatGPT-User. They are not customers.
- Our analytics counted our own automated checks of the ad URLs as people arriving from the ad. We filter them out by requiring a browser to confirm the visit.
What the report shows, and when
Impressions, clicks, spend, CTR, average CPC, average CPM and conversions; by account, campaign, ad group or ad; by hour, day, month or total; and with only one breakdown at a time (product, country, device or platform).
But not every metric is available in every cut, and that changes what you can decide:
| How you look at it | What you actually get |
|---|---|
| By day, at any level | Everything: impressions, clicks, spend, CTR, CPC and conversions |
| By hour | Impressions, clicks and spend. There are no conversions by hour |
| With a breakdown (country, device, platform) | Impressions only. No clicks, no spend, no conversions |
Checked in our own account: when you ask for the platform breakdown, the impressions do split up (6,610 on desktop web, 2,086 in the iOS app, 1,316 in the Android app…) and they add up to the total; the clicks and spend columns, on the other hand, do not come split out.
⚠️ And here is the trap to see coming: a zero and a figure that does not exist look very much alike. If a table by country shows you "0 clicks · €0.00 · 0 conversions", it does not mean that country brings no clicks: it means that figure is not there. Read it as a gap, never as a measurement — and distrust any report that presents it to you as a zero.
| Data | When it arrives |
|---|---|
| Impressions, clicks and CTR | Within minutes |
| Spend | Later: zero spend doesn't mean there are no charges |
| Conversions | Daily processing: at least a day |
The first week
- Any impressions? If not, check the reviews, ad status, pauses, budget, spend cap and bid (lesson 2).
- Are events firing? Check with
debug: trueand wait at least a day to see them in the report. - Which ad has the best CTR? Note it down, but don't decide yet.
- Do clicks and visits match? Not quite: consent, bots and links that drop parameters explain part of the gap.
- Don't judge today's spend: it arrives late.
What to remember
- Pixel if you convert on your website; sending from the server if you convert on another domain or the conversion happens later. With both, the same identifier, decided by you.
- The
oppreflinks click and conversion: server-side, capture it and carry it through. - In Europe, consent set to
falseuntil the user accepts. - One UTM per ad, and filter out bots and your own checks.
- Impressions in minutes, spend later, conversions the next day at the earliest. And there is no query report.