Google Search Console date picker not working: how to fetch data via API

Google Search Console date picker not working: how to fetch data via API

Last verified: October 16, 2026
22 min read
Guide
Technical SEO

#Why the Google Search Console date picker shows 1969

A malfunctioning date picker in the Google Search Console performance report exposes the weakness of relying on the web interface alone. On 13 October 2026 Barry Schwartz reported in Search Engine Roundtable that with a custom date range the report rejects the form with the message Date can't be after 1969-12-31. The picker was fixed, broke again on 14 October, and was working again a few hours later. While the outage lasts, analysts cannot filter historical data from the browser.

Google gave no cause, but the date itself says a lot. In the POSIX standard, Unix time counts the seconds elapsed since midnight on 1 January 1970 UTC. If a JavaScript date field receives null, an empty string or an object that is not ready yet, it easily ends up at the value 0. In time zones with a negative offset from UTC, that zero point falls on 31 December 1969, in US time zones between 16:00 and 19:00. The most probable explanation is therefore a timestamp equal to zero that reached the validator as the upper bound of the range.

Under that assumption, the validator compares the selected date with a bound set to 1969. Every real date is later, so the rule marks the range as invalid and blocks the chart.

For high-traffic sites, e-commerce stores and agencies managing dozens of portals, an outage like this paralyses day-to-day diagnostics. SEO work cannot depend on the stability of a single-page application (SPA). The solution that keeps analytics running without gaps is a direct integration with the official Google Search Console API.

                  Search Console Data Access Architecture
                  
    [GSC Web Interface]               [Search Analytics API v1]
             │                                    │
    UI errors, 1,000 row limit           Stable REST endpoint
    Unix epoch problem (1969)            25,000 rows per request
    No automated export                  50,000 rows per day
             │                                    │
             ▼                                    ▼
      [Web Browser]                     [Local DB / BigQuery]

#What are the limits of the Google Search Console UI compared to the API

The Google Search Console graphical interface was designed for a quick look at basic metrics, not for serious data engineering. Even when the date picker works properly, the web panel imposes constraints that distort the picture of a domain’s visibility.

The first constraint is the rigid display limit. The table in the Search Console panel shows at most 1,000 rows. For portals with hundreds of subpages and tens of thousands of long-tail queries, the user sees only part of the terms that bring traffic.

The second issue is data retention. Google Search Console deletes records older than 16 months. Without an automated archiving mechanism, multi-year Year-over-Year comparisons are impossible. The third factor is the anonymization of rare queries (anonymized queries): Google filters them out for privacy reasons in the panel, in the API and in the BigQuery export. The API, on the other hand, has no 1,000-row table limit, and queries run separately for each day return up to 50,000 rows per day per search type (Google documentation).

CapabilitySearch Console Web UISearch Analytics API
Row limit per request1,000 rows25,000 rows
Maximum number of rows1,000 (rigid table limit)50,000 per day per search type (startRow pagination)
Historical data retention16 months16 months, longer once stored in your own database
Vulnerability to frontend bugsHigh (UI errors, JS blocking)No UI layer (JSON response from a REST endpoint)
Reporting automationManual export clicks requiredFull automation (cron, workers, CI)
Multi-dimensional breakdownRestricted interactive filtersFull combinations: page + query + device + country

Using the API makes reporting independent of Google’s frontend bugs and gives developers control over the data archive.

#How to configure a service account for the Google Search Console API

To access the Search Analytics API without logging in through a browser every time via end-user OAuth2, configure a Service Account in Google Cloud Platform. A Service Account acts as an autonomous technical identity with its own cryptographic key pair.

First, create a project in the Google Cloud Console (console.cloud.google.com). Once the project exists, open the APIs & Services section, search for Google Search Console API and enable it.

Second, generate the service account in the IAM & Admin section, under Service Accounts. Give it a unique name, such as gsc-data-exporter. Once created, open the Keys tab and create a new private key in JSON format. The file downloads to your local disk. It contains the key ID, the service account email address and the PEM-encoded RSA private key.

