Ads in ChatGPT: reverse-engineering which ones get shown
On this page
OpenAI’s ad payload answers one question (what did ChatGPT serve?) and quietly hides another: what did the user actually see? Those are not the same number. Ads in ChatGPT are served as candidates in a result.ads[] array, but the chat interface renders at most one visible card per answer. Everything else is served-but-not-shown: paid inventory the model considered and dropped before it reached the screen.
This post reverse-engineers the gap from our analysis of cloro’s own data on ads in ChatGPT. We measured how often a served ad is actually rendered, how often “multiple ads” is really one ad re-emitted, how often OpenAI hides an ad, and, when two advertisers genuinely compete, which one the interface picks. The last question has a clean, content-based answer.
The figures come from cloro’s own measurements across millions of ChatGPT responses, not a census of all of ChatGPT: ads concentrate in the US, Canada, Australia, and Japan, and the prompt mix skews commercial.
Who sees ads in ChatGPT, and who can buy them
If you are getting ads in ChatGPT, you are on a Free or Go plan. Per OpenAI’s help center, Plus, Pro, Business, Enterprise, and Edu accounts do not get ads, and accounts identified as belonging to people under 18 do not either. The test began in the US on February 9, 2026, and ads appear below the end of a response, labeled as sponsored. OpenAI says the reason is cost: ads help pay for the infrastructure behind the Free and Go plans.
Any business can put ads in ChatGPT through OpenAI’s self-serve Ads Manager, with sales support for larger advertisers. Our guide on how to advertise on ChatGPT covers the setup. The rest of this post is about what happens after the ad is bought.
Served is not shown
A ChatGPT response can carry more paid inventory than the user ever sees. The result.ads[] array is OpenAI’s serve decision: the ad candidates the auction returned for that prompt. The visible card under the answer is the show decision, a client-side render that keeps at most one ad and drops the rest.
For anyone measuring ads in ChatGPT, this matters. If you count the length of result.ads[], you are counting what was served, not what was seen. Impression-weighted exposure (the number an advertiser actually cares about) needs the show decision, and the show decision is not a field in the served payload. You have to recover it from the rendered DOM.
What “served but not shown” looks like
Say you ask ChatGPT, “How do I clean Nike Air Max sneakers without damaging them?” The API response comes back with a result.ads[] array that is not empty. OpenAI served an ad for a shoe-care brand:
"ads": [
{
"brand": { "name": "Wolf & Shepherd", "url": "https://wolfandshepherd.com/?utm_source=chatgpt.com" },
"cards": [{ "title": "Sneaker Shoe Care Kit", "image": "https://bzrcdn.openai.com/…webp" }],
"visibility": "allowed",
"adsResponseIndex": 0,
"rendered": false
}
]
The ad sits right there in the payload. But read the answer the user actually saw, and no Sponsored card appears anywhere in it, from Wolf & Shepherd or anyone else. The rendered: false flag settles it: OpenAI served the ad, the interface never drew it. Count the response as an ad served, not an ad seen.
This happens even when the ad fits the question. A shoe-care ad against a shoe-cleaning prompt is a close match, and it still didn’t show. Serving is the auction’s call; showing is a separate decision the interface makes as it builds the answer.
Now the opposite. Ask “what’s the best outbound sales platform right now?” and the response serves JustCall. This time the answer displays its Sponsored card, so the ad carries rendered: true. Same result.ads[] shape, opposite outcome for the reader. The one field that tells the two apart is rendered.
How we read visibility and rendered
Two fields on each ad carry the story, and they come from different places.
visibility is OpenAI’s own call, passed straight through. Every served ad in the SSE stream carries a visibility.status of allowed or hidden, where hidden means OpenAI’s integrity checks filtered the ad. cloro copies that value onto the ad; it does not decide it. In practice the value is almost always allowed.
rendered is cloro’s own measurement, because the payload never says which ad the page drew. cloro reads the rendered HTML for a data-testid="image-card-v2-elevated-brand" element. That tag sits only on a real Sponsored card, not on the served-ad JSON embedded elsewhere in the page, and it holds whether the visible label reads “Sponsored” or “광고”. Its text is the advertiser name. An ad is rendered: true when its advertiser matches one of those cards, and false when it does not. The read is time-bounded, so a stalled page marks nothing rendered rather than hanging the scrape.
So visibility answers “did OpenAI allow the ad?” and rendered answers “did the user see it?” Those are separate questions, which is why an ad can be allowed and still rendered: false.
Finding 1: being served does not mean your ad was seen

Across 3.25M ad-bearing responses, about 87% rendered a visible ad card and roughly 13% were served but never shown. When a single ad is served, which is most cases, it renders ~87% of the time; the rest are counts no user ever saw. That ~13% gap is the single most important correction to make when you measure ads in ChatGPT: roughly one in eight served ads is never seen.

