How to Connect Your AI Assistant to Google Search Console

How to Connect Your AI Assistant to Google Search Console
Photo by Myriam Jessier / Unsplash

I wanted Claude to pull real Search Console data instead of me screenshot-ting graphs into a chat every time. Turns out it's a five-minute setup once you know where the permission actually lives — most of the friction is that it's split across two completely separate systems (GCP and Search Console itself), and skipping either one just gets you a silent empty result, not an error.

Setup

  1. Pick a GCP project. console.cloud.google.com → project switcher top-left → New Project (or reuse one you already have).
  2. Enable the Search Console API. APIs & Services → Library → search "Google Search Console API" → Enable.
  3. Create a service account. IAM & Admin → Service Accounts → Create Service Account. No IAM roles needed on the project itself — permission comes from Search Console, not GCP IAM.
  4. Generate a key. Open the service account → Keys tab → Add Key → Create new key → JSON. Downloads a file, keep it out of git.
  5. Add the service account inside Search Console itself. search.google.com/search-console → pick the property → Settings → Users and permissions → Add user → paste the service account's email ([email protected]) → permission level Full. This is the step people forget — the GCP-side setup alone grants zero access, Search Console keeps its own separate permission list.

Or you could just do it like this: if you already have gcloud installed and authenticated, steps 1–4 collapse into four commands —

gcloud projects create my-project-id
gcloud services enable searchconsole.googleapis.com --project=my-project-id
gcloud iam service-accounts create gsc-reader --project=my-project-id
gcloud iam service-accounts keys create creds.json \
  [email protected]

Step 5 still can't be skipped either way — that permission lives in Search Console's own system, not GCP IAM, so there's no gcloud command for it.

Querying it

from google.oauth2 import service_account
from googleapiclient.discovery import build

creds = service_account.Credentials.from_service_account_file(
    "creds.json", scopes=["https://www.googleapis.com/auth/webmasters.readonly"])
service = build("searchconsole", "v1", credentials=creds)

body = {
    "startDate": "2026-04-27",
    "endDate": "2026-07-25",
    "dimensions": ["query"],
    "rowLimit": 25,
}
r = service.searchanalytics().query(siteUrl="sc-domain:example.com", body=body).execute()
# rows come back sorted by impressions, highest first

Same service object also gives you sitemaps().list(), urlInspection().index().inspect() for per-URL indexing status, and searchanalytics().query() sliced by page instead of query. Swap the scope to the full (non-readonly) webmasters one if you need to submit sitemaps instead of just reading.

Why I set this up

  • Real numbers, not screenshots. Claude can pull the actual rows instead of me describing a chart to it.
  • It catches things I'd skim past. First time I ran this on a live site, the query list had a handful of completely unrelated foreign-language queries mixed in — looked exactly like a hacked-site keyword-injection pattern. Turned out to be a much more boring bug (a route not 404ing properly on garbage URLs), but I'd have never gone looking without the raw query data in front of me.
  • Read-only by default. The .readonly scope means an AI assistant poking around can't accidentally submit or change anything — worth defaulting to that scope unless you specifically need to push a sitemap.

Downside is there's no API for "request indexing" on a URL — that action only exists as a button in the Search Console UI (there's a separate Indexing API, but it's restricted to job-posting/livestream markup, doesn't apply to normal pages). So this setup is great for reading data and spotting problems, but you'll still end up back in the browser for that one specific action.

Source

Subscribe to Building software. Writing what I learn.

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe