Search Console API

Google Search Console API limits, and what you still have to build.

The quotas are generous and the rows are free. What costs you the weekend is everything the API does not store: yesterday against today, history past 16 months, and an opinion about which page to fix first.

From $14.99/mo · the same API, already paginated, stored and ranked

searchAnalytics.query
// what the API returns
{ "keys": ["/pricing"], "clicks": 41, "impressions": 3204,
  "ctr": 0.0128, "position": 4.3 }
// what you actually wanted to know
QueryScope · fix this first
1 /pricing ranks #4, click rate below your curve
Same row. The gap between them is the code you were about to write.

Numbers on this page come from the Search Console API code we run in production every day.

The actual numbers

"The API limit" is four different ceilings.

They fail in four different ways, and only one of them announces itself. Mixing them up is the reason most first scripts quietly return a partial answer and get believed.

Rows per request

25,000

The rowLimit parameter accepts 1 to 25,000, and defaults to 1,000. That default is the trap: leave it out and you get the first thousand rows with no error and no flag. Page through with startRow until a batch comes back short.

Fails silently. You get a number, just not the whole one.

Query rate

1,200 QPM

Per site and per user for Search Analytics, inside a project ceiling of 40,000 QPM. There is also a load quota measured in 10-minute and 1-day chunks that complex queries burn faster: a page and query join over a long date range is expensive. Trip it and Google asks you to wait 15 minutes.

Fails loudly. You get an error you can retry.

URL inspections

2,000 / day

Also capped at 600 a minute, per property. This is the one you will actually hit, because it is per URL rather than per query, and indexing questions are exactly the ones you want to ask about every page. A 5,000-page site cannot be inspected in a day.

Fails loudly, then costs you days of calendar time.

History

16 months

Not a quota at all, which is why it never appears on the limits page, and it is the one that actually costs you something. Month 17 is gone, permanently, and there is no endpoint that tells you what changed since yesterday. If you want either, you store the data yourself, starting today.

Never fails. It just quietly forgets.

Quota figures are Google's, from the Search Console API usage limits and the searchAnalytics.query reference. They match the constants in our own sync code, because we hit them.

Scope

What it gives you that the export cannot, and what it never gives you.

Only in the API

  • +The exact page and query join. Ask for both dimensions at once and every row carries both keys. The interface cannot show you this and no CSV export produces it.
  • +Hourly rows, through a separate freshness setting, which is how the last-24-hours view is built.
  • +Search appearance, the rich-result types you win. It has to be the only dimension in the call.
  • +Discover as a separate surface. No queries, no position, because nothing there is ranked.

Never in the API

  • Links. The backlink report is interface-only, so there is no endpoint for who links to you.
  • Anything about a competitor. It is your property or nothing, which also means it cannot see the results page you are ranking on.
  • The page indexing report as a whole. You reconstruct coverage one URL at a time, against that 2,000 a day cap.
  • The rare queries. Google drops them for privacy, so the query table totals less than your real clicks. No quota causes this and no parameter turns it off.

That last one is the one that bites hardest, because it looks like data rather than a gap. If you sum query rows to get a site total, you will under-report your own traffic and never see an error. Page-level and query-level data are not interchangeable, and the fix is to take volume from the page dimension and read queries only for intent.

Three things the documentation is right about and still does not prepare you for.

Each of these cost us a real debugging session. If the vocabulary is unfamiliar, the Search Console glossary defines every metric and indexing state in a sentence, with the caveat that makes it misleading.

01 The mismatch

The API and the interface disagree, and both are correct.

One setting decides whether a response includes the freshest days or only finalized ones, and it changes the totals for the same site over the same dates. We use finalized data for the weekly comparison, because a week-over-week diff has to compare like with like, and fresh data for the live query list, because that is what the interface shows. Same endpoint, two answers, no bug. Nearly every "my numbers do not match" thread is this parameter.

finalized: stable, trails ~3 days · fresh: matches the interface

Why Search Console throws the history away
02 The one we got wrong

We anchored a 24-hour window to now(). It reported 1 click instead of 7.

The hourly pipeline trails the present by a few hours, so a window ending at the current time slices off the hours that actually carry the traffic and counts empty recent hours in their place. It under-reports badly and it never errors, which is why it survived review: the number looked plausible. The fix is to anchor the window to the latest hour that has data, not to the clock. The comment explaining it is still in our sync code, because the next person deserves to find it.

now() anchor: 1 click · latest-hour anchor: 7 clicks

What we found running this on a real SaaS
03 The property string

A domain property and a URL-prefix property are different properties.

The same site can be verified as sc-domain:example.com, as https://example.com/, or with the www or http spelling, and the wrong one returns a 403 rather than an empty result. Guessing is not viable, so we list the properties the credential can actually read and match against the candidates in order. Two minutes of reading beats an afternoon spent debugging an authentication error that was never about authentication.

list the properties first · never guess the string

Connect it over MCP instead

Two ways to get there

The API is free. The layer on top of it is the actual project.

Writing the client is an afternoon and it is a genuinely good afternoon. What follows it is a store, a daily job, a diff, and the judgment call about which of forty pages to open first. QueryScope is that layer, already built, against the same free API.

Write it yourself

1Cloud project, OAuth client, tokens to keep fresh 2paginate 25k at a time, store every pull 3build the diff, there is no delta endpoint 4run it daily forever or lose month 17 5output: correct rows, no ranking

Free, and yours to keep running.

Connect QueryScope

> one line in your IDE, then authorize
no Cloud project or consent screen of your own pagination, storage and the daily job handled history kept past the 16-month wall output: a ranked list of what to fix first

One line, hosted, and the analysis done.

One line in your IDE. Then authorize and pick a site.

install.sh
claude mcp add --transport http queryscope https://mcp.queryscope.dev/mcp

Cursor, Cline, and Windsurf take the same URL in their MCP config. Your IDE runs the LLM, so there is no separate AI fee.

Keep the API. Skip the six weeks after it.

Same data, same read-only grant, already paginated, stored past 16 months, and ranked into a list your coding agent can act on. One price per site count, no credits, no metering.

7-day free trial · $0 due today · cancel anytime in one click

FAQ

Search Console API questions.

Is the Google Search Console API free?

Yes. There is no charge and no billing account required, only quotas. That is exactly why the interesting question is not what the API costs but what you build on top of it: the storage, the daily job, and the decision about what to fix are the parts that take real time.

How many rows can I get per request?

Up to 25,000, but the default is 1,000 and it applies silently if you leave the parameter out. Page through with the start-row offset and stop when a batch returns fewer rows than you asked for. If you cap your own pagination, log it when you hit the cap: a truncated result that looks complete is worse than an error.

Why doesn't my API data match the Search Console interface?

Usually the data-state setting. Finalized data trails roughly three days and stays stable; fresh data includes the most recent days and is what the interface shows by default, so the same query over the same dates returns different totals. The second common cause is summing query rows: Google drops rare queries for privacy, so query totals are always lower than page totals.

Can I get backlinks or competitor data from the API?

No, and no. The links report exists only in the interface, and the API is scoped to properties you have verified access to, so competitor data is out of reach by design. It also cannot see the results page your page appears on, which is worth knowing before you trust any tool that promises to explain a ranking from Search Console data alone.

How far back does the API go?

Sixteen months, and it rolls forward, so month 17 is deleted rather than archived. There is also no endpoint for what changed since yesterday. Both are reasons to start storing your own daily copy today rather than the day you need the comparison, which is usually the day it is already too late.