Google AI Mode sources
The pages Google AI Mode cites behind its conversational answer.
`sources` lists the cited pages in order, and `citationPills` records every page behind each `[Label +N]` chip, so you can tell a chip's named source from the ones it only counts.
Returned in result
| Field |
|---|
sources |
citationPills |
Request
curl -X POST "https://api.answerline.dev/v1/monitor/aimode" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"Family-friendly hotels in Lisbon","country":"PT","hl":"en"}'
What AI Mode’s sources are
An AI Mode source is a page Google’s AI Mode cites in its conversational answer. Google shows citations as chips labeled with a source title and a +N count when the chip bundles several pages, alongside a rail of sources. This API returns the ordered list as sources and every page behind every chip as citationPills.
AI Mode sits inside Google Search, so its citations are the conversational counterpart of organic rankings, and usually what “are we visible in AI search on Google” is asking about. Position inside a chip matters: a [Label +N] chip names one source and only counts the rest. Because AI Mode takes location and hl, citation share can be measured per city and language, which the assistant apps do not offer.
Field reference
result.sources[]
| Field | Type | Meaning |
|---|---|---|
position |
number | Position index of the source in the response. |
url |
string | URL of the source. When Google served a redirect, this is the resolved destination. |
label |
string | Display label for the source. |
description |
string | Description of the source content. |
redirectLink |
string | Google’s /goto redirect for this link, in the absolute form POST /v1/monitor/google/goto accepts. Present only when Google served the link as a redirect. |
result.citationPills[]
| Field | Type | Meaning |
|---|---|---|
label |
string, required | Per-source title from the sources rail. Empty string when the rail has no title; read domain or url then. |
citationPillId |
integer, required | 1-based ordinal shared by all entries from the same chip. |
url |
string, required | Link straight to the cited source. |
domain |
string, required | Host extracted from url. |
description |
string | Source description from the rail. Omitted when the source carries no snippet. |
position |
integer, required | 1-based position of this source in result.sources. |
redirectLink |
string | Google’s /goto redirect, present only when Google served the link as a redirect. |
A [Label +N] chip citing N sources produces N entries with the same citationPillId. The array is omitted from result when the answer carries no pills.
Annotated excerpt
Values are illustrative; field names and types follow the POST /v1/monitor/aimode result schema.
{
"success": true,
"result": {
"text": "Heat pumps work in cold climates if you choose a model rated for...",
"sources": [
{
"position": 1,
"url": "https://www.example-energy.org/guides/cold-climate-heat-pumps",
"label": "Cold-climate heat pumps explained",
"description": "Performance below freezing, sizing and backup heat..."
},
{
"position": 2,
"url": "https://www.example-hvac.com/blog/heat-pump-cost",
"label": "What a heat pump install costs in 2026",
"description": "Equipment, labor and rebates...",
// Google linked through /goto; url above is the resolved destination.
"redirectLink": "https://www.google.com/goto?url=example"
}
],
// One chip citing two sources = two entries sharing citationPillId 1.
"citationPills": [
{
"label": "Cold-climate heat pumps explained",
"citationPillId": 1,
"url": "https://www.example-energy.org/guides/cold-climate-heat-pumps",
"domain": "example-energy.org",
"position": 1
},
{
"label": "What a heat pump install costs in 2026",
"citationPillId": 1,
"url": "https://www.example-hvac.com/blog/heat-pump-cost",
"domain": "example-hvac.com",
"position": 2,
"redirectLink": "https://www.google.com/goto?url=example"
}
]
}
}
Cost and request options
No include flag is needed. An AI Mode request costs $0.00206 on every tier. The endpoint has no add-ons. include.googleGoto is deprecated and ignored; redirect links arrive as redirectLink without it.
Targeting fields that matter for citation studies:
| Field | Use |
|---|---|
country or gl |
Result geography, ISO 3166-1 alpha-2. Send one; both with different values is a 400. |
hl |
Interface language, such as en or pt-BR. Overrides the language derived from the country. |
location or uule |
City-level targeting with a Google canonical City,Region,Country name, or a pre-encoded UULE. Mutually exclusive. |
You rarely need to resolve redirectLink yourself, since url already holds the destination. POST /v1/monitor/google/goto resolves one on demand for free.
Example: citation share and chip lead share by city
The script runs one prompt set across three cities, several samples each, and reports per city the fraction of answers citing a domain and the fraction of chips it leads.
import os
import time
from collections import Counter, defaultdict
from datetime import date
from urllib.parse import urlparse
import requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
PROMPTS = ["are heat pumps worth it in a cold climate", "heat pump installation cost"]
CITIES = ["Denver,Colorado,United States", "Minneapolis,Minnesota,United States", "Boston,Massachusetts,United States"]
SAMPLES = 3
DAY = date.today().isoformat()
def run_tasks(tasks):
resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=60)
resp.raise_for_status()
body = resp.json()
pending = {item["task"]["id"]: tasks[item["index"]] for item in body["results"] if item["success"]}
results = []
while pending:
time.sleep(10)
for task_id in list(pending):
reply = requests.get(f"{API}/v1/async/task/{task_id}", headers=HEADERS, timeout=30).json()
status = reply["task"]["status"]
if status in ("COMPLETED", "FAILED"):
task = pending.pop(task_id)
if status == "COMPLETED":
results.append((task["payload"]["location"], reply["response"]["result"]))
return results
def host(url):
return (urlparse(url).hostname or "").removeprefix("www.")
tasks = [
{
"taskType": "AIMODE",
"payload": {"prompt": prompt, "country": "US", "hl": "en", "location": city},
"idempotencyKey": f"heatpump-{p}-{city.split(',')[0].lower()}-s{s}-{DAY}",
}
for p, prompt in enumerate(PROMPTS)
for city in CITIES
for s in range(SAMPLES)
]
answers = defaultdict(int)
cited = defaultdict(Counter)
leads = defaultdict(Counter)
chips = Counter()
for city, result in run_tasks(tasks):
answers[city] += 1
cited[city].update({host(src["url"]) for src in result.get("sources", []) if src.get("url")})
grouped = defaultdict(list)
for pill in result.get("citationPills", []):
grouped[pill["citationPillId"]].append(pill)
chips[city] += len(grouped)
for entries in grouped.values():
leads[city][host(min(entries, key=lambda e: e["position"])["url"])] += 1
for city in CITIES:
n, c = answers[city] or 1, chips[city] or 1
print(f"\n{city}: {answers[city]} answers, {chips[city]} chips")
for domain, hits in cited[city].most_common(8):
print(f" {domain:36} answers {hits / n:5.0%} lead {leads[city][domain] / c:5.0%}")
The script keeps the city by mapping each task ID back to its payload, so results stay attributable even though they finish in any order. Lead share uses the lowest position within a chip as an approximation of the source named on the chip; keep that definition fixed between periods.
Pitfalls
Key pages on url, the destination. redirectLink is Google’s wrapper and appears only on some links, so grouping by it splits one page into many keys.
A chip citing four pages is four entries. Count distinct citationPillId values when you mean visible chips, and default citationPills to an empty list, since it is omitted when there are no chips.
Citation share differs by location and hl, and between runs. Change one targeting field at a time, take several samples per combination, and copy location names from Google’s canonical list; see state-level and city AI answers.
The same keyword can produce different cited pages in AI Mode, the AI Overview and organic results. Store them as separate series and compare domain sets.
Related
- AI Mode engine guide: calls, webhooks, geo and language targeting, billing.
- AI Mode places and AI Mode shopping for the other modules in the same answer.
- Capture Google AI Mode answers with an API and how AI engines choose citations.
- Compare with Gemini sources and ChatGPT sources.
- AI visibility tracking and rank tracking.
Questions
Do I need an include flag to get AI Mode sources?
No. sources and citationPills are part of the AI Mode result at the base price: $2.06 per 1,000 on every tier. The endpoint has no add-ons.
What is redirectLink on AI Mode sources?
When Google served a link as a /goto redirect, url holds the destination this API resolved it to and redirectLink holds Google's redirect in the absolute form POST /v1/monitor/google/goto accepts. When Google linked directly, redirectLink is absent.
Do I still need include.googleGoto?
No. include.googleGoto is deprecated and ignored. Redirect links are returned as redirectLink beside their destination without it, and requests still sending the flag behave as if it were absent.
How do Google's [Label +N] chips map to citationPills?
A chip citing N sources becomes N citationPills entries that share one 1-based citationPillId, each with its own label, url and domain. Group by citationPillId to rebuild the chip.
Can I measure AI Mode citations by city?
Yes. The request accepts country or gl plus location, a Google canonical name such as Denver,Colorado,United States, or a pre-encoded uule instead of location. hl sets the interface language.