Finding 2: plan for one visible ad per answer, not a list
ChatGPT’s ad surface is single-slot by design, and the data agrees: only ~4.2% of ad-bearing responses serve more than one distinct advertiser. Three advertisers show up in about 1 in 4,000 responses, and four is a genuine rarity: we found four in a week of traffic.
“At most one shown” is the right intuition but slightly too strong. Among two-advertiser responses:
| Cards rendered | Share of two-advertiser responses |
|---|---|
| One card | 82.9% |
| Zero cards | 12.7% |
| Both cards | 4.4% |

So the interface usually shows one, sometimes shows none, and occasionally shows two. Treating result.ads[] as a one-per-response impression log is wrong in both directions: it overstates when an ad is served and not shown, and understates in the rare case where two render. Plan the media budget around a single visible slot, and read a two-advertiser response as a coin toss you probably lost.
Finding 3: one placement can be counted three times
Here is what makes naive ad counting wrong. ChatGPT re-emits the same ad several times as the answer streams, each copy carrying a fresh ads_response_index. A response that shows one ad can contain three identical type:"ads" events with indices 0, 1, and 2.
In cloro’s data, 5.1% of ad-bearing responses re-emit a single advertiser this way. If you de-duplicate on ads_response_index, you keep all three copies and report three ads where the user saw one.
This is a real trap. A parser that keys on ads_response_index, which differs across the re-emissions, reports three identical entries in result.ads[] for one placement. On the 5.1% of responses where it fires, that triples the reach you report for a single card. De-duplicate on the advertiser and creative content instead (the brand and its cards) and treat ads_response_index as a re-emission counter, not an ad identifier. A single ad, streamed a few times, is still a single ad.
Finding 4: the visibility flag will not tell you what was seen
Each served ad carries a visibility.status. The intuition is that hidden, an ad OpenAI’s integrity checks filtered, might explain the served-but-not-shown gap. It doesn’t. Over 60 days, not one of 8,590 ad-bearing responses in cloro’s data carried a hidden ad event. Every served ad we saw was marked allowed.
That is an important negative result. The gap between served and shown is not OpenAI flagging ads as ineligible in the payload: those almost never reach the response. It is a rendering decision made after the ad is served and marked allowed. If you were planning to infer exposure from visibility.status, don’t. It is nearly always the same value.
Finding 5: the ad that shows is the one the answer talks about
Now the interesting case. When ChatGPT serves two distinct advertisers and shows one, which does it pick? We tested every field in the payload: ad format (image_card_v2 vs product_card_v2), card count, image presence, visibility, even adsResponseIndex. The strongest signal isn’t in the ad payload at all. It’s in the answer.
The rendered advertiser’s brand appears in ChatGPT’s generated answer 61% of the time; the dropped advertiser’s brand appears just 4% of the time. The interface shows the ad for the brand the model actually talked about.
| Served ad | Brand named in the answer |
|---|---|
| The one that rendered | 61% |
| The one that was dropped | 4% |

That resolves into a clean two-part rule:
- When the answer names exactly one of the two advertisers (60% of two-ad responses), that ad renders 96% of the time (43 of 45).
- When it names neither (39%), the interface falls back to serving order: the later-served ad (higher
adsResponseIndex) renders 86% of the time.
The exceptions to the naive order rule give it away. In the ~10% of responses where the earlier-served ad wins, it is consistently the one the answer is about: Expedia rendered over a running-shoe brand for a “Starbucks in Seattle” location query; Gong.io rendered over a lead-gen tool for “best sales outreach tool”; a migration tool rendered for “how to move your Netflix profile.” Order didn’t pick those. Relevance did.
The direction matters. OpenAI states that ads do not influence ChatGPT’s answers and run on systems separate from the chat model. Our data fits that: the answer comes first, and the interface then favors the served ad whose brand the answer already names.
So the selection process is contextual match between the ad and the generated answer, not a fixed slot. adsResponseIndex predicts the winner ~90% only because OpenAI tends to serve the answer-relevant ad later; it is a proxy, not the mechanism. When you need the true answer, the shown ad is the one whose advertiser the model surfaced in its own text, and the rendered DOM is the ground truth for the rest.
What it means for measuring ads in ChatGPT
For an advertiser, the gap between served and shown is money. A brand in result.ads[] won the ad auction; a brand in the rendered card was actually shown. A report built on the served array over-credits ads nobody saw, and the error is not small or random. It counts roughly 13% more exposure than users got, reports three ads for one placement whenever a response re-emits, and, when two advertisers share a response, credits the served-first ad that the interface drops about 90% of the time.
cloro applies the three corrections to its ChatGPT results: result.ads[] is de-duplicated on the advertiser and creative, each ad carries its visibility and adsResponseIndex, and a rendered flag marks the ad the interface actually drew. That turns “what was served” into “what was seen”, the number that matters for exposure.
Winning the ad slot in ChatGPT
If the shown ad is the one ChatGPT names in its answer, the task for advertisers is clear: become the brand the model names for your target prompts. Two ads can win the auction for the same query, but only the one named in the answer is shown. So performance on ads in ChatGPT is as much a visibility problem as a bidding one.
Three things matter:
- Be worth citing for the query. The advertisers that render are the ones the model already treats as a good answer: brands with real authority on the topic and fresh, structured content that AI engines cite. If ChatGPT never names you on its own, buying the slot leaves the choice to serving order.
- Match the product to the intent, not the keyword. A charger brand served against a “best rural carrier” query loses to any advertiser the answer actually discusses. Relevance is judged against the generated answer, which is narrower than the raw prompt.
- Measure the impression, not the serve. Track the
renderedflag, notresult.ads[]length, and watch whether your brand appears in the answer text alongside the card. That overlap is the early sign that your ads in ChatGPT are being seen.
None of this shows up in a served-count report. It surfaces only when you join the ad payload to the answer content, which is the whole reason to measure ads in ChatGPT from the rendered response rather than the served list.
Reproduce it
Everything above about ads in ChatGPT is reproducible. The detection logic is public: check the result.ads[] array for served ads and the image-card-v2-elevated-brand card test id for the rendered one. The ChatGPT ads monitoring guide walks through the detection signals end to end. The ChatGPT ads penetration study tracks how often the surface fires by country. And if you want to place ads rather than measure them, see how to advertise on ChatGPT.

