ChatGPT Ads clicks vs GA4 sessions: why they never match, and how to reconcile them
Ads Manager says 1,000 clicks, GA4 says 400 sessions. Three separate gaps sit between those numbers. How to tell platform over-counting from your own attribution loss.
In early September an advertiser posted numbers on r/PPC that I keep coming back to. About 70% of their ChatGPT Ads clicks were recorded as a page-view conversion by OpenAI's pixel. Then, per ad group, GA4 saw 97%, 63% and 39% of what the platform reported. Same campaign, same UTMs, three different gaps. The thread.
The 70% isn't interesting. The spread is, because it's diagnosable.
Where clicks go missing
I owe the framing here to a reply in that thread from someone who does support for a Shopify tracking app, and whose day job is apparently explaining to merchants why two dashboards disagree. Their point: a click is counted at the ad, a page view is counted on your site, and clicks never reconcile to page views on any platform because everything in between eats some of them. People who back out before the page renders. A phone that dropped signal on the tap. A blocker. A prefetch that registers the click without a visit. The tracking-app reply calls the poster's 30 percent loss here unremarkable, and it's the part you can't do much about.
The second loss is between the page and the tag. The page arrived, but GA4 didn't run, or ran without permission to store anything. In Europe that's the consent banner: if analytics storage is denied when the tag fires you get nothing, or a cookieless hit that never becomes a session in the reports you look at. This one varies by country and device and it's entirely on your side.
The third is between the tag and the attribution, and it's the one that produces a spread like 97/63/39. A session exists, GA4 just couldn't tie it to the campaign, because the parameters weren't on the URL when the tag ran. Redirect chains strip them. Country and language routers strip them. App-generated landing pages don't carry them. The poster controlled for parameters but not for the destination, so my guess is that one ad group lands behind a redirect or a router. They didn't say and I haven't asked, so that's a hypothesis, and it's the same one the tracking-app reply reached.
One thing not to lean on is the referrer. Plenty of ChatGPT link traffic shows up in GA4 as direct because there's no usable referrer (why that happens), and as far as I can find in its help center and developer docs, OpenAI hasn't documented referrer behaviour for ad clicks specifically. Tag the URL and don't find out the hard way.
What each number is
Ads Manager clicks: OpenAI's count of "valid" clicks, which is also what it bills on for click campaigns. As far as I can find, it doesn't publish how validity is decided.
Ads Manager conversions: events from the OpenAI Pixel or the Conversions API that the platform could attribute to an ad inside the window you chose. Click windows are selectable (7, 14 or 30 days), view-through is 0 or 1 day, attribution is last-touch and the choice only affects reporting. Attribution can use the click reference, hashed customer data you send (advanced matching, or the pixel's automatic version), and, where available, modeling from aggregate patterns. The help center says reported totals "may include modeled conversions", and with the 1-day view window they include view-through conversions too. Which I hadn't taken in until I reread the measurement page for this post: the platform number can contain conversions no click ever touched.
GA4 sessions: sessions the GA4 tag started, with a campaign attached only if the parameters were on the URL and storage was allowed at that moment.
OpenAI's Measure Results page has an FAQ titled, more or less, why do Ads clicks differ from Google Analytics sessions. Its list: page load, redirects, consent settings, browser blocking, UTM handling, attribution windows, time zone settings. The Conversion Measurement page adds deduplication and modeling and ends with "A difference does not necessarily indicate an error." I'd have written that sentence too.
The tie-breaker
The neatest resolution I've seen is in the thread on measuring the European expansion, from a reply that says, roughly, settle the click count before any metric, because the two numbers being compared aren't the same number. Their instrument is the server access log. It records every request that reached your origin before a consent banner or a blocker had a say, so it sits between the first loss and the second.
For a fixed window and one landing URL, pull platform clicks from Ads Manager, raw requests for the landing path with your campaign parameters from the server or CDN log, and GA4 sessions attributed to the campaign. Log close to platform but GA4 short: the traffic arrived and your measurement lost it. Log well short of platform: the platform is counting clicks that never reached you, and the destination URL is the first suspect. If the log is somewhere in the middle, the CDN is probably counting bot prefetches too, and you'll want to filter by user agent before drawing conclusions.
For the ad-group spread, the tracking-app reply's test: put GA4 page views for the landing URL next to GA4 sessions attributed to the campaign. Page views close to the platform number but sessions short means only attribution is missing, so parameters were stripped. Page views also short means the tag isn't running for part of the traffic.
Setting it up
This is the setup for the campaign Serge intends to run, which is drafted but not built in the account yet; the September campaign whose ad was rejected is a different one and stays paused. I'll come back and say what broke if and when it runs.
Static UTMs on the landing URL, one utm_source and one utm_medium for the channel, identical across ad groups. Ours: utm_source=chatgpt&utm_medium=paid. OpenAI's help center says static parameters persist on ad clicks, and there are dynamic macros for campaign, ad group, ad and account ids if you want them.
No redirect between the ad and the page. No www hop, no HTTP-to-HTTPS hop, no country router. Every hop can lose the parameters, and it can lose the click reference too, because OpenAI appends oppref to the landing URL as a query parameter on click. Test the final URL in an incognito window with consent declined.
The OpenAI Pixel in the browser. Initialize with the Pixel ID, call it on the conversion. The developer docs are explicit that you never call the server-side Conversions API from page code. A tag manager is fine if it doesn't block or reorder the init and event calls. The pixel reads oppref off the URL and stores it in a first-party __oppref cookie; it also has its own consent switch, so if you gate it behind the banner, the platform loses conversions from declined visitors the same way GA4 does.
If you send conversions server-side as well, include oppref when you have it, and for the hybrid setup read the separate __obref cookie in the browser, send it to your server, and pass it unchanged in the user object of the Conversions API event. Send the same conversion both ways with the same event ID and OpenAI deduplicates. Without a click reference OpenAI falls back on hashed customer data or modeling to match the event.
A standard event if you want conversion bidding; custom events can't be the optimization goal.
And expect lag. Impressions, clicks and CTR within minutes; other reporting can take up to seven hours; attributed conversions 24 to 48 hours. A displayed zero spend doesn't mean nothing was charged, and spend can accrue for up to 24 hours after you pause.
The report, once it reconciles
Platform clicks and spend. Landing requests from the log as a share of clicks. GA4 sessions attributed as a share of landing requests. Outcomes counted by your own system, by channel, split new versus returning. Four lines. The fourth is the one that says whether the channel was worth it and the one most people never build.
What this can't tell you
Matching a click to a conversion is attribution. It says someone who clicked later did the thing; it doesn't say the click caused it, and a placement this close to the moment of decision is where last-click flatters. If they already had you shortlisted, the ad intercepted a decision. The only way to know is a holdout, a country or a period without the ads compared against your own numbers, and with OpenAI now counting post-view conversions the holdout has to exclude those too. It's pointless before the counts reconcile. We haven't run one. Nobody in the threads has either.
Sources
- OpenAI Help Center, Ads in ChatGPT: The Basics, "Tracking and measurement".
- OpenAI Help Center, Conversion Measurement (
oppref, advanced matching, modeled conversions, why totals differ), Measure Results (attribution windows, the clicks-vs-sessions FAQ, reporting lag), Billing & Payment (spend after a pause), Troubleshooting Common Issues. - OpenAI Developers, Measurement Pixel and Conversions API.
- r/PPC, Open AI Ad Platform Metrics Vs GA4 and ChatGPT Ads is expanding to 31 European markets.
More from the blog
- ChatGPT Ads context hints: what they do, what they don't, and how to write themResearch · September 17, 2026
- Your first ChatGPT Ads campaign: budget types, bids, review delays, and a stop ruleResearch · September 17, 2026
- How to write a ChatGPT ad: 50-character titles, 100-character copy, and the review rulesResearch · September 17, 2026
Start with your website.
Serge turns it into a ChatGPT ad campaign you review before deciding what to spend, from the ad account you own. Free to prepare.
Start my first campaign