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 Conversions API
| Pixel | Conversions API | |
|---|---|---|
| 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.
The Conversions API sends events from your server and is more
reliable than the pixel alone. If you use both, deduplication requires
the same pixel ID, the same event name and the same identifier
(event_id in the pixel, the id field in the API). And server events
must be dated within the last 7 days, and no more than 10 minutes in the
future.
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 API rejected the entire batch: sign-up requires
customer_action (more in module 17 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).
| 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; Conversions API if you
convert on another domain or on the server. With both, use the same
identifier (
event_idin the pixel,idin the API). - 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.