About the author
Ricardo Batista
Founder, cloro
Ricardo is one of the founders and engineers behind its SERP and AI-search scraping infrastructure. Before cloro he scaled a financial comparison site to $7M ARR and ran the full-country operations of a unicorn to $65M ARR, then went back to building. He writes about search engine scraping, generative-engine optimization, and turning live search and AI-answer data into something teams can act on.
Frequently asked questions
Why am I getting ads on ChatGPT?
Because you are on a Free or Go plan. OpenAI shows ads only on those plans, as a way to fund the infrastructure behind them. Plus, Pro, Business, Enterprise, and Edu accounts do not get ads, and neither do accounts OpenAI identifies as belonging to people under 18. Ads appear below the end of a response, labeled as sponsored.
Do ads influence the answers ChatGPT gives?
OpenAI says no: ads run on systems separate from the chat model, and advertisers cannot shape, rank, or alter responses. cloro's data points the same way. When two advertisers are served, the interface shows the one whose brand the answer already names, so the answer picks the ad rather than the ad shaping the answer.
Does ChatGPT show every ad it serves?
No. Ads in ChatGPT are served in the `result.ads[]` array, but the interface renders at most one visible card most of the time. Across 3M+ responses, about 87% of ad-bearing responses actually rendered a card; the other ~13% were served but never shown. Counting the length of `ads[]` overstates real user exposure.
How many ads does ChatGPT show at once?
Usually one. Among two-advertiser responses, 83% show exactly one card, 13% show none, and about 4% show both. ChatGPT serves more than one advertiser in only ~4% of ad-bearing responses (rarely three, almost never four), so the practical answer is one ad per response.
When ChatGPT serves two ads, which one does it show?
The one it talks about. The rendered advertiser's brand appears in ChatGPT's generated answer 61% of the time versus 4% for the dropped ad. When the answer names exactly one of the two advertisers, that ad renders 96% of the time; when it names neither, the later-served ad (higher `adsResponseIndex`) renders about 86%. Serving order predicts the winner ~90% as a proxy, but the real driver is contextual match to the answer.
Why does a ChatGPT response list the same ad multiple times?
It re-emits one ad several times as the answer streams, each copy carrying a higher `ads_response_index`. In cloro's data, 5.1% of ad-bearing responses re-emit a single advertiser this way. De-duplicate on the advertiser and creative, not on `ads_response_index`, or you will double-count one placement.
How can I measure real ChatGPT ad exposure instead of served counts?
Count the ad the interface actually rendered, not the length of `result.ads[]`. cloro detects the rendered card from the response DOM (the `image-card-v2-elevated-brand` card test id, which is locale-independent) and exposes a `rendered` flag per ad. See the technical monitoring guide for the detection logic.
Related reading

ChatGPT Ads Penetration Study: 51% in the US
ChatGPT ads over the last 7 days measure 51.0% of US responses, 53.6% CA, 49.8% AU, and, new since May, 18.8% JP. Everywhere else remains near zero. The surface reverted then re-spiked in June and now looks structural, not transient.

How to Monitor ChatGPT Ads (Technical Guide, 2026)
ChatGPT ads render as a `response.result.ads[]` array on the response, served from `bzrcdn.openai.com` and tagged `utm_source=chatgpt.com&utm_medium=src`. Here's how to detect them with cloro's API and build a real monitoring pipeline.

How to Advertise on ChatGPT: Self-Serve Ads Manager Guide (2026)
OpenAI's self-serve Ads Manager opened ChatGPT ads to any eligible business from a $25 daily budget, after a direct-sales pilot with a $200K minimum. Here's how to set up a campaign, what CPCs run, and what the pilot taught advertisers.