{
  "type": "service_account",
  "project_id": "production-seo-pipeline",
  "private_key_id": "4a7b9c2d1e8f3a5b",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD5...\n-----END PRIVATE KEY-----\n",
  "client_email": "gsc-data-exporter@production-seo-pipeline.iam.gserviceaccount.com",
  "client_id": "102938475610293847561",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token"
}

Third, authorize the service account in Google Search Console. Copy the client_email address and open Search Console for the verified domain. Go to Settings, choose Users and permissions, and add the new email address with the Restricted or Full role. From then on the service account can query the Search Console endpoints for that property.

The private key JSON file must never end up in a public code repository. Add it to .gitignore or pass its contents as an encrypted environment variable on the production server.

#How to check which Search Console properties a service account can access

The most common cause of a 403 error after setting up a service account is a mismatch between the property address in the script and the one Search Console knows. Instead of guessing, ask the API. The sites.list method returns the properties the account can access, and each entry has two fields: siteUrl, written exactly as the other methods expect it, and permissionLevel (sites resource documentation).

The permissionLevel field takes one of four values: siteOwner (owner), siteFullUser (full permissions), siteRestrictedUser (restricted permissions) and siteUnverifiedUser (a user without a verified property). If the property is missing from the list, the service account email was not added in the Search Console settings or was added to a different property, for example to the https://www. prefix instead of the domain property.

const { data } = await searchconsole.sites.list();
for (const site of data.siteEntry || []) {
  console.log(site.siteUrl, site.permissionLevel);
}
// sc-domain:wppoland.com siteFullUser

The same resource has add, delete and get methods. For fetching data alone, the webmasters.readonly scope is enough, with list run once when the script starts: if the returned siteUrl differs from the configured one, the script can stop with a clear message before it fires hundreds of failing queries.

#How to fetch sc-domain and URL prefix data in Node.js

When working with the Search Console API, developers often hit a 403 or 404 error caused by an invalid site identifier format (siteUrl). Google supports two different property types:

  1. Domain Property: aggregates all protocols and subdomains. In the API its identifier must carry the sc-domain: prefix, such as sc-domain:wppoland.com.
  2. URL-prefix Property: covers a specific protocol and path. In the API its identifier is the full URL with a trailing slash, such as https://wppoland.com/en/.

On multilingual sites, the best practice is to query the prefix properties for individual language versions, or the domain property and then filter URL paths in code.

The following Node.js script shows a complete implementation of fetching performance data with pagination and saving it to a JSON file. It uses the official googleapis library.

import fs from "node:fs";
import path from "node:path";
import { google } from "googleapis";

async function runSearchConsoleExport() {
  const credentialsPath = path.resolve("./scripts/gsc-service-account.json");
  const creds = JSON.parse(fs.readFileSync(credentialsPath, "utf8"));

  if (creds.private_key) {
    creds.private_key = creds.private_key.replace(/\\n/g, "\n");
  }

  const auth = new google.auth.GoogleAuth({
    credentials: creds,
    scopes: ["https://www.googleapis.com/auth/webmasters.readonly"],
  });

  const client = await auth.getClient();
  const searchconsole = google.searchconsole({ version: "v1", auth: client });

  const siteUrl = "sc-domain:wppoland.com";

  // Offset 3 days back to allow Google performance aggregation to finalize
  const endDate = new Date(Date.now() - 3 * 864e5).toISOString().slice(0, 10);
  const startDate = new Date(Date.now() - 33 * 864e5).toISOString().slice(0, 10);

  console.log(`Starting extraction for ${siteUrl} between ${startDate} and ${endDate}`);

  const aggregatedRows = [];
  let startRow = 0;
  const rowLimit = 25000;

  while (true) {
    const response = await searchconsole.searchanalytics.query({
      siteUrl,
      requestBody: {
        startDate,
        endDate,
        dimensions: ["page", "query", "device", "country"],
        rowLimit,
        startRow,
      },
    });

    const rows = response.data.rows || [];
    aggregatedRows.push(...rows);
    console.log(`Extracted batch: ${rows.length} rows (Running total: ${aggregatedRows.length})`);

    if (rows.length < rowLimit) {
      break;
    }

    startRow += rowLimit;
  }

  const destination = "./reports/gsc-performance-data.json";
  fs.mkdirSync(path.dirname(destination), { recursive: true });
  fs.writeFileSync(destination, JSON.stringify(aggregatedRows, null, 2), "utf8");

  console.log(`Extraction complete. Saved ${aggregatedRows.length} rows to ${destination}`);
}

