The response uses an outer envelope and a data object. Check HTTP status first, then JSON status. Read the answer from data.ai_overview and citations from data.sources. A valid request may still return no AI Overview or an answer without sources.
A Google AI Overviews API response has two parts: an outer envelope and a data object. First check the HTTP status. Then check the numeric status in the JSON. If both are successful, read data.ai_overview for the answer and data.sources for cited pages.
Do not assume that every successful request contains an answer or citations. Google does not show an AI Overview for every search. Your parser should accept three normal result states: no overview, an answer without sources, and an answer with sources.
The endpoint is GET /ai-overview. The request uses query, gl, and hl. See the Google AI Overviews API product page for the current request limits.
Open the API and inspect a response
What is the response shape?
A successful response observed on August 5, 2026 used this structure. The answer, screenshot URL, raw HTML, and source URL were shortened. The field names were not changed.
{
"description": "OK",
"status": 200,
"data": {
"exists": true,
"url": "https://www.google.com/search?q=what+is+bitcoin&hl=en&gl=us&num=10",
"ai_overview": "[answer text omitted]",
"sources": [
{
"url": "https://example.com/source",
"title": "Example source",
"site": "example.com",
"position": 1
}
],
"screen_url": "[screenshot URL omitted]",
"html": "[raw HTML omitted]"
}
}
The outer fields tell you whether the API completed its work. The fields inside data describe the captured search result. Keep those jobs separate in your code.
How should I read the envelope fields?
| Field | Observed type | What it means | Required check |
|---|---|---|---|
description | String | A readable API result message | Use it in an error message, not as your only success test |
status | Number | The API-level status inside the JSON | Confirm that it equals 200 |
data | Object | The captured Google result | Confirm that it is an object before reading child fields |
HTTP status and JSON status are not the same value, even when both are 200. Your HTTP client checks the first one. Your parser checks the second one.
Google AI Overviews API data fields
The table describes fields seen in the August 5 test. A field can be missing or empty in another result, so the type column says "when present" where that distinction matters.
| Field | Observed type | Use in your application |
|---|---|---|
data.exists | Boolean | Provider signal that result data exists. Do not use it alone as proof that citations exist. |
data.url | String | The Google search URL built from the request inputs |
data.ai_overview | String when present | The captured AI Overview answer |
data.sources | Array when present | The source records connected with the answer |
data.screen_url | String when present | A screenshot location for visual debugging |
data.html | String when present | The captured page HTML, useful for debugging but often too large for a main result table |
Application logic should normally use ai_overview and sources. Treat screen_url and html as debugging artifacts unless your product has a clear reason to retain them.
What is inside each source?
Each observed source was an object with a page URL, title, domain, and position.
| Field | Observed type | Safe fallback |
|---|---|---|
url | String | Skip the source when the URL is missing or is not a string |
title | String | Store null when no title is available |
site | String | Store null, or derive a hostname only after validating the URL |
position | Number | Store null when it is missing or is not an integer |
Keep the complete source URL. A domain is useful for grouping citations, but it cannot tell you which exact page Google connected with the answer.
Do exists, the answer, and sources mean the same thing?
No. These fields describe different parts of the result. The August test included a response with exists=true and answer text but no source records. That is why one Boolean cannot represent every useful state.
| State | Answer | Sources | Recommended action |
|---|---|---|---|
no_overview | Missing or empty | Missing or empty | Record a completed check with no overview |
answer_without_sources | Present | Missing or empty | Store the answer and an empty source list |
answer_with_sources | Present | One or more valid records | Store the answer and normalized sources |
The exact no-overview JSON was not retained in the August test set. The table therefore defines an application state, not a promised provider payload. Detect it from a missing or empty answer instead of inventing a required combination of exists, null, and empty arrays.
A small Python response parser
This function accepts parsed JSON and returns one predictable object. It rejects a bad envelope, removes malformed source records, and assigns one of the three states above. It does not make the HTTP request.
def parse_ai_overview_response(payload):
if not isinstance(payload, dict):
raise ValueError("The API response is not a JSON object.")
if payload.get("status") != 200:
message = payload.get("description") or "The API returned an error."
raise ValueError(message)
data = payload.get("data")
if not isinstance(data, dict):
raise ValueError("The response does not contain a data object.")
answer_value = data.get("ai_overview")
answer = answer_value.strip() if isinstance(answer_value, str) else None
if not answer:
answer = None
raw_sources = data.get("sources")
if not isinstance(raw_sources, list):
raw_sources = []
sources = []
for source in raw_sources:
if not isinstance(source, dict) or not isinstance(source.get("url"), str):
continue
position = source.get("position")
if type(position) is not int:
position = None
sources.append(
{
"url": source["url"],
"title": source.get("title") if isinstance(source.get("title"), str) else None,
"site": source.get("site") if isinstance(source.get("site"), str) else None,
"position": position,
}
)
state = "no_overview"
if answer and not sources:
state = "answer_without_sources"
elif answer and sources:
state = "answer_with_sources"
return {
"state": state,
"answer": answer,
"sources": sources,
"exists": data.get("exists") is True,
"search_url": data.get("url") if isinstance(data.get("url"), str) else None,
"screen_url": data.get("screen_url")
if isinstance(data.get("screen_url"), str)
else None,
}
The function uses only Python's built-in data types, so you do not need another package. Keep the HTTP request on your server because browser code would expose the RapidAPI key.
Test the response fields on RapidAPI
Which errors should the client handle?
| Failure | What your code receives | What to do |
|---|---|---|
| Network failure or timeout | No usable HTTP response | Retry a small number of times with a delay |
| HTTP 400 | A client error response | Fix the request instead of repeating it unchanged |
| HTTP 500, 502, 503, or 504 | A temporary server error may have occurred | Retry with a delay and a fixed attempt limit |
| HTTP 200 with bad JSON contract | Missing data or unexpected field types | Stop parsing, log a redacted sample, and alert on the contract change |
| HTTP 200 with no overview | No usable answer | Store no_overview as a normal result |
A request without query returned HTTP 400 with The Query field is required. during the August 5 test. Repeating that request would waste another call. The same test session also saw temporary HTTP 500 responses, so a production client needs a timeout and limited retries.
What should I store?
Store the normalized result together with the request inputs and collection time. At minimum, keep the query, country, language, result state, answer, sources, and an observation timestamp in UTC.
Do not overwrite an older result. AI Overview answers and cited pages can change between requests. A history table lets you distinguish a parser bug from a real change in Google's result.
For the complete request example, read how to extract Google AI Overview answers and citations as JSON. To turn sources into a practical check, continue with the website citation checker guide.
Frequently asked questions
Is data.exists enough to detect an AI Overview?
No. Inspect the answer and source fields separately. One observed response had exists=true and answer text but no sources.
Must sources always be an array?
Your code should not assume that. Use an empty array when the field is missing or has another type, then record the state based on the usable answer and source records.
Should I store html?
Usually only for short-lived debugging or auditing. The normalized answer and source records are easier to query and use less storage.
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.
The response fields, source shape, HTTP 400 message, and temporary HTTP 500 behavior in this guide are observations from a live test performed on August 5, 2026. They are not guarantees about every future response.