The Search Console 1,000-row limit is the Performance export. Google's export help says the download is truncated to 1,000 representative rows. For a small property that may be every named row. For a large one it is not. The chart totals in the same file include the truncated data, so a sum of the 1,000 rows that sits under the headline is the cap, not a tracking bug.
The API is a second limit, not a way around the first one until you change the request. The Search Analytics query reference (page updated 11 August 2026) says rowLimit defaults to 1,000 and accepts 1 to 25,000. A script that never sets it repeats the UI cap. The performance-data deep dive puts the ceiling at 50,000 rows per day per site per search type. You reach the second half with startRow 25,000. Getting all your data says to page in steps of 25,000 until a response comes back empty, and to query one day at a time so the row budget is not spent on the first day of a long range.
Ways past the export button: raise rowLimit (Search Analytics for Sheets can do this without code), turn on bulk data export to BigQuery for days after you set it up, or use a hosted archive that imports daily. The Performance table in the interface is a top list. It is not the API, and it is not the bulk export.
The rest of this page is those export paths, then the arithmetic of the caps: the UI's 1,000, the API's default 1,000, the 25,000-row page, and Google's 50,000-row day. The headline and the table are different objects. Summing the table does not rebuild the headline.
If the property is not connected to SiteLine yet, start with Connect Google Search Console to SiteLine.
SiteLine imports up to 25,000 rows per day per report. That is one Search Analytics API page, not the second page that would reach Google's 50,000-row ceiling. It is also not a claim that 25,000 rows are the whole property. Rare queries are anonymised and never appear as rows. Headline clicks and impressions come from site totals, stored separately. A table footer is the total of the rows in the table.
How to export more than 1,000 rows
| Path | Row shape | Notes |
|---|---|---|
| UI export (CSV, Google Sheets, Excel) | About 1,000 representative rows | The same table you see. Chart totals in the file include the truncated data. Fine for a slide, not for analysis |
| Search Analytics for Sheets | Whatever rowLimit the add-on requests |
Calls the API. A default of 1,000 recreates the UI cap. Raise it to 25,000 for a real API pull |
| Your own script or Excel query | 1 to 25,000 per request, optional second page | The default rowLimit is still 1,000 until you set it. You own auth, quota, scheduling and storage |
| BigQuery bulk export | The full named-row set Google keeps, going forward | Not bound by the interactive API's daily ceiling. Forward-only, and you run the Google Cloud project |
| Hosted archive (SiteLine) | Up to 25,000 rows per day per report | Backfills what Google still holds, then imports daily. No scripts or SQL |
Search Analytics for Sheets is the quickest bridge if you want a spreadsheet without a pipeline. Check the dimensions, the date range and especially rowLimit. A multi-day query pull can spend the whole row budget on the first day and look empty afterwards, so pull breakdowns one day at a time.
The API. rowLimit accepts 1 to 25,000 and defaults to 1,000. Results are sorted by clicks, descending, except when you group by date: the query reference says those rows come back oldest first. A multi-day query or page request can still spend the entire row budget on the first days and return nothing useful for the rest, with no error. To reach Google's ceiling of about 50,000 rows per day per search type, send a second request with startRow 25,000 and rowLimit 25,000 (Google's guide to getting all your data). Request one day at a time for breakdowns, and keep a date-grouped request for site totals. Even the full 50,000 does not name anonymised queries and is not a site total. To sort a CSV once you have it, the free GSC opportunity analyzer finds striking-distance queries and cannibalisation in a Performance export, in your browser.
The API also has a dataState switch the UI export does not expose. Omit it, or send final, and the response is finalised data only. Send all and Google includes fresh rows that can still change. SiteLine's import uses the fresh rows. A "final only" script and a fresh import of the same day will disagree, and that disagreement is not the 1,000-row cut.
BigQuery bulk export sends daily Performance data into your own BigQuery project. The trade-offs: it is forward-only, with the first export up to about 48 hours after setup and no backfill of the 16 months already in Search Console; you run a billing-enabled Google Cloud project; and the interface is SQL. It fits when you need maximum row completeness from now on and already live in GCP. It is the wrong first step if you still need history Google holds today. Many teams run two paths: BigQuery for forward completeness plus an API or hosted backfill so months already in Search Console are not lost when the window rolls on (see the 16-month limit and BigQuery vs hosted).
Hosted archive. SiteLine connects with the read-only webmasters.readonly scope, backfills up to 16 months on connect, stores site totals separately so headlines are not rebuilt by summing rows, and keeps imported days while you subscribe. Plans start at $4.99 a month with a 7-day trial and no card. Create an account, or sign up with MCP intent if you want an agent to read the data first.
Three cuts that get called "the data"
Read these as three different scissors. They stack. Passing one of them does not mean you passed the others.
| Cut | What Google or SiteLine actually does | What it is safe to add up |
|---|---|---|
| Chart / site totals | Property-level clicks, impressions, CTR, and position for that day and search type. Totals include rows the table never lists | The headline, the sparkline, the year-over-year on totals |
| UI export | Truncated to 1,000 representative rows. Chart totals in the same file include the truncated data | A working list. Not a site total |
| API default | rowLimit defaults to 1,000, even though you are not in the UI |
The same 1,000-row shape, unless you raise the limit |
| API maximum page | rowLimit may be set from 1 to 25,000. Click-descending, except a date grouping, which is oldest first |
Up to 25,000 named rows for that request |
| Google's ceiling | At most 50,000 rows per day per search type, so a second request with startRow 25,000 can ask for rows 25,001–50,000 |
Still a ranked sample of named rows, not the anonymised queries |
| SiteLine | One page: at most 25,000 rows stored per day per report. The second page is not requested | "Of the rows we stored." Never the site total |
Sources, in the order those sentences come from Google: the export help for the 1,000 representative rows and for totals that include truncated data; the Search Analytics query reference for the default rowLimit of 1,000, the maximum of 25,000, and click-descending sort; the performance-data deep dive for the UI maximum of 1,000, the API default of 1,000, rowLimit 25,000, startRow for rows 25,001–50,000, and the 50,000-row ceiling per day per site per search type; the how-to for getting all your data for the same 50,000-row ceiling per day per search type and for paging in steps of 25,000.
The Performance report overview describes the chart and the table as a product: clicks, impressions, CTR as clicks divided by impressions, average position, and a table grouped by query, page, country, device, search appearance, or date. It also says chart totals can differ from table totals because of aggregation, property versus page. That aggregation gap is real, and it is not the truncation gap. Quote the cause you mean.
Google's deep dive adds a third gap that is easy to blend into the row cap. Anonymised queries are queries that were not issued by more than a few dozen users over a two-to-three month period. They are omitted from tables and from the API. They stay in chart totals unless you filter by query. More rows do not name them. A 25,000-row import does not name them. A 50,000-row import would not name them either.
For requests that do not involve a query or a URL — countries, devices, and search appearance — the deep dive says Search Console displays and exports all of the data. Those tables are short. The 1,000-row UI cut is a query and page problem. SiteLine still stores those smaller reports under the same per-report ceiling, and they simply never approach it.
A limit illustration, not a customer result
The figures in this section are arithmetic about the caps. They are not traffic from a property, not a share of anyone's clicks, and not a measurement SiteLine took. Rows are not clicks. A row with one click and a row with ten thousand clicks each count as one toward the cap. The API sorts by clicks, so the rows that fall past a cut are the lower-click part of that ranked list. This illustration does not assign those rows a click total.
Case A. The stored page is full. A report-day has 25,000 stored rows. That is SiteLine's cap: one API page of 25,000. The UI export of the same kind of table contains 1,000 representative rows.
25,000 − 1,000 = 24,000
The export leaves 24,000 of those stored rows out. Twenty-four thousand is a row count. It is the stored list minus the export length. It is not a percentage of demand, and it is not "missing traffic." The 1,000 rows Google put in the file are the representative slice the export help describes. The other 24,000 are still rows in the stored report. They are absent from that spreadsheet.
Case B. The day is small. A site has 400 query rows that day. Four hundred is less than one thousand.
400 < 1,000
The UI export already has all 400. Rows left out by the export: 400 − 400 = 0. There is no second pile of named queries hiding behind the export button. Google's export help says the same thing in prose: on a smaller site the 1,000 rows may be most or all of the data. Anonymised queries are still not in the 400. They were never rows. The chart total can sit above the sum of the 400 for that reason alone. Case B being "complete" means every named query row fit. It does not mean every click has a query string.
Put the two cases in one table so the subtraction stays visible:
| Limit illustration | Named rows stored for that report-day | Rows in the 1,000-row UI export | Stored rows the export does not contain |
|---|---|---|---|
| Full stored page | 25,000 | 1,000 | 25,000 − 1,000 = 24,000 |
| Small query day | 400 | 400 | 400 − 400 = 0 |
Case C. Google's ceiling, which SiteLine does not store. The deep dive and the how-to both put the API ceiling at 50,000 rows per day per search type. The second page is startRow 25,000 and another rowLimit of 25,000, which is rows 25,001 through 50,000. SiteLine does not send that request.
50,000 − 25,000 = 25,000
On a day where Google would serve the full ceiling, one page stores 25,000 rows and leaves the other 25,000 unfetched. SiteLine does not store more than 25,000 rows per day per report. The UI export is still 1,000 rows. Of the 25,000 that were stored, the export still leaves 24,000 out, which is Case A again. The unfetched second page is a separate 25,000 rows, and it is not part of the 24,000. Keep those gaps in separate sentences: rows the spreadsheet dropped from the stored page, and rows the importer never requested past 25,000.
A day with 12,000 named rows sits between the cases. SiteLine stores 12,000, because 12,000 is under 25,000. The UI export stores 1,000 of them and leaves 12,000 − 1,000 = 11,000 named rows out of the file. The API's default rowLimit of 1,000 would do the same if a script forgot to raise it. Setting rowLimit to 25,000 is what makes 12,000 come back in one response. The default is why a "we used the API" pipeline can still be a 1,000-row export with extra steps.
Google's own numeric picture of anonymised queries
The row arithmetic above is not Google's privacy filter. Google published a separate illustration, and they flagged that it ignores the daily row limit. In the deep dive, four itemised queries are the entire named list:
| Queries | Clicks |
|---|---|
| classic literature | 150 |
| poetry | 125 |
| science fiction | 100 |
| non fiction | 75 |
| Total for itemised queries | 450 |
| Total overall | 550 |
150 + 125 + 100 + 75 = 450. The chart total in their illustration is 550. 550 − 450 = 100 clicks that have no query row. Those 100 are not sitting at row 1,001 waiting for a higher rowLimit. They are withheld. Filtering to queries that contain "fiction" yields 175 (100 + 75). Excluding "fiction" yields 275 (150 + 125). 175 + 275 = 450, and the chart still says 550. Any filter on query drops the anonymised clicks from both sides, so the two filtered totals add up to the named list, not to the chart.
Use that when a sum of rows misses the headline. First ask whether you are looking at anonymised demand. Then ask whether the table was also cut at 1,000 or at 25,000. The fixes differ. You cannot import your way to the anonymised strings. You can import your way from 1,000 named rows to 25,000 named rows, on days that have more than 1,000.
What the 1,000-row file costs you, in rows rather than in a slogan
The missing rows are the ones past the representative cut, which on the API's sort is the lower-click end of the list. A monthly paste of the UI export into a deck is the head of the list. It is a poor place to see:
- Queries with a few dozen impressions and no clicks, the ones a title change is for. They sort to the bottom when the table is ranked by clicks, so they are exactly the rows a 1,000-row click-sort drops first on a large property.
- A second URL that only appears once the query is broken out by page. Query-plus-page is a different report, with its own 25,000-row page. The UI's 1,000 rows of queries will not show that split.
- Country or device cuts attached to a query. Countries alone are a small dimension and, per the deep dive, export in full. Country crossed with query is a query report again, and it hits the same caps.
SiteLine's import is daily, per report, per search type: query, page, query plus page, country, device, and search appearance. One day per request on the breakdowns, because a multi-day query request applies the row limit to the whole response and can keep the first day while dropping the rest. Site totals are the exception: grouped by date, one row per day, so the 16-month headline series is a single request and is not trimmed by the 25,000-row page. That split is why a sparkline can be complete on a day when the query table is capped. The 16-month limit is the calendar that then deletes the day on Google's side. Keeping the imported day while the subscription continues is what makes "this URL, last spring" a question you can still ask after the Performance report has rolled that spring off.
Do not average the export into a new total
Two spreadsheet habits make a 1,000-row file worse than the truncation already did. This illustration uses two rows so the arithmetic is visible. It is not a site.
| Row | Clicks | Impressions | CTR | Position |
|---|---|---|---|---|
| Row A | 10 | 100 | 10 ÷ 100 = 0.10 | 2.0 |
| Row B | 2 | 1,000 | 2 ÷ 1,000 = 0.002 | 8.0 |
Unweighted average position: (2.0 + 8.0) ÷ 2 = 5.0. Impression-weighted position: (2.0 × 100 + 8.0 × 1,000) ÷ (100 + 1,000) = (200 + 8,000) ÷ 1,100 = 8,200 ÷ 1,100 = 7.4545…. Five treats the 100-impression row like the 1,000-impression row. The weighted figure is the position of this pair. A 1,000-row export has the same bug at a larger size: AVG(position) is not the Performance report's average position.
Unweighted average CTR: (0.10 + 0.002) ÷ 2 = 0.051. CTR from the sums: (10 + 2) ÷ (100 + 1,000) = 12 ÷ 1,100 = 0.01090…. The report's CTR is the second one, and only for these two rows. Site CTR is clicks ÷ impressions on the site totals, a third ratio, because anonymised queries and any rows past the cap are in the site totals and not in this pair. Quote site CTR from site totals. Quote a row's CTR from that row. If you need a CTR for a named set, sum that set's clicks and divide by that set's impressions, and label the set.
The API returns CTR from 0 to 1. Multiplying by 100 is a display choice. Averaging the displayed percentages is the same mistake as averaging the ratios.
How to read a long list next to analytics
More rows are for diagnosis. They are not a bigger total.
- Take Web site totals for the last 28 days that Search Console has actually published. The lag is typically 2–3 days, so "last 28" usually ends before yesterday. Clicks versus sessions is why you do not then subtract on-site visitors from those clicks.
- Open pages before queries. Pages are fewer, and they are the join key to the tracker. The tracker records the URL that rendered. Google records the URL it ranked. A redirect splits them. Group on purpose.
- For a page that moved, open its queries. You are in the incomplete table on purpose. Say "of the queries we can see." If that day stored 25,000 query rows, remember Case A: a UI export of the same day would have left 24,000 of those rows out. If the day had 400, the UI already had all 400 named rows, and the remaining gap to the chart is anonymisation, not the export.
- On the cookieless side, open the same path: pageviews, and visitor-days as the daily hash of truncated IP (/24 v4, /48 v6), user agent, and daily salt. Goals on that path are a third on-site number. None of them completes the anonymised queries. Organic traffic versus Search Console covers the channel-name version of putting them in one column.
MCP follows the same split. Site overview for totals. Top results for the stored rows. Every response includes data_through, so a model can see the publish lag, and a note that the rows do not sum to the property. An agent that adds the top queries until they match the overview is ignoring the note.
The import scope is webmasters.readonly. Unlimited sites on the Search Console side. Plans start at $4.99, $19.99, and $99.99 a month; import rows are not analytics events. The tracker, if you want the on-site half, is /docs/script. Connect at /register.
If the SEO process still starts from a 1,000-row export, the process is ranking a representative list and reporting the chart beside it as if the list were the chart. Keep the chart for the total. Keep the longest named list you actually stored for the questions a total cannot answer.
FAQ
Why does SiteLine stop at 25,000 rows if Google can return 50,000?
25,000 is one API page, ranked by clicks. The second page would be another request, startRow 25,000, for rows 25,001–50,000. SiteLine does not send it. On a day at Google's ceiling that leaves 50,000 − 25,000 = 25,000 rows unfetched. Headlines still come from site totals either way. The extra page would be more named rows, still not the anonymised ones.
If a day only has 400 query rows, is the UI hiding the rest?
No. 400 is under 1,000, so the export already contains all 400 named rows. The arithmetic is 400 − 400 = 0 rows left out by that cap. The chart can still be higher because anonymised queries are included in totals and omitted from the table. That gap is not the 1,000-row cut.
Can I add query-row clicks until they match the site?
No. Anonymised queries are omitted on purpose. Rows past 1,000, or past 25,000, are a second reason the sum falls short, on days large enough to hit those caps. When the sums disagree, believe the site total and say whether you are looking at withheld queries, a truncated table, or both.
Does the 1,000-row cap apply to the Search Analytics API?
The UI export cap is 1,000 representative rows. The API's default rowLimit is also 1,000, which is how a script repeats the UI without meaning to. The maximum per request is 25,000. Google exposes at most 50,000 rows per day per search type if you page. A download from the Search Console website is still 1,000. The practical paths past that download are in the export section at the top of this guide.
Is 24,000 rows the same thing as 24,000 lost clicks?
No. In the limit illustration, 25,000 stored rows minus a 1,000-row export is 24,000 rows. Rows are ranked by clicks, so those 24,000 are the lower-click part of the stored page. This guide does not turn that row count into a share of clicks or impressions. Use site totals when you need the click count.
Does Search Analytics for Sheets bypass the limit?
It can, if the add-on requests a higher API rowLimit (up to 25,000 per call) and you pull breakdowns one day at a time. If rowLimit stays at 1,000 you get the UI shape inside Sheets.
Will BigQuery bulk export give me my last 16 months?
No. Bulk export is forward-only from the day you set it up. For history Google still holds, use the API or a hosted archive that backfills on connect, before the 16-month window drops it.
Do country and device tables hit the same wall?
Google says country, device, and search appearance requests, the ones without a query or URL, are displayed and exported in full. They are small. Query, page, and query-plus-page are where 1,000 and then 25,000 bind. Each of those is its own report-day, with its own cap. Filling the query report does not empty the page report.
Why not pull sixteen months of queries in one API call?
The row limit applies to the response, not to each day inside it. A single call grouped by date and query across a long range can spend the entire 25,000 rows on the first day and return nothing useful for the rest, with no error. Site totals can span the window because they are one row per day. Breakdowns are requested one day at a time so the cap means "this day."