This is the module's most uncomfortable lesson: our campaign, with its real numbers and its dates. Everything below was measured in the Ninja Scripts account or in our own analytics. No industry averages, no client cases: just what happened, zeros included, with the date on which each number was true — and one of those zeros turned out to be our own fault, so that is told here too. On 16/10 we corrected another reading of ours, the one about robots, and the correction carries its date.
The diary is CLOSED: the campaign was stopped on 8 October 2026, and the why, with the arithmetic that settles it, is at the end. It is told in full and in order because the decisions along the way were taken without knowing how it ended, which is the situation you will be in.
The setup
A deliberately simple campaign, so we could understand whatever happened:
| Setting | Value |
|---|---|
| Objective | Clicks |
| Budget | $25/day (the account's minimum, see below) |
| Country | Spain |
| Context hints | 4, generated by the Ads Manager itself |
| Conversion event | 1 (sign-up in the panel) |
| Ads | 8 |
The $25/day was not a choice of ours: it is the minimum daily budget that account accepts, and we learned it by having the platform reject lower figures. It is not published anywhere and it is not the same for every account: in an account we manage that is billed in euros, the minimum is 15. It is worth knowing yours BEFORE you split a budget across campaigns (the "Bidding and budgets in ChatGPT Ads" lesson covers it).
⚠️ The trap we fell into: 7 of the 8 ads pointed to pages with no measurement installed. You can build a campaign in an afternoon; measurement has to be in place BEFORE the first impression, or the first day of data is lost forever.
The days before · All approved, nothing live
The 8 ads were approved, with no low-bid warning, and the campaign was not serving. Not one impression. The cause was not in the ads but in the account brand review, approved on 16/09/2026 at around 11:30. A cheap lesson: when everything looks right and nothing delivers, check the account reviews (see "Brand, policies and reviews: how to stay out of trouble").
17/09/2026 · First day serving
| Metric | What we saw that day | What was really there |
|---|---|---|
| Impressions | 4,024 | 4,024 ✅ |
| Clicks | 0 | 21 |
| Spend | €0 | $49.32 |
We took that "0 clicks · €0" at face value for four days, and it was a fault in our own measurement. It is told in full a few lines below, because it is the most expensive lesson in this diary.
What was true about the first day: 4,024 impressions and 21 clicks make a CTR of 0.52%. Very few people tapping, which is worse news than it sounds, not better.
Where they were seen:
| Surface | Impressions |
|---|---|
| iOS app | 2,076 |
| Android app | 1,314 |
| Desktop web | 548 |
| iOS web | 49 |
| Android web | 37 |
In short: 3,476 on mobile against 548 on desktop. (These five figures add up to exactly the day's 4,024, but that was not always the case: with the data badly requested, the breakdown could end up not matching the total, because each one is requested separately and with its own period. If it happens to you, check the dates before believing in a mismatch.)
Which ad took the shop window:
| Ad | Impressions | Clicks |
|---|---|---|
| One-month demo | 2,109 | 16 |
| Ninja Academy | 592 | 0 |
| Ebook · The eternal ad | 513 | 2 |
| Weekly news | 188 | 0 |
| Guardian script (free) | 187 | 1 |
| Ebook · AI Max, the black box | 161 | 1 |
| AI Max Analyzer script (free) | 141 | 0 |
| Ebook · Quality Score | 133 | 1 |
Over half the impressions went to the ad that demands the most effort: trying a script for a month, which means creating an account and installing it in Google Ads. A desktop job, served mostly in the mobile app.
And the clicks column is the one we could not see until 21/09: 16 of the day's 21 clicks went to that same ad, while "Ninja Academy" ate 592 impressions without a single click. With the split in view, the platform was mostly showing the ad that got tapped the most — it was doing its job; the problem was on the other side of the click.
17/09/2026 · What we measured ourselves
What the platform counts is one thing; what reaches your site, another:
| Metric (our analytics, bots excluded) | Value |
|---|---|
| People | 19 |
| On mobile | 16 of 19 |
| Arrived between 2:00 and 5:00 | 17 of 19 |
| Time on page (median) | 2 seconds |
| Left without reading anything | 37% |
| Sign-ups | 0 |
As an internal benchmark from the same month: people arriving at our site from social media spent almost 3 minutes and only 10% left without reading. This is not a "bad traffic" problem: it is a fit problem.
💡 Ninja tip: that night also brought about 40 visits from OpenAI's crawlers and about 25 from automated link checks. Without filtering them, the traffic looked bigger and even worse. Filter bots before you pass judgement on quality.
One important caveat about the hours: the concentration between 2:00 and 5:00 is what the report gives in the account's time zone. We do not assume that is local time: it has to be confirmed before taking any scheduling decision.
17/09/2026, 19:09 · The decision
With those numbers, and knowing one day is not a conclusion, we limited the campaign to desktop and to office hours (Mon-Fri, 9:00-18:00). It is a hypothesis, not a verdict: our audience manages campaigns at work and at a computer. It is logged with its date so it can be judged in two weeks against comparable working days.
18/09/2026 · The move to desktop showed the very next day
The surface breakdown of the following day, with the campaign already limited:
| Surface | 17/09 | 18/09 |
|---|---|---|
| Desktop web | 548 | 2,936 |
| iOS app | 2,076 | 5 |
| Android app | 1,314 | 2 |
From 548 impressions on desktop to 2,936, and mobile all but disappears from the split. A platform change takes effect the same day here: there is no learning period to wait for. Whether it improves the outcome is another matter: that took us two weeks to be able to say (below).
18/09/2026 · The first accepted conversion
Until that day, OpenAI's conversion setup screen still said pending, and the reason was not a misconfigured setting: no conversion had ever arrived. Our first send was being rejected because of how we declared the event: we sent it as a web event, and that requires stating the URL where it happened. That particular sign-up arrived with no known landing page.
The fix was to stop declaring it as a web event, rather than invent a URL. With that, the first conversion was accepted on 18/09/2026. Making the data up would have worked just as well — and would have dirtied the measurement forever.
21/09/2026 · 🚩 That "0 clicks · €0" was OUR fault
Four days later, opening the Ads Manager for something else, the numbers did not add up: the platform said 53 clicks and $82.98 where our own panel still showed 0 and 0. The impressions, on the other hand, matched almost exactly. It was not a data delay nor a platform error: it was the way we asked for the report.
When a tool reads these reports automatically, you have to explicitly ask for the columns you want. If you do not ask, the platform returns the row with the impressions and nothing else: no clicks, no spend, no conversions. We never asked for them, so we had been storing zeros where there was money since day one.
Once fixed, the data window was rewritten in full and the history appeared on its own:
| Day | What we had stored | What was there |
|---|---|---|
| 17/09 | 4,024 impr · 0 clicks · €0 | 4,024 impr · 21 clicks · $49.32 |
| 18/09 | 2,943 impr · 0 clicks · €0 | 2,943 impr · 15 clicks · $33.66 |
⚠️ This is what to take away, because it can happen to anyone: a zero and a figure you did not ask for look exactly the same. For four days we believed the campaign could not get a single click, when what it could not get was our panel to read the clicks. If you use your own tool or a third-party one to look at these reports, check it once against the Ads Manager: if the two figures disagree, the one lying is yours.
And an uncomfortable consequence worth saying: we took the decision of 17/09 on a false figure. It still looks like the right decision for other reasons (the 2-second time on page, an audience that manages campaigns at a computer), but we took it believing there was not a single click when there were 21.
01/10/2026 · The first two weeks, with the right numbers
Fifteen days of campaign (17/09 → 01/10), now with the measurement fixed:
| Metric | Value |
|---|---|
| Impressions | 32,126 |
| Clicks | 219 |
| CTR | 0.68% |
| Spend | $349.05 |
| Average CPC | $1.59 |
| Conversions (the ones the platform counts) | 4 |
| Cost per conversion | $87.26 |
Our stated cost-per-conversion target is $10. We are paying eight and a half times that. Said plainly: at this price the campaign is not profitable, and that is the honest conclusion of the first two weeks.
What did improve: the CTR. Comparing the first day (on mobile) with everything that came after it (on desktop):
| 17/09 · mobile | 18/09 → 01/10 · desktop | |
|---|---|---|
| Impressions | 4,024 | 28,102 |
| Clicks | 21 | 198 |
| CTR | 0.52% | 0.70% |
The best day was 25/09: 1,661 impressions and 34 clicks, a 2.05% CTR. And the caveat this deserves: it is not a clean experiment. Over those same days we split the campaign into six intent-based ad groups and rebuilt the ads, so part of the improvement may come from that and not from the device. What none of this fixed is the cost per conversion.
And the other side of it: attribution. Of the 109 sign-ups that arrived in the panel over these two weeks, only 4 carried ChatGPT's click identifier. The rest came from search engines, direct visits or another ads platform: they are not from this campaign. That is why the 4 conversions the platform counts line up with the 4 attributable sign-ups, and why the figure that rules is the cost per conversion and not the number of sign-ups in the panel.
Two measurement details that came out of those two weeks and are worth knowing before you live them:
- The 7-day window is real and it shows: of the 107 sign-ups we tried to send as conversions, 59 were left out as too old. An event uploaded more than a week after the fact no longer gets in.
- The schedule has moved three times, and the latest one — Mon-Fri 16:00 to 19:00, since 30/09 — has a section of its own further down, because how the spend splits by hour taught us something we did not expect.
30/09/2026 · The time slot: three tests and a budget that runs out
We have moved the schedule three times, not once, and every change had an idea behind it:
| Since | Slot (Mon-Fri) | The idea |
|---|---|---|
| 17/09 | 9:00-18:00 | our audience manages campaigns while they work |
| 24/09 | 12:00-18:00 | the morning ate the budget in its first hour |
| 30/09 | 16:00-19:00 | test the afternoon, which is when people browse |
The afternoon idea is this: in our industry the morning goes to working and the afternoon leaves room for browsing, so an ad seen at 10:00 is less likely to make anyone stop and look. It is a behavioural hypothesis, and the data is further down.
But the real reason to test short slots is a different one, and it is about method: with the campaign open all day, the budget is spent in the first hours and the rest never get tested at all. Measured across our three slots, working days only:
| Slot | Days | Impressions/day | Clicks/day | CTR | CPC | 1st hour takes |
|---|---|---|---|---|---|---|
| 9:00-18:00 | 4 | 2,719 | 19.5 | 0.72% | $1.95 | 87% of the spend |
| 12:00-18:00 | 4 | 3,473 | 27.5 | 0.79% | $1.12 | 35% of the spend |
| 16:00-19:00 | 1 | 3,291 | 10.0 | 0.30% | $2.51 | 87% of the spend |
Two readings, and the second one changes how you test:
- The best of the three slots has been the midday one: 27.5 clicks a day at $1.12 each, against 19.5 clicks at $1.95 in the morning, and spending less money per day.
- The hour the money goes out is not chosen by the user: you choose it when you open the door. With the 9:00-18:00 slot, 87% of the spend went in the 9:00 hour; with 16:00-19:00, 87% went in the 16:00 hour. Across a nine-hour window, the last five hours shared 1% of the money: the afternoon did not perform badly, it never got tested.
That is why slots are tested one at a time and short. And it is why an "hourly performance" report from a campaign that exhausts its budget does not say what it looks like: the later hours only get the leftovers.
⚠️ Trap: the CTR of the last hours looked brilliant — 1.5% at 16:00 against 0.60% at 9:00. It is a sample mirage: that hour had 136 impressions and the 9:00 one had 9,833. When the budget runs out, few and very selective impressions are served, so the ratio climbs without the hour being any better.
What our own analytics says about the afternoon hypothesis, with 90 days of Spanish visits to our website and bots filtered out:
| Block | Visits | Stay over 1 min | Sign-ups | Sign-ups per visit |
|---|---|---|---|---|
| Morning (8:00-14:00) | 1,336 | 11.5% | 75 | 5.6% |
| Afternoon (14:00-21:00) | 642 | 12.5% | 58 | 9.0% |
In other words: twice as many people come in the morning, and almost twice as many sign up, proportionally, in the afternoon. The hunch half holds — the afternoon does not bring more traffic, it brings more decisions — and it is consistent with the midday slot giving us the lowest cost per click.
Two warnings before copying this into another account: these are two different sources — website visits and panel sign-ups, which arrive through any channel — so that last column is an indication and not a measured conversion rate; and the behaviour of someone inside a ChatGPT conversation does not have to look like the behaviour of someone arriving from a search.
💡 Ninja tip: this change also settled a question we had been carrying since day one: which time zone does the hourly report use? The account's own. The schedule itself proves it: on 30/09 it opened at 16:00 Madrid time — 14:00 UTC — and the report put the spend in the 16:00 hour, not the 14:00 one. The same happened with all three slots, so the hourly map reads in your account's time and there is nothing to guess.
08/10/2026 · 🛑 We stopped it
This is where the campaign ends: it was paused on 8 October. The reason is not a technical fault or a bad run, it is a piece of arithmetic.
| Figure | 17/09 → 08/10 · 19 days serving |
|---|---|
| Impressions | 49,704 |
| Clicks | 304 |
| CTR | 0.61% |
| Spend | $547.46 |
| Average CPC | $1.80 |
| Conversions (the ones the platform counts) | 5 |
| Cost per conversion | $109.49 · stated target: $10 |
| Real sign-ups we measured ourselves | 7 → $78.21 each |
The arithmetic. What this campaign buys is a free sign-up, and a free sign-up can only cost cents: whatever it pays has to come out of the small fraction of registered users who end up subscribing. With our funnel's figures, the ceiling it can bear is €1 per sign-up. The starting click costs $1.80 — nearly twice the whole sign-up we are after, and that is before anyone fills in anything.
When the click already costs more than the result it buys, no amount of optimisation saves the channel: you would need to improve by two orders of magnitude, not by 20%.
The visits confirm it from the other side. Of the 713 paid visits, 358 came in flagged as robots; that left 313 people and 7 signed up, 2.2%. (Those 358 were hardly clicks at all: we explain it in the 16/10 correction, a little further down.) In the same period LinkedIn — paying nothing — brought more people and seven times the sign-ups:
| Channel · same period | People | Sign-ups | Cost |
|---|---|---|---|
| ChatGPT Ads | 313 | 7 | $547.46 |
| LinkedIn, unpaid | 389 | 49 | $0 |
And the trend was not on our side either. The peak was the second week, not the last one:
| Week | CTR | CPC | Conversions |
|---|---|---|---|
| 17 → 19/09 | 0.52% | $2.31 | 0 |
| 21 → 26/09 | 1.08% | $1.25 | 4 |
| 28/09 → 03/10 | 0.45% | $2.32 | 0 |
| 05 → 08/10 | 0.46% | $2.03 | 1 |
A campaign still learning gets better as the days go by. This one had its best week after ten days and then went back to half the CTR with almost double the CPC.
16/10/2026 · 🩺 Correction: the "half robots" were hardly clicks
Until today this lesson said that half the paid traffic were robots. Our analytics' robot flag was right; the conclusion we drew from it was not. We noticed while reading a study from an anti-fraud vendor that was going round that week, which says ChatGPT Ads clicks come from data centers and proxies 3.6 times more often than Google clicks. We went to check it in our own data and, once we split the 358 visits apart, this is what came out:
| What they were | Visits | Did they come from a click? |
|---|---|---|
| OpenAI's own crawlers (OAI-SearchBot and ChatGPT-User) opening the ad URL | 206 | No |
| Our own tools checking the page | 46 | No |
| A data center VPN, browsers with no language set, one visitor who reloaded 42 times and 2 email scanners | 106 | 22 yes |
In other words: 252 of the 358 did not come from any click. OpenAI's crawlers open the ad URL, with all its parameters, to review the page; nobody pays for that. Of the 132 visits that did arrive with OpenAI's click ID, 22 looked invalid (VPNs, hosting networks or browsers with no language set): 17%. That is a figure to keep an eye on, but it is not half.
What does not change: the 313 people, the 7 sign-ups and the decision to stop. What does change is the diagnosis. This campaign's problem was never the robots: it was the price of the click and the low intent of the people arriving.
💡 Ninja tip: before you call a paid visit a robot, set aside the platform's crawlers. They arrive with the ad URL and its parameters, but there is no click behind them. Mixed in with the visits, they make the platform reviewing your page look like fraud.
What money could not fix
With a CTR that had improved, the temptation was to keep tweaking. These are the ceilings we ran into, and not one of them lifts with budget:
- The campaign's objective was "clicks" and it cannot be changed. To move to "conversions" you have to create another campaign, and for it to learn it needs something like 30 conversions a month. We had 5 in 19 days.
- The account's minimum budget was $25/day: there was no way to test cheaper or to stretch the experiment by spending less.
- The ad tests never reached enough sample. All twelve we opened stayed at "not enough data": without volume there is no verdict, and without a verdict there is nothing to improve.
- The people who arrived came with little intent: 7 of 313 signed up, 2.2%, and that is not something you negotiate with a bid. (The first version of this lesson said here that half the traffic were robots; it was not so, as the 16/10 correction explains.)
What was NOT the problem: relevance. Every group's relevance index sat between 67 and 98 out of 100 — ads, context hints and landing pages were all talking about the same thing. Had the channel failed there, it would have been fixable.
Where there was room, so it is clear this was not for lack of looking:
| Group | Spend | CTR | CPC | Conversions |
|---|---|---|---|---|
| ChatGPT Ads course | $104.62 | 1.32% | $1.04 | 3 |
| What's new | $110.06 | 0.44% | $2.29 | 2 |
| Suite demo | $233.29 | 0.47% | $2.26 | 0 |
| Free ebooks | $98.11 | 0.58% | $1.92 | 0 |
One group genuinely worked — the course one: three times the CTR and half the CPC of the account average — and another took 43% of the spend without a single conversion. The optimistic scenario was obvious: put everything into the good group. But its measured cost per conversion is $34.87, that is 35 times the €1 ceiling. Not even the best possible case got there, and that is why the decision was not "let's optimise" but "let's stop".
What we still do not know
Four of the questions we kept leaving open now have an answer, and they are worth seeing together:
| What we were asking | What we know |
|---|---|
| Why do 4,024 impressions produce 0 clicks? | The question was wrong: they produced 21. The real CTR sits between 0.45% and 1.08% depending on the week |
| Does limiting to desktop improve anything? | The CTR does (0.52% → 0.70%), though we changed more than one thing at once |
| What does a conversion cost here? | $109.49, against a $10 target. And a sign-up, $78.21 |
| What is "the account's time"? | Confirmed: it is the account's zone, not UTC. The 30/09 schedule change proved it |
| Can the cost be brought down to something defensible? | Not in this account. Not even the best group, at $34.87 per conversion, comes close to the €1 ceiling |
And what is left unanswered, because the campaign stopped first:
- How much of the CTR improvement was the desktop and how much was having split the campaign into six intent-based groups. We changed both at once and there will be no way to separate them now.
- Whether the course group, on its own and with the whole budget, would have scaled while keeping its $1.04 CPC. It was never tested.
- Whether the short afternoon slot performed better than the midday one.
- How long attribution takes to settle: with 5 conversions nothing can be judged with confidence.
What we take away from this
The diary closes, but with five things that apply to any new channel you try:
- Work out the ceiling BEFORE you open the campaign. If what you are buying is a free sign-up, write down what it is allowed to cost. We set that number afterwards, and it — €1 per sign-up — would have ruled the channel out on day one just by looking at the starting CPC.
- The starting CPC already tells you most of it. You do not need to wait for the cost per conversion: if one click costs more than the result it buys, the rest of the analysis is decoration.
- Measure it yourself, do not rely on the platform alone. It counted 5 conversions; we counted 7 sign-ups. Neither figure is redundant: one says what the channel attributes, the other what actually came in.
- Compare it with what you already have, not with zero. A cost per sign-up is neither expensive nor cheap in a vacuum: it is so next to the channels that already work. LinkedIn's 49 free sign-ups were the real verdict.
- A channel that does not add up is not a failure of the channel. ChatGPT Ads does what it promises: it puts ads inside the conversation and charges its price for them. What does not add up is that price against our funnel. Another advertiser, with a high ticket and a direct sale, may have a very different account — and this lesson says nothing about theirs.
And the decision, with no dressing up: we stopped. Zeros get told just like wins, and this diary ends in one — with the exact number, the date and the why.