runSearchConsoleExport().catch((error) => {
  console.error("Search Console extraction failure:", error.message);
  process.exit(1);
});

The code iterates over result pages using the startRow parameter. When the API response contains fewer rows than the declared limit of 25,000, the loop ends. This lets you fetch the full query history without losing long-tail data.

#How to extract Search Console data using Python

For data engineers and teams working in Pandas and Jupyter, a Python script is the most convenient tool for extracting and cleaning Search Console data. The example below fetches data split by day and saves it to the optimized Parquet format, which takes less space than CSV and keeps column types.

The script needs the google-api-python-client, google-auth, pandas and pyarrow libraries:

pip install google-api-python-client google-auth pandas pyarrow

Here is the extraction script:

import datetime
import pandas as pd
from google.oauth2 import service_account
from googleapiclient.discovery import build

def export_search_analytics(site_url: str, days_window: int = 30) -> pd.DataFrame:
    key_file = "scripts/gsc-service-account.json"
    creds = service_account.Credentials.from_service_account_file(
        key_file,
        scopes=["https://www.googleapis.com/auth/webmasters.readonly"]
    )
    
    client = build("searchconsole", "v1", credentials=creds)
    
    end_date = (datetime.date.today() - datetime.timedelta(days=3)).strftime("%Y-%m-%d")
    start_date = (datetime.date.today() - datetime.timedelta(days=days_window + 3)).strftime("%Y-%m-%d")
    
    records = []
    start_row = 0
    row_limit = 25000
    
    while True:
        body = {
            "startDate": start_date,
            "endDate": end_date,
            "dimensions": ["date", "page", "query", "country", "device"],
            "rowLimit": row_limit,
            "startRow": start_row
        }
        
        response = client.searchanalytics().query(
            siteUrl=site_url,
            body=body
        ).execute()
        
        rows = response.get("rows", [])
        if not rows:
            break
            
        for item in rows:
            records.append({
                "date": item["keys"][0],
                "page": item["keys"][1],
                "query": item["keys"][2],
                "country": item["keys"][3],
                "device": item["keys"][4],
                "clicks": item["clicks"],
                "impressions": item["impressions"],
                "ctr": item["ctr"],
                "position": round(item["position"], 2)
            })
            
        print(f"Retrieved {len(rows)} records (startRow={start_row})")
        if len(rows) < row_limit:
            break
            
        start_row += row_limit
        
    df = pd.DataFrame(records)
    return df

if __name__ == "__main__":
    property_id = "sc-domain:wppoland.com"
    dataset = export_search_analytics(property_id, days_window=60)
    
    if not dataset.empty:
        dataset["date"] = pd.to_datetime(dataset["date"])
        dataset.to_parquet("reports/gsc_performance.parquet", index=False)
        print(f"Exported {len(dataset)} records into Parquet format.")
    else:
        print("No search records returned.")

Saving to the column-oriented Parquet format allows fast aggregation and grouping of queries by product category or WordPress page template without straining server memory.

#How to fetch fresh and hourly data from the Search Console API

The scripts above skip the last three days, because Google states that data is usually available after 2 to 3 days (guide to getting all your data). The same guide recommends a simple test: a query with the date dimension for the last 10 days shows which day is the latest one available.

