The shortest useful path from a search question to a citation dataset is one request to GET /ai-overview. The response can contain the AI Overview text, an ordered list of source pages, the Google search URL, a screenshot URL, and the captured HTML.

Use the structured answer and sources array for application logic. Keep the screenshot and raw HTML for short-lived debugging, not as the primary database contract. Our test on August 5, 2026 also found response times from 5.7 to 28.9 seconds and two temporary HTTP 500 responses. A production client needs a real timeout and a bounded retry policy.

What does the Google AI Overviews API return?

The Google AI Overviews API returns a JSON envelope with an internal status and a data object. In the successful test, data.ai_overview held the visible answer as one string. data.sources held ordered source records with url, title, site, and position.

The result is an observation, not a permanent fact. Google decides when an AI Overview appears, and its answer or cited pages can change between requests. Country and language settings also matter. Store the inputs beside the output.

See the Google AI Overviews API product page for the current request plans and the rest of the integration guides.

Inspect an AI Overview response on RapidAPI

A verified request for answer text and citations

We called the public RapidAPI endpoint from a Windows development workspace on August 5, 2026. The test query was what is bitcoin with gl=us and hl=en. The API key stayed in the request header and is omitted below.

curl --request GET \
  --url "https://google-ai-overviews.p.rapidapi.com/ai-overview?query=what%20is%20bitcoin&gl=us&hl=en" \
  --header "x-rapidapi-host: google-ai-overviews.p.rapidapi.com" \
  --header "x-rapidapi-key: $RAPIDAPI_KEY"
Observed value Test result
HTTP status 200
Envelope status 200
Measured response time 17.6 seconds
data.exists true
Answer Non-empty ai_overview string
Sources 9 ordered records

This is a dated field test, not an uptime or latency benchmark. Two other queries returned temporary HTTP 500 responses after about 20 to 22 seconds. Retrying later produced a valid response for one of those topics.

An anonymized response excerpt

{
  "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": "[AI Overview text omitted from this excerpt]",
    "sources": [
      {
        "url": "https://finance.yahoo.com/...",
        "title": "Yahoo Finance",
        "site": "finance.yahoo.com",
        "position": 1
      }
    ],
    "screen_url": "[VERIFICATION SCREENSHOT URL]",
    "html": "[RAW GOOGLE RESULT HTML]"
  }
}

The excerpt keeps the field names and one observed source shape while removing the full generated answer, screenshot location, and raw page. Those large fields are unnecessary for defining the application contract.

Google AI Overviews API JSON fields

The table below separates the API envelope from the captured search data. Treat the names as the contract observed on August 5, 2026 and validate them before every release that changes your parser.

Field Observed type How to use it
description String Human-readable envelope result
status Number API-level status inside the HTTP response
data.exists Boolean Provider signal that result data exists
data.url String Google search URL built from the inputs
data.ai_overview String Captured AI Overview answer text
data.sources Array Ordered citation records
source.url String Cited page URL
source.title String Displayed source title
source.site String Source domain
source.position Number Order in the returned source list
data.screen_url String Visual verification artifact
data.html String Raw captured result for debugging

A short query in our test returned exists=true with an answer string but no sources. That matters: a non-empty answer, an overview with citations, and a response without an overview should remain separate states in your model. Do not reduce all three to one Boolean.

A server-side JavaScript implementation

The request belongs on the server because a browser call would expose the RapidAPI key. The function below also checks the HTTP status, the internal envelope status, and the shape of every source before returning a normalized snapshot.

export async function fetchAiOverview({ query, gl = "us", hl = "en" }) {
  const endpoint = new URL(
    "https://google-ai-overviews.p.rapidapi.com/ai-overview"
  );
  endpoint.search = new URLSearchParams({ query, gl, hl });

  const response = await fetch(endpoint, {
    headers: {
      "x-rapidapi-host": "google-ai-overviews.p.rapidapi.com",
      "x-rapidapi-key": process.env.RAPIDAPI_KEY
    },
    signal: AbortSignal.timeout(45_000)
  });

  if (!response.ok) {
    throw new Error(`AI Overview HTTP ${response.status}`);
  }

  const payload = await response.json();
  if (payload.status !== 200 || !payload.data) {
    throw new Error(payload.description || "Unexpected API response");
  }

  const data = payload.data;
  const sources = Array.isArray(data.sources)
    ? data.sources
        .filter((source) => source && typeof source.url === "string")
        .map((source) => ({
          url: source.url,
          title: source.title ?? null,
          site: source.site ?? new URL(source.url).hostname,
          position: Number.isInteger(source.position)
            ? source.position
            : null
        }))
    : [];

  return {
    observedAt: new Date().toISOString(),
    query,
    gl,
    hl,
    exists: data.exists === true,
    answer: typeof data.ai_overview === "string"
      ? data.ai_overview
      : null,
    sources,
    searchUrl: data.url ?? null,
    screenUrl: data.screen_url ?? null
  };
}

Use a retry only for failures that may be temporary, such as HTTP 500, 502, 503, 504, or a network timeout. Cap the attempts and add jitter. A 400 validation error is different. Our request without query returned HTTP 400 with The Query field is required., so repeating it unchanged would only waste another request.

Run the verified endpoint on RapidAPI

Store observations, not one mutable answer

An update-in-place table loses the evidence needed for citation tracking. Use an observation row for each query, market, language, and collection time. Store sources as child records or a JSON array, depending on the analysis you plan to run.

CREATE TABLE ai_overview_observation (
  id            BIGINT PRIMARY KEY,
  query_text    TEXT NOT NULL,
  country_code  CHAR(2) NOT NULL,
  language_code VARCHAR(10) NOT NULL,
  observed_at   TIMESTAMP NOT NULL,
  exists_flag   BOOLEAN NOT NULL,
  answer_text   TEXT NULL,
  search_url    TEXT NULL,
  screen_url    TEXT NULL
);

CREATE TABLE ai_overview_source (
  observation_id BIGINT NOT NULL,
  source_position INTEGER NULL,
  source_site      TEXT NULL,
  source_title     TEXT NULL,
  source_url       TEXT NOT NULL
);

This shape supports questions that one current row cannot answer: when a domain first appeared, whether its position changed, whether a query stopped producing cited sources, and whether the answer changed between markets.

If your immediate job is checking one site, continue with the domain citation checker. For operational trade-offs, compare the managed endpoint with a self-maintained browser scraper.

Questions to settle before production

Does every search return an AI Overview?

No. Google states that AI Overviews appear when its systems determine they add value to classic search. Your code should accept a valid request that does not yield the citation data you expected.

Are gl and hl optional?

The RapidAPI listing presents query, gl, and hl as the request inputs. In our test, omitting hl did not fail; the resulting Google URL used hl=en. That is observed fallback behavior, not a reason to omit the field. Send all three values explicitly so a future default cannot change your dataset.

Should the application store raw HTML?

Usually not in the main observation table. The raw HTML was much larger than the normalized answer and sources. Keep it only when you have a debugging or audit requirement, set a retention period, and prevent it from becoming the interface used by downstream jobs.

What should a contract test assert?

Assert the envelope, the presence and type of data, the answer type, and the fields in each source record. Include fixtures for HTTP 400, temporary 500, an empty source list, and a normal response with citations. Do not assert a specific answer sentence or fixed source domain because the search result can change.

Sources checked August 5, 2026

The endpoint request, response fields, error behavior, and timing values above come from our own tests on August 5, 2026. Product availability and plan limits can change.

Start with one query and inspect the JSON