On this page
The short version
- Leaving branded queries in the pool overstated non-branded CTR by 2.6x at position 1 and 3.2x at position 3, on a real 36,277-query export.
- Pooling hands each position to whichever query has the most impressions, and one query held 67% of a bucket, which is what makes a pooled curve rise as ranking gets worse.
- On 42 million impressions, an interval built on impressions rather than queries came out roughly ten times too narrow, because impressions cluster inside queries.
- Gradient boosting cannot extrapolate at all: trained on positions 1 to 8, it returned one frozen value for every position out to 20.
Every organic traffic forecast rests on a click-through rate curve, and most of them borrow one. Borrowing is the problem. On a real 36,277-query Search Console export I rebuilt the curve from scratch, then broke it three ways on purpose to find out what the borrowed version costs. Blending branded and non-branded queries together overstated position 1 by 2.6 times and position 3 by 3.2 times. Inside one position, a single query held 67% of the impressions, which made the pooled curve climb as ranking got worse. Then there is gradient boosting, the obvious reach for anyone holding this much data, which turned out structurally incapable of the one thing a curve exists for. If your forecast says a move from position 7 to position 3 pays for a quarter of engineering, these are the three places that number breaks.
On a 36,277-query export, blending branded queries into the pool overstated non-branded click-through rate by 2.6x at position 1 and 3.2x at position 3.
There is a reason this matters more now than when the method was written. Back in July, Google said its AI features send billions of clicks to the web every week while Cloudflare measured human traffic to publishers falling roughly 40% in under a year, and neither figure can be checked against your own site data. When the platform-level numbers are contested, a curve you measured on your own property stops being a refinement and becomes the only ground you have.
Seer Interactive’s walkthrough is the piece everyone links, and its central instruction is right.1 Within a position bucket, sum the clicks and sum the impressions, then divide. Averaging each query’s own rate instead lets a nine-impression query count as much as a nine-million-impression one. That part I kept. Where it stops is where this piece starts.
Before any of this reads as general, one caveat on the source. Every figure comes from a single property, a large beauty retailer, web search, three months to August 2026. Because that property is unusually brand-heavy, treat the shape of these findings as transferable and the specific percentages as not.
Why does a published CTR curve overstate your top positions?
A published curve blends every query type together, and brand searches behave nothing like discovery searches. When someone types your brand name, the click was decided before the results loaded, so their behavior prices brand demand instead of ranking value. The gap is not subtle. On this property branded queries ran at 17.9% while non-branded ran at 1.65%, and mixing an 18% population into a 1.7% population produces a curve describing neither.
Here is what the blend costs at each position:
| Position | Blended curve | Non-branded only | Overstated by |
|---|---|---|---|
| 1 | 42.81% | 16.36% | 2.6x |
| 2 | 13.67% | 5.18% | 2.6x |
| 3 | 12.33% | 3.87% | 3.2x |
| 4 | 3.53% | 2.80% | 1.3x |
| 7 | 0.61% | 0.56% | 1.1x |
| 10 | 0.22% | 0.19% | 1.1x |
One caveat on that first row before anyone quotes it. Position 1 non-branded rests on 97,276 impressions against 22.7 million at position 4, and the pooled and fitted estimates for that one cell disagree, so read the 2.6x as a direction and not a precise multiple. Notice where the distortion sits. Anyone modeling a move into the top three on the blended curve overstates the gain by roughly threefold, while the deep positions nobody forecasts against are almost unaffected.
One detail worth stealing. Because misspellings and transliterations behave like brand searches while reading like generic ones, filtering on the literal brand string leaves a lot behind. On this export the classifier recovered 517 rows of misspellings and 490 rows written in Hebrew, Arabic, Cyrillic, Korean, Japanese and Chinese, together about 1% of impressions and sitting almost entirely at positions 1 to 3.
Before that fix, the naive non-branded bucket 1 read 60.9% CTR. After it, not one query remained in that bucket. Every position-1 “non-branded” query had been a brand transliteration.
What does pooling clicks and impressions miss?
Pooling produces an impression-weighted average, so whichever query carries the most impressions effectively becomes the bucket. On this export three positions were dominated by a single query. You can see the effect without any statistics at all.
| Position | Impressions | Largest query’s share | Effective sample |
|---|---|---|---|
| 3 | 42,390,556 | 67.2% | 2.2 queries |
| 7 | 29,025,318 | 47.7% | 4.3 queries |
| 10 | 13,933,670 | 52.3% | 3.2 queries |
With 5,380 queries in it, position 3 behaves like it holds two. Borrowed from antitrust economics, “effective sample” is the inverse Herfindahl index, which converts a weight distribution into the number of equally weighted queries carrying the same concentration.
Look at what that does to the curve. The pooled curve is not monotonic, meaning it should only fall as rank gets worse and here it does not. Position 7 sits below position 8, and position 10 sits below both. Since click-through rate does not improve as you rank worse, those inversions are three large queries wearing a curve’s clothes.
Two additions fix it without discarding the pooled number. First, cap any single query’s impression weight at 5% of its bucket, which on this data was the only cap that removed the inversion without reweighting positions that had no concentration problem. Then flag any bucket where one query exceeds a fifth of the weight. Four of ten tripped that flag here.
How wide is the uncertainty on a CTR curve?
The uncertainty on a CTR curve is wider than almost anyone reports, because the usual interval treats every impression as an independent coin flip. They are not independent. Since impressions cluster hard inside queries, the standard textbook interval, the Wilson interval, comes out roughly ten times too narrow over 42 million of them.
Resampling gives honest width instead: draw a random sample of whole queries, recompute the rate, and repeat a thousand times to see how much the answer wobbles. On this property non-branded position 7 lands between 0.28% and 1.18%.
On a number people quote to two decimal places, that is a fourfold range. My read: reporting a point estimate for a position with fewer than a few hundred well-spread queries is the single most common overclaim in this whole genre, including in my own earlier work.
Would machine learning do better than a fitted curve?
Tested instead of argued about, the answer splits cleanly in two. Scoring used impression-weighted binomial log loss, which punishes a confident wrong answer harder than an unsure one and weights each query by how many impressions it actually carried. Five models ran against two tests: a random holdout, which asks whether a model can interpolate inside the observed range, and a second test training on positions 1 to 8 to predict 9 and 10, which asks whether it can extrapolate.
| Model | Random holdout | Extrapolation |
|---|---|---|
| Bucket lookup | baseline | baseline |
| Fitted curve, position only | -0.4% | -68.7% |
| Fitted curve plus brand and nav flags | -4.7% | -69.1% |
| Gradient boosting, position only | +0.8% (worse) | -59.8% |
| Gradient boosting, all features | -6.8% | -71.9% |
Gradient boosting on position alone scored worse than a plain lookup table. Given one input, a tree ensemble rebuilds a noisy step function and overfits the concentrated buckets. Compare the two middle rows against the last one and the real story appears: adding two binary flags to a three-parameter regression captured 4.7 of the 6.8 points available, so roughly 70% of the total gain came from segmentation and the entire boosting apparatus bought the remaining two points.
The second half is structural. A decision tree predicts a constant beyond its training range, so here is what each model says at positions it never saw:
| Position | Fitted curve | Gradient boosting, all features |
|---|---|---|
| 9 | 0.61% | 5.00% |
| 12 | 0.31% | 5.00% |
| 20 | 0.09% | 5.00% |
Both boosted models return one frozen value forever. On page two, the all-features version still claims a 5% click-through rate, and it scored best on the extrapolation test because a flat line happens to pass near the truth just past the edge of the training data. That is luck with a short shelf life, and the failure is silent: the model returns a confident number instead of an error.
Use a fitted curve for the curve, and consider a learned model only for a different question. Predicting how one specific page and query will perform is a genuine machine learning problem where features beat a curve. What a curve gives you instead is a marginal relationship you can publish, draw on a slide, and defend in a meeting.
How much of your search data can you actually see?
You can see less than a third of your search data, and the missing part can be priced instead of assumed away. Because Google withholds queries issued by very few people, they never appear in any export at any row limit.2 Subtract what your query export accounts for from your site totals and the remainder is that anonymized mass.
| Clicks | Impressions | CTR | |
|---|---|---|---|
| Visible in the query export | 10,652,056 | 174,133,437 | 6.12% |
| Anonymized remainder | 6,996,163 | 436,282,890 | 1.60% |
The queries you can see convert about four times better than the ones you cannot, and the hidden ones carry 71% of impressions. Those two pulls ran minutes apart with slightly different date handling, so the decimals are approximate, though a 1% drift cannot explain a fourfold gap. Every curve built from visible queries is therefore an upper bound, including this one and including every published table. One subtraction gets you that ratio. Almost nobody prints it.
Worth knowing before you try this: the Search Console UI download caps at 1,000 rows sorted by clicks, so the 1,000th row on this property still had 815 clicks. Covering 51% of clicks and 19% of impressions, that export selects on the very thing you are trying to model. An API pull or a browser extension gets past the cap.
What should you do with your CTR curve?
Rebuild the curve on your own data, split branded out, and carry the uncertainty. It takes an afternoon. Those three fixes are worth more than any modeling choice downstream of them.
So you don’t have to write the code, I built the tool: the GSC CTR curve builder runs entirely in your browser, so your export never reaches a server. Drop in a CSV or the Excel file Search Console gives you, name your brand, and it returns the pooled rate, the capped rate, a resampled interval and a fitted curve for positions 1 to 10.
One property of the data is worth naming before those limits, because it is a deliberate alignment and not a flaw. Show at positions 2, 4 and 6 for a single search and Search Console records the topmost position with one impression, never three.2
This curve keeps that accounting on purpose, so it prices what your best listing achieved and never values a second listing separately, because Google’s own data never separates them. Build a forecast on a different definition of position than your reporting uses and the two will not reconcile when someone checks.
Three limits apply to any curve built this way, mine included, and none has a workaround. Average position is a blend and not a rank, so a query averaging 3.0 might have sat at 3 every day or swung between 1 and 5, and no export separates those. SERP features are invisible too, so an AI Overview above the results changes click-through rate at every position with nothing in the file recording whether one was there.
A daily-grain API pull would expose per-query position variance and fix the first of those, which is the highest-value upgrade still available to me. A third limit belongs beside them, and it applies to every curve built from Search Console rather than to mine alone. Google records a result’s position only when somebody actually saw it, so a listing on page three is not recorded at all when the searcher never leaves page one.2
Deep positions are therefore measured only across the searches where someone scrolled far enough to reach them, and the impressions least likely to end in a click are exactly the ones that never enter the denominator. My read: that pushes the bottom of every published curve upward, mine included, by an amount no export can measure.
Terms defined here
- Bucket concentration. A position whose pooled click-through rate is really one query's rate, because that query carries most of the impressions assigned to it.
Sources
Seer Interactive, Google Search Console documentation, and first-party measurement.
Related reading
From the Daily Pulse
Explore with