Check citations by comparing normalized source hostnames with your domain. Run the same query list with fixed country and language values, then keep cited, not cited, no sources, no overview, and request failed as separate results. One match proves one observed citation, not permanent visibility.
To check whether your website is cited in Google AI Overviews, send each important search query to the API and inspect data.sources. Parse every source URL, extract its hostname, and compare that hostname with your domain. Save the query, country, language, and check time with the result.
A match proves that your domain appeared in one captured AI Overview for one query and market. It does not prove that the site is always cited. A failed request also does not mean "not cited." Keep those outcomes separate.
The current endpoint is GET /ai-overview with query, gl, and hl. The Google AI Overviews API product page documents the current request path and plans.
Check one query and inspect its sources
What counts as a website citation?
For this checker, a citation is a returned source whose hostname equals your target domain. You can also choose to include subdomains. For example, docs.example.com belongs to example.com when subdomain matching is enabled.
Do not search for the domain as plain text inside a URL. The expression "example.com" in url also matches notexample.com and may match text inside a query string. A URL parser gives you the actual hostname.
A brand mention is different. Google may mention a brand in data.ai_overview without citing the brand's website. It may also cite a page without writing the brand name in the answer. Track mentions and linked citations as separate values.
Which queries should you check?
Start with searches connected with pages, products, or problems your site actually covers. A small list you understand is easier to review than an export containing thousands of unrelated keywords.
| Input | Example | Why you need it |
|---|---|---|
| Target domain | example.com | Defines the hostname you want to find |
| Query | how does a heat pump work | Identifies the search you checked |
| Country | us | Keeps results from different markets separate |
| Language | en | Keeps language variants separate |
| Check time | UTC timestamp | Shows when the observation was collected |
Use the same query list and inputs when you compare two dates. Otherwise, a change in the report may come from a different test setup rather than a different Google result.
Request the AI Overview and keep the sources
curl --request GET \
--url "https://google-ai-overviews.p.rapidapi.com/ai-overview?query=how%20does%20a%20heat%20pump%20work&gl=us&hl=en" \
--header "x-rapidapi-host: google-ai-overviews.p.rapidapi.com" \
--header "x-rapidapi-key: $RAPIDAPI_KEY"
In the live test from August 5, 2026, each source object could contain url, title, site, and position. The answer was in data.ai_overview. These are test observations, so your code should still check types before using the fields.
| Field | How the checker uses it |
|---|---|
data.ai_overview | Distinguishes an answer from a result with no overview |
data.sources | Provides the list searched for matching domains |
source.url | Provides the cited page and a hostname fallback |
source.site | Provides a domain value when present |
source.position | Records the observed order of the source |
Check the HTTP status before reading this data. A timeout or server error belongs in the run log. Never convert it into a clean "not cited" result.
A complete Python domain checker
The script below calls the endpoint once per query. It removes a leading www., accepts subdomains, and rejects lookalike domains such as notexample.com.
import os
from urllib.parse import urlparse
import requests
API_URL = "https://google-ai-overviews.p.rapidapi.com/ai-overview"
TARGET_DOMAIN = "example.com"
QUERIES = [
"how does a heat pump work",
"heat pump maintenance checklist",
]
def normalize_host(value):
if not isinstance(value, str) or not value.strip():
raise ValueError("The hostname is empty.")
candidate = value.strip().lower()
if "://" not in candidate:
candidate = f"https://{candidate}"
host = urlparse(candidate).hostname
if not host:
raise ValueError(f"Cannot read a hostname from: {value}")
host = host.rstrip(".")
return host[4:] if host.startswith("www.") else host
def is_same_domain(source, target_domain, include_subdomains=True):
if not isinstance(source, dict):
return False
source_value = source.get("site") or source.get("url")
if not isinstance(source_value, str):
return False
try:
source_host = normalize_host(source_value)
target_host = normalize_host(target_domain)
except ValueError:
return False
if source_host == target_host:
return True
return include_subdomains and source_host.endswith(f".{target_host}")
def check_query(query, api_key, target_domain):
response = requests.get(
API_URL,
headers={
"x-rapidapi-host": "google-ai-overviews.p.rapidapi.com",
"x-rapidapi-key": api_key,
},
params={"query": query, "gl": "us", "hl": "en"},
timeout=45,
)
response.raise_for_status()
payload = response.json()
if not isinstance(payload, dict):
raise RuntimeError("The API response is not a JSON object.")
data = payload.get("data")
if payload.get("status") != 200 or not isinstance(data, dict):
message = payload.get("description") or "Unexpected API response"
raise RuntimeError(message)
answer = data.get("ai_overview")
sources = data.get("sources")
if not isinstance(sources, list):
sources = []
matches =
if not isinstance(answer, str) or not answer.strip():
state = "no_overview"
elif matches:
state = "cited"
elif not sources:
state = "no_sources"
else:
state = "not_cited"
return {"query": query, "state": state, "matches": matches}
def main():
api_key = os.environ.get("RAPIDAPI_KEY")
if not api_key:
raise RuntimeError("Set the RAPIDAPI_KEY environment variable first.")
for query in QUERIES:
try:
result = check_query(query, api_key, TARGET_DOMAIN)
except (requests.RequestException, RuntimeError) as error:
print(f"\n{query}: request_failed ({error})")
continue
print(f"\n{query}: {result['state']}")
for source in result["matches"]:
print(f"- {source.get('url', 'URL missing')}")
if __name__ == "__main__":
main()
Install the dependency with python -m pip install requests. Set RAPIDAPI_KEY in your terminal, replace TARGET_DOMAIN and QUERIES, then run the file. On PowerShell, set the key with $env:RAPIDAPI_KEY="your-key".
Run the checker against live JSON
Keep five result states separate
| State | Meaning | Next action |
|---|---|---|
cited | At least one valid source matches the target domain | Store every matching URL |
not_cited | An answer and sources exist, but no source matches | Keep the completed observation |
no_sources | An answer exists without a usable source list | Store an empty citation list |
no_overview | No usable AI Overview answer was returned | Record that the query was checked |
request_failed | The request timed out, returned an HTTP error, or broke the expected contract | Retry when appropriate and preserve the error |
The distinction matters when you calculate a citation rate. Use completed checks with an actual overview as the denominator. Report no-overview and failed requests separately so they cannot improve or damage the percentage by accident.
Store evidence instead of one Boolean
A useful record contains the query, gl, hl, observation time, result state, answer, full source list, and matched URLs. Keep the returned source URL even if you later resolve its redirects.
Do not overwrite yesterday's result. Google explains that AI Overviews appear only when its systems decide they add value to classic Search, and the returned links can vary. One current Boolean cannot show when a citation appeared or disappeared.
Your monthly request count is:
queries * countries * languages * checks per month
For example, 50 queries checked in two countries once a week require about 50 * 2 * 1 * 4 = 400 requests per month. Calculate this before choosing an API plan.
Can Search Console replace the API check?
No. Search Console reports performance and visibility for your verified property. The API check answers a narrower question: which source pages appeared in one captured AI Overview response. Search Console does not provide the full competing source list returned by this endpoint.
Use Search Console to understand impressions, clicks, and search visibility. Use the API dataset when you need query-level citation evidence with the returned source URLs.
For every response field and error state, read the Google AI Overviews API response guide. To compare several domains, continue with the AI Overview competitor monitor.
Frequently asked questions
Does one match prove broad AI Overview visibility?
No. It proves one citation for one query, country, language, and check time. Broader conclusions need a defined query set and repeated checks.
Should subdomains count?
Decide before collecting results. Documentation sites often want docs.example.com included under example.com. A marketplace comparing independent hosts may require exact matching.
Should the checker follow redirects?
Keep the URL returned by the API as the original evidence. If redirects matter, resolve them in a separate step and store both URLs.
How often should it run?
Match the schedule to your decision. A weekly content review rarely needs hourly checks. Use the request formula above before increasing frequency.
Sources and verification dates
- DataOcean Google AI Overviews on RapidAPI, listing checked September 22, 2026.
- Let's Scrape Google AI Overviews API product page, endpoint and request inputs checked September 22, 2026.
- Google Search Central documentation for AI features, checked September 22, 2026.
- Google Search Central announcement for generative AI performance reports, checked September 22, 2026.
The response field names and temporary error behavior referenced in this guide come from a live product test performed on August 5, 2026. They are dated observations, not guarantees about future responses.