gsc_* tools. Google Search
Console is not a neutral recorder: it censors queries, lags about 3 days,
caps rows, and rate-limits properties. Every rule below exists because a
confident wrong answer was produced without it.
The same content is available mid-session as the resource
aga://guides/gsc-data-fidelity.
Anonymization: named queries are a biased floor
Google withholds rare queries. It is common for well under half of impressions — and even fewer clicks — to be attributable to a named query. Three properties of that hidden tail matter:- It is not random. Rare long-tail phrasings live there — exactly where conversational AI-style queries sit — and hidden queries often convert better than named ones. The named sample is biased, not just incomplete.
- The naming rate is non-stationary. The named share can double within months as a site grows. Distinct-query counts are NOT comparable across periods — later months look broader partly because Google names more of them.
- Zero is the most fragile finding. NEVER claim “zero clicks” from query data. A claim of “zero clicks for an entire intent class” has collapsed the moment page-level data was checked: the clicks were real, sitting on queries Google refuses to name.
[page, query] and read meta.anonymization
— it reports named vs anonymized impressions, clicks, and CTR. Query-only
pulls never surface it; you need the page-level denominator alongside the
named total. Pull it early: this block has retracted headline findings after
they were already reported.
Query-frame responses without a page denominator carry a top-level
queryBiasNote restating this: gsc_query_analytics, gsc_export_dataset,
gsc_query_export, and gsc_compare_periods all say so when their rows are
query-level. Read it as a standing warning, not a per-call observation.
Operating rule: use query text to learn WHAT KIND of demand exists and to
find specific opportunities — never to size a segment, compare breadth across
periods, or claim something earns no clicks. Size segments at page level;
page data has no anonymization. Every query-derived figure is a floor. Where
the instrument is biased, quote bounds (page-level ceiling vs named-query
floor), not point estimates. The page-level ceiling can be several times the
named-query floor — the truth is between, and the bound is the quotable
result.
The ~3-day lag and incompleteDays
GSC data settles over about 3 days; the most recent days revise upward. Cut analysis at today − 3.meta.incompleteDays flags only dates that fall inside the real lag window —
today−3 … today at the time of the call. Historical pulls carry no flags: a
January export requested in September is complete and says so. Never trend on
flagged days; never discard unflagged historical data because of a stale
mental model of the flag.
Row cap, partitioning, coverage
gsc_export_datasetcaps at 25,000 rows per property per call. Slice large accounts by month so every export lands under the cap — a single busy month on a growing site can run to tens of thousands of rows.- Capped pulls auto-partition (device → page-regex) and reconcile against an
uncapped denominator. Gate impression-based analysis on
coverageRatioof at least 0.98 andtruncatedByApi: false. Click-based analysis survives capping either way — the cap discards the zero-click impression tail first.
The daily quota
Google enforces a daily per-property load quota. When it trips, EVERYTHING fails — pulls can fail repeatedly for hours, and a tiny analytics request fails identically to a huge export, because it is a property-level daily cap, not a request-size limit. It resets the next day. When the quota is exhausted the tools return GSC 429 errors with quota-specific guidance — the daily per-property cap, the next-day reset, and the budgeting rules below. Treat a 429 as “stop pulling today,” not “retry smaller.” Budget your pulls:- Enumerate what you need before you start, rather than iterating exploratorily against the API.
- Prefer one wide export plus local re-slicing (
gsc_query_export, or pandas over the downloaded JSON) over many narrow calls. - Exploit the 6-hour identical-params cache instead of re-pulling.
- Have a labelled proxy method ready. When page×query attribution is unavailable, pages can be classified by their own target search term instead — a documented proxy, clearly labelled, replaced with real attribution once quota returns.
Export files are remote
gsc_export_dataset writes the file on the MCP server, not your machine. The
returned filePath is a server path — reading it locally fails. The response
also carries a pre-signed downloadUrl that expires in about an hour;
curl it immediately:
forceRefresh to bypass.
Filters and metadata
- A substring path filter catches unrelated URLs — a filter like
page contains "articles"can also match pages that merely contain the string. Enumerate what it caught before trusting it. updatedAtmay be a bulk touch: count distinct dates and the max articles sharing one — hundreds of articles sharing a handful of timestamps means a bulk operation. True update dates may live in content bylines or schema.org markup — ask the client what their content contains.- The session’s current account is an in-memory override that can reset
silently — pass
accountIdexplicitly on every call, subagents especially.content_planner_list_questions’squestionCounts.totalcan undercount; the returned rows are authoritative.
See also
- First analysis on an account — where these rules sit in the Phase 0–5 runbook
- Analysis guardrails — the analytical patterns for modelling on top of this data
- Reading Search Console data correctly
— aggregation frames, the page-filter trap, and the
metablock - Available MCP tools — full input and
output reference for the
gsc_*tools