Build Your Own AI Overview Tracker: Monitor Google AI Overviews by Keyword (2026)
Track which of your keywords trigger a Google AI Overview, what it says and whether your pages are cited — across countries, on a schedule, with Python, Node and SQL.
Why AI Overviews need their own tracker
For a growing set of queries, the first thing a searcher reads on Google is not a blue link but an AI Overview: a few sentences of answer and a short list of cited pages. Being one of those cited pages is the new position one. Being absent while a competitor is cited is a loss your rank tracker will not show you, because your organic position can stay exactly the same.
An AI Overview tracker answers four questions for every keyword you care about, in every market you sell in:
- Does Google show an AI Overview for this query at all?
- What does the overview say — and is it accurate about you?
- Which pages does it cite, and is one of them yours?
- How does that change over time and between countries?
Reading an AI Overview through Irmu
`GET /google-ai-overview` does the browser work for you. You send the `query` (up to 500 characters, as you would type it) and the `domain` of the Google to ask — `com`, `de`, `es`, `co.uk`, `com.br` and so on. Irmu builds the search URL, presses past the consent dialog a first visit is greeted with, expands the overview and reads it.
The response carries `ai_overview` (the answer as text, without its heading or Google's standing notice), `sources` (each cited page with `title` and `url`), the `url` that was read, `status`, and the credits charged and remaining. `premium` is on by default because the standard pool is the one Google turns away; it costs nothing extra here.
curl -G https://app.irmu.com/api/google-ai-overview \
-H "Authorization: Bearer $IRMU_API_KEY" \
--data-urlencode "query=best project management software for agencies" \
--data-urlencode "domain=co.uk" \
--data-urlencode "country=gb"{
"query": "best project management software for agencies",
"domain": "co.uk",
"url": "https://www.google.co.uk/search?q=best+project+management+software+for+agencies",
"ai_overview": "For agencies, popular options include…",
"sources": [
{ "title": "Example review site", "url": "https://example.com/best-pm-tools" }
],
"credits_charged": 30,
"credits_remaining": 970,
"job_id": "…",
"status": "done",
"position": null,
"debug": null,
"error": null
}Step 1 — Pick the keywords and markets
Start from the keywords that already bring you buyers, not the ones with the most volume: comparison queries ("best X for Y"), problem queries ("how to…") and alternative queries ("X alternative"). Twenty to fifty is plenty to begin with.
Then decide which Googles matter. `domain` decides the language the overview is written in, so `domain=de` gives you the German answer. Add `country` (and optionally `city`) to search from inside that market too — localized results are part of what you're measuring.
Step 2 — Run the queries on a schedule
Most calls answer with a 200. A long one can come back as a 202: it is paid for and still running, and you collect it for free from `GET /crawl/{job}`. Note the shape changes there — the answer arrives under `data.ai_overview` and `data.ai_overview_sources`.
import os, time, json, requests
BASE = "https://app.irmu.com/api"
H = {"Authorization": f"Bearer {os.environ['IRMU_API_KEY']}"}
KEYWORDS = ["best web scraping api", "web scraping api for developers"]
MARKETS = [("com", "us"), ("co.uk", "gb"), ("de", "de")]
def overview(query, domain, country):
r = requests.get(f"{BASE}/google-ai-overview", headers=H, timeout=200,
params={"query": query, "domain": domain, "country": country})
body = r.json()
if r.status_code == 200:
return body.get("ai_overview"), body.get("sources", []), body.get("status")
if r.status_code == 202:
job = body["job_id"]
while True:
time.sleep(3)
p = requests.get(f"{BASE}/crawl/{job}", headers=H, timeout=60)
if p.status_code != 202:
data = p.json().get("data") or {}
return data.get("ai_overview"), data.get("ai_overview_sources", []), "done"
raise RuntimeError(f"{r.status_code}: {body}")
rows = []
for kw in KEYWORDS:
for domain, country in MARKETS:
text, sources, status = overview(kw, domain, country)
rows.append({"query": kw, "domain": domain, "country": country,
"has_overview": text is not None, "ai_overview": text,
"sources": sources, "status": status})
print(json.dumps(rows, indent=2, ensure_ascii=False))Step 3 — Detect citations and mentions
Two signals matter most. A citation is your domain appearing in `sources`. A mention is your brand name appearing in the `ai_overview` text, cited or not. Track both for yourself and for each competitor.
const BRANDS = { irmu: ["irmu"], rivalA: ["rival-a"], rivalB: ["rival-b"] };
export function score(row) {
const text = (row.ai_overview ?? "").toLowerCase();
const hosts = row.sources.map((s) => new URL(s.url).hostname.replace(/^www\./, ""));
return Object.fromEntries(
Object.entries(BRANDS).map(([brand, terms]) => [brand, {
mentioned: terms.some((t) => text.includes(t)),
cited: hosts.some((h) => terms.some((t) => h.includes(t))),
citePosition: hosts.findIndex((h) => terms.some((t) => h.includes(t))) + 1 || null,
}]),
);
}Step 4 — Store snapshots so you can chart them
Keep every run, including runs with no overview. A keyword that stops triggering an overview is as important a change as a lost citation.
create table aio_snapshots (
id bigserial primary key,
query text not null,
domain text not null,
country text,
has_overview boolean not null,
ai_overview text,
sources jsonb not null default '[]',
captured_at timestamptz not null default now()
);
-- Share of tracked queries where we are cited, per market and week
select domain, date_trunc('week', captured_at) as week,
avg((sources::text ilike '%irmu.com%')::int) as cited_share
from aio_snapshots
where has_overview
group by 1, 2
order by 2 desc;What it costs
Every query is 30 credits flat — `premium`, `country` and `city` change where the search comes from, not the price. A query Google shows no overview for is still charged, because a null `ai_overview` with `status: done` is Google's answer. A crawl that fails with a 500 is refunded; a 402, 422 or 503 charges nothing.
So 40 keywords × 3 markets × weekly is 480 queries a month, or 14,400 credits — well inside the Lite plan. Check the pricing page for current plan volumes.
40 keywords × 3 markets × weekly = 14,400 credits a month.
Track ChatGPT alongside it
Google's overview and ChatGPT's answer often cite different sources for the same question. Running the same keyword set through `GET /chatgpt` gives you both AI surfaces in one dataset — see the ChatGPT brand monitoring guide for that half.
Turning the data into action
Look at the sources Google cites where you are absent: those are the pages, formats and sites it trusts for your topic. Fix inaccurate statements by fixing the public pages they come from. Then keep the schedule running and watch whether the next snapshots change.
Keep reading
ChatGPT Brand Monitoring: Track What AI Tells Your Customers (2026)
Build your own LLM visibility tracker: run a fixed set of buyer questions through ChatGPT on a schedule, record whether your brand is mentioned, where, and which sources are cited — with Python, Node and SQL.
AIAI Web Scraping: Extract Data Without Writing Selectors
When to ask a question about a page instead of writing CSS selectors, when to combine both in a recipe, and what each approach costs — with curl, Python and recipe JSON.
GuidesBooking.com API Alternative: Get Hotel Data Without Partner Approval
The official Booking.com API is only open to approved partners. Here's how to get search results, hotel details, room prices and ratings as JSON anyway — with curl, Python and Node examples.
Start building with Irmu today
200 free credits every month, no card required. Every API, every integration, one key.