Brandon Lazovic

Tool · Search Console analysis

GSC CTR curve builder

Drop in a Search Console query export and get a click-through-rate curve for positions 1 to 10, split by branded and non-branded intent, with an honest confidence interval on every point.Your file is parsed in your browser and never reaches a server.

Drop your Search Console export here

or choose a file · .csv, .tsv, .txt, .xlsx

or paste CSV / TSV text
Add site totals to bound the estimate

Get these from the Devices or Countries tab of the same export. They cover every query, including the ones Search Console withholds from your download.

Add a file or paste query data, then build the curve.

No curve yet. Drop a file, paste query data, or

How to read this

What each number means, and what it does not

Branded

A branded search already named your business, so the click was decided before the results ever loaded. The curve sets these aside because they price brand demand, not the value of a ranking position.

Branded navigational

Branded, and aimed at one destination: a login page, a store locator, a gift-card balance. The intent here is even more fixed than plain branded, since the searcher already knows exactly which page they want.

Non-branded

A discovery search, where ranking position actually changes what gets clicked. This is the curve worth forecasting with, and it is the segment the tool shows by default.

Pooled rate

Every query's clicks divided by every query's impressions at that position, summed first and divided once. Averaging each query's own rate instead would let a nine-impression query count as much as a nine-million-impression one.

Capped rate

The same calculation, run again after no single query is allowed more than 5% of a position's weight. Where the pooled and capped rates agree, nothing is concentrated. Where they pull apart, trust the capped number.

Fitted rate

A smooth curve drawn through all ten positions at once, so a single odd position cannot bend it. Useful where a position's own measurement cannot be trusted, and worth ignoring where the fitted value falls outside that position's likely range, which means the curve shape and the data disagree.

95% resampled interval

The range the true rate probably sits inside, built by resampling whole queries rather than individual impressions. Impressions inside one query rise and fall together, so treating them as independent would understate how wide that range really is.

Why the column does not total 100%

Each position is a separate rate on its own impressions, so the column is ten answers to ten questions and not a breakdown of one total. Check the impressions column beside it and the reason is visible: one position might be asking about ninety thousand impressions while the next asks about twenty-eight million.

Which number should I use?

Forecast with the measured rate where the position looks solid, meaning no concentration flag and a few thousand queries behind it. Where one query dominates or the row is thin, use the fitted rate instead, since the row cannot carry itself. Quote the likely range whenever the number leaves the room, because on this data the range at position 7 runs from 0.25% to 1.20% and a single figure hides that.

How to use this curve for a forecast

A curve is a lookup table and not a budget. Every forecast uses exactly two rows, your current position and your target position, and ignores the other eight.

Worked example

A page sits at position 7, and the searches it appears for produce 10,000 impressions a month. You want to know what moving it to position 3 is worth.

At position 7: 10,000 impressions × 0.56% = 56 clicks

At position 3: 10,000 impressions × 3.87% = 387 clicks

The move is worth 331 clicks a month.

Two numbers out of ten did that work. The other eight never entered the arithmetic.

Why the percentages do not add up to 100%

Reading a percentage column downward and totalling it is the natural instinct, because almost every other percentage table is a distribution: market share, budget split, traffic by channel. Those carve one total into slices. This one does not.

Each row is a separate rate measured on a separate group of searches. Position 1 in the example data covers a few thousand queries and their impressions; position 7 covers a different few thousand queries and a much larger pile of impressions. Two different questions, two different denominators, no shared total.

One query cannot appear in two rows either. Google records a single position per query, the topmost one, so a site showing at positions 2, 4 and 6 for one search is logged as position 2 with one impression. Ten rows means ten different groups of searches.

Summing was never the risk, because forecasting never sums. Picking the wrong row is the risk. Forecast that same page on a blended curve that still has branded queries in it and position 3 reads 12.33% instead of 3.87%, which turns 387 clicks into 1,233. You would have promised roughly three times the traffic you were going to get.

What is a CTR curve, and why build your own?

A click-through rate (CTR) curve answers one question: at each position in a search results page, what share of the people who see your listing actually click it? Because every traffic forecast for a ranking change rests on that number, it matters whose curve you use. Seer Interactive's widely-read walkthrough made the case for building your own curve instead of pulling a generic published table, since every site's ranking mix and query intent differ. This tool follows that instruction and adds three things a quick pooling method leaves out. One is a branded and non-branded split, which Seer's walkthrough says plainly that it skips. Another is a check for whether one query has quietly become the whole bucket. The third is a confidence interval built for the way query data actually clusters.

How to use this tool

  1. Export your Search Console queries. Open Search Console, pick a page or the whole property, and export the Queries table as a CSV or Excel file. The default download caps at 1,000 rows; an API pull or a browser extension gets the rest.
  2. Drop the file in, or paste it. Drag the export onto the tool, choose it from a file picker, or paste CSV or TSV text straight from a spreadsheet.
  3. Name your brand, if you have one. Type the brand term so the tool can split branded searches from the rest. Leave it blank and every query counts as non-branded. Add transliterations and non-Latin spellings in the second field, since those change the split materially on an international property.
  4. Build the curve and read the census first. Click Build the curve. Check the segment census before anything else, since it shows whether your branded and non-branded split looks right for your data.
  5. Read the callouts before you trust a number. Any concentration flag, non-monotonic warning, or coverage bound appears under the chart. Read those before quoting a position's click-through rate.
  6. Switch segments, then export. Toggle between non-branded, branded and all queries to compare the three curves, read the per-position table under the chart, then use Download CSV to take the numbers into a forecast.

Where do I get a Search Console export?

In Search Console, open the Performance report, filter to the page or property you want, and export the Queries table. The button in the UI writes at most 1,000 rows, sorted by clicks, so any query past that cutoff is silently absent no matter which file format you choose. Through the Search Console API, or a browser extension built on it, a full pull returns every query Google is willing to report. Either export works here: this tool reads a CSV, a TSV, plain text, or an Excel file with Query, Clicks, Impressions, and Position columns, and it figures out which sheet and header row to use on its own.

How does it work?

Within each position bucket, the tool sums every query's clicks and sums every query's impressions, then divides. That is called pooling, and it is the correct move. Averaging each query's own rate instead would let a query with nine impressions count as much as one with nine million. Though pooling is the right call, it still has a failure mode of its own. A single high-volume query can carry most of a bucket's weight and effectively become the bucket. On the reference export this tool's engine was tested against, one query held 67% of a bucket's impressions, which is why every bucket also reports a capped rate: the same pooled calculation, after limiting any one query to 5% of the bucket's weight. Where pooled and capped agree, nothing is concentrated. Where they diverge, trust the capped number.

Branded and non-branded queries get separated before the curve is built. Because a shopper searching your brand name already decided to click before the page loaded, their behavior does not price a ranking change the way a non-branded search does. Skipping that split, as a simpler walkthrough does for simplicity, mixed an 18% click-through population into a 1.7% population on the export this method was measured against and overstated position 1 by 2.6 times against the real non-branded rate. Instead of impressions, each bucket's interval comes from resampling queries, because impressions inside one query cluster together rather than behaving like independent coin flips; a plain statistical interval over raw impression counts would read roughly ten times too narrow. Last, a curve is fit through all ten buckets using a logistic model, the same shape statisticians use whenever an outcome has to stay between 0% and 100%. The fit smooths over noisy buckets and extrapolates past position 10, and the tool always shows the pooled number beside it so a reader can judge how far the fit is leaning on the data.

What this tool cannot see

