Your Search Console API rows do not add up to the total: measure the gap in Python
You export every query for a property through the Search Console API, sum the clicks, and the number is lower than the total in the Performance report. Nothing is broken. But if you build reports on that sum without knowing how much is missing, you will overstate how well you understand your own traffic. This tutorial builds a small script that measures the gap: it fetches the property total,…
Your Search Console API rows do not always add up to the total clicks and impressions shown in the Performance report. After exporting every query through the API, summing the clicks reveals a lower number than what appears in the report. While nothing is broken, failing to account for the missing data will lead to an overestimation of your website's traffic understanding.
This guide presents a Python script that measures this gap, fetching the property total, retrieving all rows using pagination, and reporting the discrepancy. The script also illustrates what the gap actually reveals. The Performance report's official troubleshooting page lists the causes of the discrepancy. Two of the most significant reasons are anonymized queries and rare queries being omitted from the query table but included in the chart totals, unless a query filter is applied.
Another factor is row limits and truncation: the UI table displays a maximum of 1,000 rows, and when filtering by page or query, the match and does-not-match totals may not equal the unfiltered total due to anonymized queries and data truncation. Like the UI, the API functions similarly. A request without dimensions returns one aggregate row, while a request with dimensions: [query] provides the rows for that grouping, with any withheld data simply absent.
Thus, the critical question is not "why do they differ" but "by how much, for this property and this month." The API allows you to ask for the total number of rows (rowLimit), which accepts a value between 1 and 25,000, with a default of 1,000. This default silently truncates your export if you forget to set it. You can also use startRow for paging, a zero-based offset.
If it surpasses the number of results, you receive a successful response with zero rows. Setting dataState to final (or omitting it) returns only finalized data, excluding fresh data that can still change. Lastly, aggregationType can be byProperty or byPage, and totals can differ between the two, so it's essential to keep it consistent across the requests you compare.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.