---
title: "Build a Search Console API query"
description: "Build a mobile page report, combine filters, and paginate Search Analytics results without confusing returned rows with complete data."
canonical_url: "https://gscdump.com/learn-google-search-console/api/query-builder"
last_updated: "2026-09-11"
---

Suppose you want the pages that received the most Web search clicks from mobile users in the United States. You need page rows, with device and country filters.

This guide uses Google's Search Analytics request body. If you haven't made a request yet, follow the [first API request](/learn-google-search-console/api) for authorization and the endpoint.

## Build one page report

The dates below are an example week. Replace them with the period you want to examine.

```json
{
  "startDate": "2026-09-01",
  "endDate": "2026-09-07",
  "type": "web",
  "dataState": "final",
  "dimensions": ["page"],
  "dimensionFilterGroups": [{
    "groupType": "and",
    "filters": [
      { "dimension": "device", "operator": "equals", "expression": "MOBILE" },
      { "dimension": "country", "operator": "equals", "expression": "usa" }
    ]
  }],
  "rowLimit": 100
}
```

`dimensions` decides what each row represents. Here, the row's first key is a page URL. Filters narrow the data included in those rows. You don't need to add `device` or `country` to the dimensions just to filter them.

If you add `device` to the dimensions, the keys follow that order: page, then device. That matters when your code turns the response into table columns. See Google's [query reference](https://developers.google.com/webmaster-tools/v1/searchanalytics/query) for the field definitions.

## Add detail only when it helps

For a first diagnosis, a page report is easier to interpret than page-by-query-by-device rows. Add `query` when you need to investigate the searches associated with a particular page.

Keep a separate request without page or query dimensions for headline totals. Google recommends this in its [data extraction guide](https://developers.google.com/webmaster-tools/v1/how-tos/all-your-data), because detailed requests can lose data.

For example, a decline in a page's clicks is a reason to inspect its queries. It doesn't establish that a specific query caused the decline when some query detail is missing.

## Combine filters deliberately

The filter group uses AND: both conditions must match. An OR filter group is not currently supported.

For alternatives within one text field, `includingRegex` can express a choice. This illustrative filter matches queries containing either product name:

```json
{
  "dimension": "query",
  "operator": "includingRegex",
  "expression": "(?i)(acme|northstar)"
}
```

Search Console uses RE2 syntax. Escape special characters when turning a literal name into a pattern. A regex you write for brand names is your own definition; it doesn't reproduce Google's [branded queries classification](/learn-google-search-console/performance/branded-queries-filter).

For separate requests representing alternative conditions, watch for overlap before adding totals. A query matching both conditions would otherwise be counted twice.

## Read the top rows, then paginate

The API normally orders results by clicks descending. Date-grouped results use date order. There is no request field for a custom sort.

`rowLimit` accepts up to 25,000 rows per response. `startRow` is a zero-based offset. To request the next page after 25,000 returned rows, keep the same request and set:

```json
{
  "rowLimit": 25000,
  "startRow": 25000
}
```

Those fields extend your original body; they are not a complete request by themselves. Continue until a response contains fewer rows than requested. Save the request's dates, filters, and dimensions with the result so later pages remain comparable.

A finished pagination loop means you've read the rows this request returned. Google does not guarantee every underlying row. The [export limits guide](/learn-google-search-console/limits/export-row-limits) separates pagination, internal limits, and anonymized queries.

## Keep recent data separate

`dataState: "final"` requests finalized data. Use `all` only when your report can label fresh data and handle later changes. For hour-by-hour analysis, use the [hourly request and metadata example](/learn-google-search-console/api/hourly-search-analytics-api).

When a detailed request becomes expensive, narrow the dates or remove dimensions you don't need. Retrying the same wide query may keep hitting the same [load quota](/learn-google-search-console/api/rate-limits).

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
