Skip to Content
Google Search Console

Query search analytics

Run a live Search Console performance query, with clicks, impressions, CTR and average position grouped by the dimensions you choose.

GEThttps://api.rankparse.com/v1/gsc/search-analyticsFreeAPI key + connected Google account

Runs a Search Console performance query for one property, live against Google: clicks, impressions, click-through rate and average position, grouped by query, page, country, device, date or search appearance. It covers any query Google reports, not only the ones you track. For stored, multi-engine snapshots of your tracked queries, use Rank tracking instead.

Query parameters

sitestringrequired

The property as returned by List properties, for example https://example.com/ or sc-domain:example.com. A bare host such as example.com also works: see The site parameter. Missing returns 400 missing_site.

startDatestringrequired

First day, YYYY-MM-DD. Missing returns 400 missing_dates; any other format returns 400 invalid_date. The same applies to endDate.

endDatestringrequired

Last day, YYYY-MM-DD. RankParse checks only the shape of the dates. Google applies its own range rules (such as its history window), and a request Google rejects comes back as 502 gsc_api_error with Google's message.

dimensionsstringdefault query

Comma-separated list of query, page, country, device, date and searchAppearance. Unknown names are dropped silently; if none is valid the call returns 400 invalid_dimensions. The order you give is the order of keys in each row.

searchTypestringdefault web

web, image, video, news, googleNews or discover. Anything else returns 400 invalid_search_type. Google does not offer every dimension for discover and googleNews (query is not available there).

filterPagestring

Keep rows whose page URL equals this exactly.

filterPageContainsstring

Keep rows whose page URL contains this text, for a segment such as /blog/. Sending it with filterPage returns 400 conflicting_filters.

filterQuerystring

Keep rows whose query equals this exactly. Can be combined with either page filter; all must match.

filterQueryContainsstring

Keep rows whose query contains this text. Sending it with filterQuery returns 400 conflicting_filters.

countrystring

Keep traffic from one country: an ISO 3166-1 alpha-3 code such as USA or GBR. A two-letter code such as US is accepted for common countries. Anything else returns 400 invalid_country.

devicestring

Keep traffic from one device type: desktop, mobile or tablet. Anything else returns 400 invalid_device.

filterQueryRegexstring