Whether the API returns preliminary data is controlled by the dataState parameter (query method documentation):

dataState valueWhat the API returns
final (or no parameter)Finalized data only
allFresh data as well, which may still change
hourly_allHourly breakdown, partial, used with the hour dimension

With dataState: "all" and grouping by date, the response metadata contains a first_incomplete_date field. All values after that date may still change noticeably, so an archiving script should store them separately or overwrite them on the next run. Times in the metadata are given in the America/Los_Angeles time zone, which matters when you join the data with your own server logs.

Google added the hour dimension on 9 April 2025. The panel shows hourly data only for the last 24 hours, while the API returns it for up to 10 days (announcement on the Google Search Central Blog). This lets you compare the latest day with the same weekday a week earlier, for example after publishing a post or deploying a new template.

{
  "startDate": "2026-10-15",
  "endDate": "2026-10-15",
  "dataState": "hourly_all",
  "dimensions": ["hour"]
}

Keys in the response look like 2026-10-15T00:00:00-07:00, an hour in the Los Angeles time zone with its offset. Convert them to UTC before writing them to the database.

#How to filter pages and queries in the Search Analytics API

A query without filters returns all traffic for the property. On a multilingual site you usually need a slice, for example only URLs under /en/. That is what the dimensionFilterGroups array is for. You can filter on the country, device, page, query and searchAppearance dimensions, and the available operators are (query method documentation):

  • equals (default) and notEquals: exact match, case sensitive for page and query,
  • contains and notContains: substring match, case insensitive,
  • includingRegex and excludingRegex: a regular expression in RE2 syntax.
{
  "startDate": "2026-09-01",
  "endDate": "2026-09-30",
  "dimensions": ["page", "query"],
  "type": "web",
  "dimensionFilterGroups": [{
    "filters": [
      { "dimension": "page", "operator": "includingRegex", "expression": "^https://wppoland\\.com/en/" },
      { "dimension": "query", "operator": "notContains", "expression": "wppoland" }
    ]
  }],
  "rowLimit": 25000
}

The second filter removes branded queries, a typical step before long-tail analysis. The type parameter replaced the deprecated searchType and accepts web (default, the All tab without Discover and Google News), image, video, news (the News tab), discover and googleNews. Each type has to be fetched with a separate query.

The aggregationType parameter decides whether metrics are calculated by property (byProperty) or by URL (byPage); the default auto leaves the choice to Google. The byProperty value does not work for the discover and googleNews types.

#Why Search Console API totals differ from the chart

After the first export, almost every team notices that the sum of clicks across rows is lower than the number on the panel chart. This is not a bug in the script. Google describes three causes (guide to getting all your data):

  1. The API exposes at most 50,000 rows per day per search type, sorted by clicks. On large sites, the tail of queries below that threshold never reaches the response.
  2. When grouping by the page or query dimensions, the system may drop some data so that the calculations stay feasible.
  3. Impressions, clicks, position and CTR are calculated differently when aggregated by page than when aggregated by property.

On top of that come anonymized queries, which are missing from every source. The practical takeaway: take traffic totals from a query without the page and query dimensions (only date), and treat the breakdown by query as a sample ordered by clicks. Google also recommends fetching data day by day and paginating in steps of 25,000 rows until you get an empty page, separately for each search type.

#How to stream Search Console data into Google BigQuery

For large sites, the most outage-resistant setup is an automated export from Google Search Console to the Google BigQuery warehouse. Google launched Bulk Data Export on 21 February 2023: the mechanism sends a daily dump of performance data to a BigQuery project you choose (announcement on the Google Search Central Blog).

Key advantages:

  1. No 16-month limit: data stored in BigQuery stays as long as you need it.
  2. The export is not subject to the daily API row limit. Google filters out only anonymized queries, for privacy reasons.
  3. You can join Search Console data with WordPress database tables (WooCommerce orders, carts, conversions).