Average position is a blend, not a rank, and that is the first of four limits worth knowing before you lean on a result. For example, a query at average position 3.0 might have sat at exactly 3 every day, or at 1 half the time and 5 the rest, and this method cannot tell those two histories apart even though their true click-through rates differ. SERP features are invisible to a query export too. An AI Overview or a shopping module above the results changes click-through rate at every position, and nothing in a Search Console file records whether one was present. Because Search Console withholds queries it judges too rare to report, for privacy reasons, at every row limit and every export method, that gap never shows up in any query file. Add your site totals above and the tool will price that gap directly, rather than let you assume full coverage. Brand matching is the fourth limit, and it is the one you can act on. Transliterations are matched as plain text, so a spelling variant you did not list stays in the non-branded pile. On the 36,000-query export this method was built against, that left 149 queries worth about 17,000 impressions misfiled, roughly a hundredth of one percent. Sort your non-branded results by click-through rate and anything near the top is usually a brand spelling worth adding to the field above.

Is my data safe?

Yes. In your browser, plain JavaScript handles parsing, classification and every statistical calculation. Your file or pasted text is never transmitted, logged, or stored anywhere, which matters when the export is from a client account or a property that has not launched yet.

Frequently asked questions

Is my query data uploaded anywhere?

No. Because every calculation runs in the browser with plain JavaScript, nothing about your file ever needs to leave it. Your file or pasted text never reaches a server, so it is safe to use with client accounts or unreleased data.

Why does my curve differ from a published click-through rate table?

On a published table, every query type gets blended into one curve built from someone else's site. Your own non-branded curve prices your traffic and your ranking mix instead, and the gap can be large. On the export this tool's engine was measured against, the blended method overstated position 1 by 2.6 times and position 3 by 3.2 times against the true non-branded rate.

Why split branded and non-branded queries?

Someone searching your brand name already decided to click before the results loaded, so their click-through rate barely moves with ranking position. Mixing that population into a ranking-sensitive curve inflates the top positions and flattens the relationship a real rank change would move.

What does the capped CTR column mean?

After capping any single query at 5% of a bucket's impression weight, the tool recalculates the pooled rate. That number is what the capped column reports. Real query exports concentrate hard, and on the reference export, one query held 67% of a bucket's impressions and effectively set the whole bucket's rate by itself. Where the pooled and capped numbers agree, concentration is not a problem, and where they diverge, trust the capped column more.

Why is the interval so wide at some positions?

The interval comes from resampling queries, not impressions, because impressions inside one query are not independent events. A bucket with few queries, one of them dominant, produces a wide range even across millions of impressions, and that width is honest information rather than a flaw in the method.

What is the 1,000-row cap, and how do I get past it?

On Search Console's UI download, rows stop at 1,000, sorted by clicks, so anything past that threshold never appears no matter how you export. A full pull through the Search Console API, or a browser extension built on it, returns every query Google will hand over. Paste or upload whichever file you have; the tool works with either.

Can I use this to forecast future traffic?

Use it to price a ranking change on the property you measured, not to forecast a different one. Since it carries every limitation named in "What this tool cannot see" below, the curve is best read as a marginal relationship between position and click-through rate on your own query mix, not as a stand-alone prediction.

Why not use machine learning instead of a fitted curve?

It was tested rather than assumed. A gradient boosting model trained on position alone scored worse than a plain bucket lookup, and every tree-based model froze at one fixed value past the positions it had seen. Which value it froze at depended on the model, and on the data. On the reference export the position-only version froze at 1.67% and the one trained on every feature froze at 5%, both forever past position 20. The freezing happens on any dataset; the value it freezes at will differ. A model like that looks right up to the edge of its training data and goes silently wrong past it. By design, the fitted curve here extrapolates on purpose.

What counts as a branded query if someone misspells or transliterates the name?

The classifier checks three things: the literal brand string, a fuzzy match against the individual words in the query, and any transliterations you list. That combination catches spellings like "sefora" or "saphora" and non-Latin scripts like Hebrew or Cyrillic, which a simple text search misses entirely.

Why does the pooled curve sometimes go up at a worse position?

When one or two large queries carry most of a bucket's weight, click-through rate does not actually rise as ranking gets worse even though the pooled number can look that way. The tool flags that pattern as concentration rather than a real finding, and the capped and fitted columns are built to survive it.

Related tools

Once you know which positions matter, pull the URLs ranking there with the sitemap URL extractor, or map how those pages sit in your site structure with the URL taxonomy visualizer. See all SEO tools.