Keep rows whose query matches this RE2 regular expression, 1 to 500 characters. For example ^(?:\S+\s+){7,}\S+$ keeps queries of 8 or more words. Sending it with minQueryWords returns 400 conflicting_filters; a length outside 1 to 500 returns 400 invalid_param; a pattern that is clearly not valid RE2 (unbalanced parentheses, an unclosed [, a quantifier with nothing to repeat, lookahead, lookbehind or a backreference) returns 400 invalid_filter_regex before Google is called.

minQueryWordsinteger

Keep queries of at least this many words, from 2 to 50. The same filter as the regular expression above, built for you: 8 means 8 or more words. Anything else returns 400 invalid_param.

minPositionnumber

Keep rows with an average position at or above this number. Not a number returns 400 invalid_param.

maxPositionnumber

Keep rows with an average position at or below this number.

maxCtrnumber

Keep rows with a CTR at or below this, as a fraction from 0 to 1 (0.03 means 3%).

minImpressionsnumber

Keep rows with at least this many impressions. With compareTo, a row passes when either period meets it.

minClicksnumber

Keep rows with at least this many clicks (same rule with compareTo).

startRowintegerdefault 0

Offset into Google's rows (ordered by clicks), to read past the first page. Use the next_start_row from a response that says has_more. A negative or non-integer value returns 400 invalid_param, and so does any value above 0 together with compareTo.

compareTostring

previous_period also reads the period of the same length that ends the day before startDate and adds previous, delta and status to every row. Anything else returns 400 invalid_compare_to. It cannot be combined with startRow above 0 or with the date dimension (both return 400 invalid_param). See Comparing periods.

sortstring

Order the rows by clicks, impressions, ctr or position; with compareTo also by clicks_delta, impressions_delta, ctr_delta or position_delta. The default order is Google's (clicks, descending). Anything else returns 400 invalid_sort.

orderstring

asc or desc. The default is largest first, except position, where the best (lowest) comes first. For the biggest losers use sort=clicks_delta&order=asc. Anything else returns 400 invalid_order.

fieldsstring

Comma-separated subset of keys, clicks, impressions, ctr, position, previous, delta and status. Each row then carries only those fields, which keeps a large response small. An unknown name returns 400 invalid_fields.

rowLimitintegerdefault 100

Rows to return. Values above 1000 are lowered to 1000; a missing, zero or non-numeric value uses 100.

Response

sitestring

The property you queried.

startDatestring

Echo of the request.

endDatestring

Echo of the request.

dimensionsarray of strings

The dimensions that were accepted, in order.

filterPagestring

Echoed only when you sent it. The same goes for filterPageContains, filterQuery and minQueryWords.

filterQueryRegexstring

Echoed when you sent filterQueryRegex, or minQueryWords, in which case it is the regular expression that was built from it.

searchTypestring

The search type used.

requested_sitestring

Present only when RankParse matched your site to a different property; site then holds the property it used.

countrystring

Echoed only when you sent country, as the alpha-3 code that was used. The same goes for device.

row_countinteger

Rows in this response.

total_matchedinteger

Rows that passed every filter before rowLimit trimmed them, out of the rows read from Google.

has_moreboolean

true when Google returned a full page of rows, so more may exist. Filters, sorting and comparison work on that page only.

next_start_rowinteger

Present when has_more is true: pass it as startRow to read the next page.

previous_periodobject

With compareTo: the startDate and endDate of the period compared against.

comparison_may_be_incompleteboolean

With compareTo: true when either period hit the 1000-row read, so a row marked new or lost may only be outside the rows read.

rowsarray

Result rows, at most rowLimit, in Google's order (by clicks, descending). Empty when Google has no data for the request.

Show properties
keysarray of strings

One value per dimension, in dimensions order. For date, a YYYY-MM-DD string.

clicksnumber

Clicks from Google Search.

impressionsnumber

Impressions in Google Search.

ctrnumber

Click-through rate, a fraction from 0 to 1.

positionnumber

Average position for the row. A Google-reported average, not a live SERP rank.

previousobject | null

With compareTo: that period's clicks, impressions, ctr and position, or null for a new row.

deltaobject

With compareTo: the change, where positive is better. clicks and impressions are current minus previous, ctr likewise, and position is previous minus current, so a positive position means the row moved up. position is null when the row is in only one period.

statusstring

With compareTo: both, new (only in the current period) or lost (only in the previous one; its current values are 0).

responseAggregationTypestring

How Google aggregated the rows (byProperty, byPage or auto). Omitted when Google does not send it.

Behavior and limits

  • Credits: 0. Rate limit 60 requests per minute per key, plus Google's own quota.
  • Finalized data only: RankParse asks Google for final data, so the last day or two are usually missing.
  • Position, CTR and impression filters run after Google answers. When any of minPosition, maxPosition, maxCtr or minImpressions is set, RankParse fetches Google's top 1000 rows, filters them, then trims to rowLimit. A filter can only find rows inside that top 1000, so for a large property narrow the date range or add filterPageContains first.
  • Sorting, comparison and paging work on one page of Google's rows. Sorting by anything other than clicks, or setting compareTo, also reads the top 1000 rows. Use startRow to move that page, except with compareTo, which always reads the first 1000 rows of each period.
  • Query regex filters run inside Google. filterQueryRegex and minQueryWords narrow the rows before the top 1000 are taken, so they are the way to find long, specific searches on a large property. RE2 has no lookahead or backreferences. Google answers many malformed patterns with no rows instead of an error, and RankParse catches only the clearly invalid ones, so an empty result from a regular expression you wrote can mean a mistake in the pattern as well as no matches.
  • Multiple Google accounts: the property is read through the account that can see it. See The site parameter.

Comparing periods

compareTo=previous_period answers "what changed?" in one call. For startDate=2026-10-01&endDate=2026-10-28 it also reads 2026-09-03 to 2026-09-30, joins the two on the row keys, and adds a delta to each row. Rows that exist in only one period are kept and marked new or lost, so a page that dropped out entirely still shows.

Pages that lost the most clicks in the US on mobile
GET /v1/gsc/search-analytics?site=example.com&dimensions=page&startDate=2026-10-01&endDate=2026-10-28
    &country=US&device=mobile&compareTo=previous_period&sort=clicks_delta&order=asc&minClicks=20&rowLimit=10

Common recipes

GoalParameters
Top queriesdimensions=query
Top pagesdimensions=page
Queries for one pagedimensions=query&filterPage=https://example.com/blog/post
Biggest losers against the previous perioddimensions=page&compareTo=previous_period&sort=clicks_delta&order=asc
One segment, one marketfilterPageContains=/free-tools/&country=US&device=mobile
Pages ranking for one querydimensions=page&filterQuery=best seo tools
Daily trenddimensions=date (use rowLimit=500 or more for long ranges)
Cannibalization checkdimensions=query,page
Quick wins (positions 8 to 20)dimensions=query&minPosition=8&maxPosition=20
Low CTR, high impressionsdimensions=page&minImpressions=500&maxCtr=0.05
One section of the websitedimensions=page&filterPageContains=/blog/
Long, specific searches (8 or more words) with few clicksdimensions=query,page&minQueryWords=8&minImpressions=50&maxCtr=0.03
Countries or devicesdimensions=country or dimensions=device
Rich results and search featuresdimensions=searchAppearance

Errors

Plus the shared Search Console errors (see the overview).

HTTPCodeWhen
400missing_sitesite is missing.
400missing_datesstartDate or endDate is missing.
400invalid_dateA date is not in YYYY-MM-DD shape.
400invalid_dimensionsNone of the requested dimensions is valid.
400invalid_search_typesearchType is not one of the allowed values.
400conflicting_filtersfilterPage and filterPageContains were both sent, or filterQueryRegex and minQueryWords were both sent.
400invalid_paramminPosition, maxPosition, maxCtr or minImpressions is not a number, filterQueryRegex is empty or over 500 characters, or minQueryWords is not a whole number from 2 to 50, or compareTo is combined with a startRow above 0 or with the date dimension.
400invalid_filter_regexfilterQueryRegex is not valid RE2. RankParse refuses the clearly invalid patterns itself without calling Google, and also returns this if Google rejects one.
400gsc_not_connectedNo Google Search Console account is connected.
404gsc_property_not_foundNo connected Google account can see site.
429gsc_quota_exceededGoogle's quota was exceeded. Retry later.
502gsc_api_errorGoogle rejected the request or failed. The message carries the detail.

Every MCP tool below calls this route with fixed dimensions and filters, and each takes an optional searchType (default web). All need site, startDate and endDate.

MCP toolWhat it sends
get_gsc_top_queriesdimensions=query, filterQueryRegex (optional), rowLimit (default 25)
get_gsc_top_pagesdimensions=page, rowLimit (default 25)
get_gsc_page_queriesdimensions=query, filterPage from page, rowLimit (default 25)
get_gsc_query_pagesdimensions=page, filterQuery from query, rowLimit (default 25)
get_gsc_date_trendsdimensions=date, rowLimit=500
get_gsc_country_breakdowndimensions=country, rowLimit (default 25)
get_gsc_device_breakdowndimensions=device, rowLimit=10
get_gsc_query_page_pairsdimensions=query,page, filterQueryRegex (optional), rowLimit (default 100)
get_gsc_page_trenddimensions=date, filterPage from page, rowLimit=500
get_gsc_query_trenddimensions=date, filterQuery from query, rowLimit=500
get_gsc_opportunity_queriesdimensions=query, minPosition (default 8), maxPosition (default 20), rowLimit (default 50)
get_gsc_long_queriesdimensions=query,page, minQueryWords from minWords (default 8), minImpressions (default 50), maxCtr (default 0.03), rowLimit (default 50). It reads at most 1000 query and page rows ordered by clicks before the impressions and CTR filters apply
get_gsc_low_ctr_queriesdimensions=query, minImpressions (default 100), maxCtr (default 0.05), rowLimit (default 50)
get_gsc_low_ctr_pagesdimensions=page, minImpressions (default 500), maxCtr (default 0.05), rowLimit (default 25)
get_gsc_page_segmentdimensions=page, filterPageContains from urlPattern, rowLimit (default 25)
get_gsc_search_appearancedimensions=searchAppearance, rowLimit=50