The export is set up in two steps. In Google Cloud Console you enable the BigQuery API in the project and grant permissions to the Search Console service account. In the Search Console settings you enter the project ID and the dataset location. Only a property owner can set up the export. Search Console first simulates the export; if the simulation succeeds, all owners receive an email and regular exports start within 48 hours. If it fails, an alert appears immediately.

The export creates three tables:

  • searchdata_site_impression: data aggregated by property, with query, country, search type and device.
  • searchdata_url_impression: data aggregated by URL, with query details and rich result details.
  • ExportLog: a record of which data reached the database on a given day. Failed exports are not logged here.

The following BigQuery SQL query identifies pages with high impressions and low CTR (candidates for reworking meta tags and headings):

SELECT
  url,
  query,
  SUM(impressions) AS total_impressions,
  SUM(clicks) AS total_clicks,
  ROUND(SAFE_DIVIDE(SUM(clicks), SUM(impressions)) * 100, 2) AS calculated_ctr,
  ROUND(SUM(sum_position) / SUM(impressions) + 1, 1) AS avg_position
FROM
  `production-project.searchconsole.searchdata_url_impression`
WHERE
  data_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND country = 'gbr'
GROUP BY
  url,
  query
HAVING
  total_impressions > 500
  AND calculated_ctr < 2.0
  AND avg_position BETWEEN 3.0 AND 10.0
ORDER BY
  total_impressions DESC
LIMIT 100;

The searchdata_url_impression table includes, among others, the data_date, url, query, country, search_type, impressions, clicks and sum_position columns, plus flags for rich result types (Google’s example filters on search_type = 'WEB'). The sum_position column counts position from zero, so the average position is calculated as SUM(sum_position) / SUM(impressions) + 1, as in Google’s example. The query picks out first-page terms in the UK market that convert below 2 percent of impressions into clicks. These are candidates for testing a new title, H1 heading and description; measure the effect of the change over the following weeks instead of assuming it in advance.

                    Search Console to BigQuery Data Pipeline
                    
   [Google Search Console] ──(Bulk Export)──> [Google BigQuery]
                                                    │
                                                    ├──> [Looker Studio Dashboard]
                                                    ├──> [Ranking Drop Anomaly Audit]
                                                    └──> [WooCommerce Conversion Joins]

#When to use the Search Analytics API vs Bulk Data Export

Both sources deliver the same metrics, but they solve different problems. In the export announcement, Google writes that the export is especially useful for large sites with tens of thousands of pages or with traffic from tens of thousands of queries per day, while small and medium sites can access all their data through the interface, the Looker Studio connector or the Search Analytics API (Google Search Central Blog).

CriterionSearch Analytics APIBulk Data Export
Row limit25,000 per request, 50,000 per day per search typeNo daily row limit
Anonymized queriesOmittedOmitted
FreshnessPreliminary (all) and hourly (hourly_all) dataDaily dump
Who can set it upAny user with access to the propertyProperty owner only
Where the data goesWherever your script stores itInto your BigQuery project

In practice the two complement each other. The BigQuery export serves as the archive and the source for long-tail analysis, while a lightweight API script with dataState: "hourly_all" watches the last few hours after a publication or deployment. For a small WordPress blog, the script from the previous sections, run once a day by cron, is usually enough.

#How to bind Search Console analytics to the WordPress database

Raw Search Console data gains the most business value once it is linked to the internal content structure of the CMS. A standard Search Console export contains only full URLs as text strings. It says nothing about the post type (post, WooCommerce product, landing page), the date of the last edit in the Gutenberg editor or the author of the text.

The integration comes down to translating the URL path into a WordPress object ID (post_id). In a WordPress environment, this is done with the url_to_postid($url) function or by matching the slug directly in the wp_posts table.

The following PHP code shows how to assign query data imported from the API to the right product or article in the database:

<?php
/**
 * Bind Search Console performance records to WordPress post entities
 */
declare(strict_types=1);

namespace WPPoland\Analytics;

class SearchConsoleIngestor {
    
    public function recordPageMetrics(string $fullUrl, int $clicks, int $impressions, float $position): void {
        $path = wp_parse_url($fullUrl, PHP_URL_PATH);
        if (!$path) {
            return;
        }

        $postId = url_to_postid($fullUrl);
        
        if ($postId === 0) {
            $postId = $this->resolveCategoryOrArchive($path);
        }

        if ($postId > 0) {
            update_post_meta($postId, '_gsc_last_30d_clicks', $clicks);
            update_post_meta($postId, '_gsc_last_30d_impressions', $impressions);
            update_post_meta($postId, '_gsc_avg_position', $position);
            update_post_meta($postId, '_gsc_synced_at', current_time('mysql', true));
        }
    }

    private function resolveCategoryOrArchive(string $path): int {
        global $wpdb;
        $cleanSlug = trim($path, '/');
        $segments = explode('/', $cleanSlug);
        $targetSlug = end($segments);

        $termId = $wpdb->get_var($wpdb->prepare(
            "SELECT t.term_id FROM {$wpdb->terms} t 
             JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id 
             WHERE t.slug = %s LIMIT 1",
            $targetSlug
        ));

        return $termId ? (int)$termId : 0;
    }
}

With this mapping, the editorial team sees the exact impressions and position of every page in the WordPress dashboard. If, after a template update or a new code deployment, an article’s average position drops from 4 to 18, the system can automatically send a Slack notification or create an audit task for the developer.

In architectures built on headless CMS development or static site generators, Search Console API data can be fetched at build time and used to generate dynamic sections with trending topics and related articles.

#How to check indexing status with the URL Inspection API

A drop in a post’s clicks in Search Analytics data does not tell you whether the page is still in the index. The URL Inspection API answers that question, using the same service account and the same scopes (webmasters or webmasters.readonly). The request is POST https://searchconsole.googleapis.com/v1/urlInspection/index:inspect with the fields inspectionUrl (the full URL, which must belong to the property), siteUrl (in the same format as before: sc-domain: or a prefix with a trailing slash) and an optional languageCode (inspect method documentation).

The indexStatusResult object includes, among others (UrlInspectionResult reference):

FieldWhat it means
verdictOverall result: whether the URL is indexed
coverageStateWhether Google found and indexed the page
indexingStateWhether a noindex rule blocks indexing
robotsTxtStateWhether robots.txt blocks crawling
lastCrawlTimeWhen the primary crawler last fetched the URL
googleCanonical and userCanonicalThe canonical chosen by Google and the one declared on the page

In WordPress this pairs well with the SearchConsoleIngestor class from the previous section: when a post’s position drops, the script inspects its URL and stores coverageState and googleCanonical in the post meta. A mismatch between Google’s canonical and the one set by your SEO plugin usually explains a drop faster than query analysis. The limit is low, though: 2,000 queries per day and 600 per minute per site (Search Console API limits), so inspect only URLs that show a drop signal, not the whole sitemap. The method shows the version from Google’s index and does not test the URL live. The difference between this tool and the Indexing API is covered in our guide to GSC and the Indexing API.

#How to manage API rate limits and network errors

The Search Analytics API has limits described in the Google documentation. Exceeding them returns a quota error, and the script has to wait:

Limit scopeValue
Per site (queries for the same property)1,200 queries per minute
Per user (queries from the same account)1,200 queries per minute
Per Google Cloud project40,000 queries per minute and 30,000,000 per day

A separate load quota applies, measured in 10-minute and daily windows. According to Google, queries are expensive when you group or filter by page or query, and the load grows with the length of the date range. Google explicitly advises against fetching the same data repeatedly, for example the whole previous month on every run. An archiving script should therefore fetch only the missing days.

To keep scripts that fetch millions of records for large e-commerce sites reliable, implement three safeguards:

  1. Exponential Backoff: when the script receives a 429 or 503 status code, it does not abort but waits an increasing number of seconds (2 to the power n plus random jitter) before retrying the request.
  2. Daily Date Chunking: rather than fetching a whole year in one call with huge pagination, split the job into one-day loops. If one query fails because of a temporary network error, you retry only the missing day.
  3. Access Token Caching: Google client libraries refresh the OAuth2 token automatically from the service account key, but in serverless environments (AWS Lambda, Cloudflare Workers) make sure the token is not generated anew for every single HTTP request.

The following JavaScript pattern shows a resilient query wrapper with retries:

async function executeWithRetry(apiOperation, maxRetries = 5) {
  let attempt = 0;
  while (attempt < maxRetries) {
    try {
      return await apiOperation();
    } catch (error) {
      attempt++;
      const isRateLimit = error.code === 429 || error.status === 429;
      const isTransientServerFault = error.code >= 500 && error.code < 600;

      if ((isRateLimit || isTransientServerFault) && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000 + Math.random() * 500;
        console.warn(`Request failed with code ${error.code}. Retrying in ${Math.round(delay)} ms (Attempt ${attempt}/${maxRetries})...`);
        await new Promise((resolve) => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
}

These three mechanisms keep SEO data archiving running regardless of errors in the browser-based Google Search Console panel.

#How to manage SEO data with the Search Console API

Graphical interface bugs, such as the date picker failure that rolled the calendar back to 1969, are a reminder that a site’s analytics data should live in the site owner’s own system, not only in an external panel.

An independent pipeline built on the Search Console API delivers measurable benefits:

  • Up to 50,000 rows per day per search type instead of the 1,000-row panel table, and with Bulk Data Export the full dataset minus anonymized queries.
  • Reporting that does not depend on Google’s frontend bugs.
  • Protection against losing historical data after 16 months, thanks to archiving in BigQuery or a relational database.
  • Direct correlation of traffic with WooCommerce store revenue and with changes to the WordPress theme code.

To implement advanced analytics, automate reporting or audit your site technically, consult a WordPress developer who will connect the data pipeline to your store’s architecture and protect it from failures. For technical consulting, contact our engineering team.

Next step

Turn the article into an actual implementation

This block strengthens internal linking and gives readers the most relevant next move instead of leaving them at a dead end.

Want this implemented on your site?

If visibility in Google and AI systems matters, I can build the content architecture, FAQ, schema, and internal linking needed for SEO, GEO, and AEO.

Related cluster

Explore other WordPress services and knowledge base

Strengthen your business with professional technical support in key areas of the WordPress ecosystem.

Why is the Google Search Console date picker stuck on 1969-12-31#
Google has not published a cause. The date itself points to a timestamp of zero, which is midnight on 1 January 1970 UTC (Unix epoch) and displays as 31 December 1969 in time zones west of Greenwich. Search Engine Roundtable reported the bug on 13 October 2026; the picker was fixed, broke again on 14 October and started working again the same day.
How many rows can you export using the Google Search Console API#
A single call to the searchanalytics.query method returns up to 25 000 rows (1000 by default). The startRow parameter lets you paginate results, but Google exposes at most 50 000 rows per day per search type through the API, sorted by clicks. A fuller dataset, without anonymized queries, comes from Bulk Data Export to BigQuery.
What is the difference between querying sc-domain and a URL prefix#
The sc-domain syntax queries an aggregated domain property across all subdomains and protocols. A URL prefix property targets an exact path and protocol, requiring a trailing slash in the siteUrl parameter.
How long does Google keep Search Console data#
Search Console stores performance data for 16 months. Once this window passes, historical data is deleted permanently. Exporting data to BigQuery or a relational database preserves multi-year records for Year-over-Year comparison.
How can you connect Search Console API data to WordPress#
You can correlate the page URL from the Search Analytics payload with the wp_posts database table using the url_to_postid function, allowing editors to track organic impressions and rank drops directly inside WordPress.

Need an FAQ tailored to your industry and market? We can build one aligned with your business goals.

Let’s discuss

Related Articles