
Lucas Mitchell
Automation Engineer

Google's AI Overviews now appear for a growing percentage of search queries, citing specific web pages as sources. For brands and publishers, being cited in these AI-generated summaries drives significant traffic and authority. Monitoring which pages get cited — and when citations change — requires automated data collection from Google's search results. This guide shows how to build an AI Overview citation monitoring system using CapSolver to handle Google's verification challenges and maintain continuous tracking.
Google AI Overviews represent a fundamental shift in how search traffic flows. When Google generates an AI-powered answer and cites your page, you receive both a direct link and implied authority. When your citation disappears, traffic from that query drops immediately. Search Engine Land research indicates that AI Overviews now appear on 15-30% of informational queries, with the percentage growing monthly.
The challenge for monitoring is that AI Overview citations are dynamic — they change based on content freshness, query reformulation, and Google's ongoing model updates. A page cited today may lose its citation tomorrow without any notification. Manual checking is impractical at scale: a brand tracking 200 keywords would need to manually search each one, scroll to the AI Overview, and record which sources are cited — multiple times per week.
Automated monitoring solves this, but Google's bot protection blocks systematic search access. After 50-100 automated queries, Google presents a reCAPTCHA challenge or blocks the IP entirely. CapSolver provides the verification-clearing layer that keeps your monitoring pipeline running continuously.
Install required packages:
pip install git+https://github.com/capsolver-ai/capsolver-core.git
pip install aiohttp beautifulsoup4 pandas
Set your API key:
export CAPSOLVER_API_KEY="your-capsolver-api-key"
Additional requirements:
Not all queries generate AI Overviews. Focus your monitoring on keywords where AI Overviews consistently appear:
from dataclasses import dataclass, field
from typing import List, Optional
import time
@dataclass
class AIOverviewCitation:
"""A single citation within an AI Overview."""
position: int # 1-based position in the citation list
url: str # Cited page URL
domain: str # Domain of the cited page
anchor_text: str # Text used to link to the source
snippet_context: str # Surrounding text in the AI Overview
@dataclass
class AIOverviewResult:
"""Complete AI Overview monitoring result for one keyword."""
keyword: str
has_ai_overview: bool
citations: List[AIOverviewCitation] = field(default_factory=list)
overview_text: str = ""
timestamp: float = 0.0
your_domain_cited: bool = False
your_citation_position: Optional[int] = None
# Keywords most likely to trigger AI Overviews
PRIORITY_KEYWORDS = [
# Informational queries (highest AI Overview rate)
"what is generative engine optimization",
"how to optimize for AI search",
"best practices for AI citation",
# Commercial investigation queries
"best CAPTCHA solving API",
"top AI agent frameworks 2025",
# Comparison queries
"reCAPTCHA vs Cloudflare Turnstile",
]
Informational and "how to" queries have the highest AI Overview trigger rate (40-60%), followed by comparison queries (20-30%) and commercial investigation queries (15-25%).
Monitoring keywords that never trigger AI Overviews wastes CAPTCHA solving credits. Focus on queries where your content has citation potential — informational queries in your expertise area, comparison queries where your product is relevant, and "best of" queries in your category.
Create a parser that extracts AI Overview citations from Google search result pages:
from bs4 import BeautifulSoup
import re
class AIOverviewExtractor:
"""Extract AI Overview citations from Google SERP HTML."""
def extract(self, html: str, keyword: str, your_domain: str = "") -> AIOverviewResult:
"""Parse HTML and extract AI Overview citation data."""
soup = BeautifulSoup(html, 'html.parser')
# Detect AI Overview presence
# Google uses various container classes for AI Overviews
ai_containers = soup.select(
'[data-attrid*="ai"], '
'.ai-overview, '
'[class*="aiOverview"], '
'.kp-wholepage [data-md-type]'
)
if not ai_containers:
return AIOverviewResult(
keyword=keyword,
has_ai_overview=False,
timestamp=time.time()
)
# Extract the AI Overview text
overview_container = ai_containers[0]
overview_text = overview_container.get_text(separator=" ", strip=True)[:2000]
# Extract citations (source links within the AI Overview)
citations = []
source_links = overview_container.select('a[href^="http"]')
for i, link in enumerate(source_links, 1):
url = link.get('href', '')
if not url or 'google.com' in url:
continue
domain = self._extract_domain(url)
anchor = link.get_text(strip=True)
# Get surrounding context
parent = link.parent
context = parent.get_text(strip=True)[:200] if parent else ""
citations.append(AIOverviewCitation(
position=i,
url=url,
domain=domain,
anchor_text=anchor,
snippet_context=context
))
# Check if your domain is cited
your_cited = any(your_domain in c.domain for c in citations) if your_domain else False
your_position = next(
(c.position for c in citations if your_domain in c.domain), None
) if your_domain else None
return AIOverviewResult(
keyword=keyword,
has_ai_overview=True,
citations=citations,
overview_text=overview_text[:500],
timestamp=time.time(),
your_domain_cited=your_cited,
your_citation_position=your_position
)
def _extract_domain(self, url: str) -> str:
"""Extract domain from URL."""
match = re.search(r'https?://([^/]+)', url)
return match.group(1) if match else url
Build the data collection layer with integrated CAPTCHA solving:
import asyncio
import aiohttp
import random
from capsolver_core import create_capsolver, CaptchaType, CaptchaInfo
class CitationMonitorCollector:
"""Collect AI Overview data with CAPTCHA handling."""
def __init__(self, api_key: str, proxies: list):
self.cap = create_capsolver(api_key=api_key)
self.proxies = proxies
self.proxy_idx = 0
self.extractor = AIOverviewExtractor()
self.stats = {"searches": 0, "captchas": 0, "overviews_found": 0}
async def collect_citation_data(
self, keyword: str, your_domain: str = "", location: str = "us"
) -> AIOverviewResult:
"""Collect AI Overview citation data for a keyword."""
proxy = self.proxies[self.proxy_idx % len(self.proxies)]
self.proxy_idx += 1
url = f"https://www.google.com/search?q={keyword}&gl={location}&hl=en"
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml",
"Accept-Language": "en-US,en;q=0.9"
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, proxy=proxy, timeout=30) as resp:
html = await resp.text()
# Handle CAPTCHA if triggered
if "unusual traffic" in html.lower() or "g-recaptcha" in html:
self.stats["captchas"] += 1
html = await self._solve_and_retry(session, url, headers, proxy)
self.stats["searches"] += 1
# Extract citation data
result = self.extractor.extract(html, keyword, your_domain)
if result.has_ai_overview:
self.stats["overviews_found"] += 1
return result
async def _solve_and_retry(self, session, url, headers, proxy) -> str:
"""Solve Google's reCAPTCHA and retry the search."""
info = CaptchaInfo(
type=CaptchaType.RECAPTCHA_V2,
website_url="https://www.google.com",
website_key="6LfwuyUTAAAAAOAmoS0fdqijC2PbbdH4kjq62Y1b"
)
solution = await self.cap.solve(info)
# Retry with a fresh proxy after solving
new_proxy = self.proxies[self.proxy_idx % len(self.proxies)]
self.proxy_idx += 1
async with session.get(url, headers=headers, proxy=new_proxy, timeout=30) as resp:
return await resp.text()
async def monitor_batch(
self, keywords: list, your_domain: str = "", delay: float = 7.0
) -> list:
"""Monitor a batch of keywords with rate limiting."""
results = []
for keyword in keywords:
result = await self.collect_citation_data(keyword, your_domain)
results.append(result)
await asyncio.sleep(delay + random.uniform(0, 3))
return results
async def close(self):
await self.cap.aclose()
The CapSolver reCAPTCHA documentation covers Google's specific reCAPTCHA implementation in detail.
Track citation changes over time and alert when your pages gain or lose AI Overview citations:
class CitationChangeDetector:
"""Detect changes in AI Overview citations over time."""
def __init__(self, your_domain: str):
self.your_domain = your_domain
self.history = {} # keyword -> list of AIOverviewResult
def record_and_detect(self, results: list) -> list:
"""Record new results and detect changes from previous check."""
changes = []
for result in results:
keyword = result.keyword
previous = self.history.get(keyword, [])
if previous:
last = previous[-1]
# Citation gained
if result.your_domain_cited and not last.your_domain_cited:
changes.append({
"type": "CITATION_GAINED",
"keyword": keyword,
"position": result.your_citation_position,
"timestamp": result.timestamp
})
# Citation lost
elif last.your_domain_cited and not result.your_domain_cited:
changes.append({
"type": "CITATION_LOST",
"keyword": keyword,
"previous_position": last.your_citation_position,
"timestamp": result.timestamp
})
# Position changed
elif (result.your_domain_cited and last.your_domain_cited and
result.your_citation_position != last.your_citation_position):
changes.append({
"type": "POSITION_CHANGED",
"keyword": keyword,
"old_position": last.your_citation_position,
"new_position": result.your_citation_position,
"timestamp": result.timestamp
})
# AI Overview appeared/disappeared
if result.has_ai_overview and not last.has_ai_overview:
changes.append({
"type": "AI_OVERVIEW_APPEARED",
"keyword": keyword,
"timestamp": result.timestamp
})
# Update history
if keyword not in self.history:
self.history[keyword] = []
self.history[keyword].append(result)
# Keep last 30 days of history
self.history[keyword] = self.history[keyword][-60:]
return changes
def generate_report(self) -> dict:
"""Generate a summary report of citation status."""
total_keywords = len(self.history)
cited_keywords = sum(
1 for k, h in self.history.items()
if h and h[-1].your_domain_cited
)
overview_keywords = sum(
1 for k, h in self.history.items()
if h and h[-1].has_ai_overview
)
return {
"total_keywords_monitored": total_keywords,
"keywords_with_ai_overview": overview_keywords,
"keywords_where_cited": cited_keywords,
"citation_rate": f"{cited_keywords/max(overview_keywords,1)*100:.1f}%",
"average_citation_position": self._avg_position()
}
def _avg_position(self) -> float:
positions = [
h[-1].your_citation_position
for h in self.history.values()
if h and h[-1].your_citation_position
]
return sum(positions) / len(positions) if positions else 0
Run the complete pipeline on a schedule:
async def run_daily_monitoring():
"""Daily AI Overview citation monitoring run."""
collector = CitationMonitorCollector(
api_key="YOUR_CAPSOLVER_API_KEY",
proxies=RESIDENTIAL_PROXY_LIST
)
detector = CitationChangeDetector(your_domain="capsolver.com")
# Monitor all priority keywords
results = await collector.monitor_batch(
keywords=PRIORITY_KEYWORDS,
your_domain="capsolver.com",
delay=8.0
)
# Detect changes
changes = detector.record_and_detect(results)
# Report
if changes:
print(f"\n{'='*50}")
print(f"CITATION CHANGES DETECTED: {len(changes)}")
for change in changes:
print(f" [{change['type']}] {change['keyword']}")
print(f"{'='*50}\n")
report = detector.generate_report()
print(f"Summary: {report}")
await collector.close()
# Run daily
asyncio.run(run_daily_monitoring())
Claim Your Bonus Code: Use code WEBS at CapSolver Dashboard to get an extra 5% bonus on every recharge. Essential for GEO teams tracking AI Overview citations at scale.
The monitoring data directly informs your Generative Engine Optimization strategy:
The CapSolver blog on AI and automation covers additional patterns for AI-powered data collection. For handling different CAPTCHA types across search engines, the CapSolver products page lists all supported verification systems.
Automating AI Overview citation monitoring requires a CAPTCHA-aware search collection layer, a citation extraction parser, and a change detection system. CapSolver provides the verification-clearing infrastructure that enables continuous monitoring of Google's AI Overviews, solving reCAPTCHA challenges in 3-8 seconds so your GEO strategy always has fresh citation data.
Start with 20-50 high-priority keywords where you expect AI Overviews, validate your extraction accuracy, then scale to full keyword coverage. The citation change data directly informs content optimization decisions — helping you understand what Google's AI considers citation-worthy for your target queries.
For high-priority keywords (brand terms, core product queries), check daily. For broader monitoring (industry terms, informational queries), 2-3 times per week is sufficient. AI Overview citations can change within hours of content updates, so more frequent checking catches changes faster.
Currently 15-30% of informational queries show AI Overviews, with the percentage growing. "How to" queries, definition queries, and comparison queries have the highest trigger rates. Commercial and transactional queries show AI Overviews less frequently.
Most AI Overviews cite 3-8 sources, with the first 2-3 positions receiving the majority of click-through traffic. Position 1 in the citation list receives approximately 3-5x more clicks than position 5+. Monitoring your citation position matters as much as monitoring whether you are cited at all.
Yes. Set your_domain to a competitor's domain to track their citation frequency and positions. Compare your citation rate against competitors to identify content gaps and opportunities. Track which competitors consistently appear for keywords where you are absent.
At 200 keywords with 8-second delays and approximately 10% CAPTCHA encounter rate, you need about 20 CAPTCHA solves per daily run. At $2-3 per 1,000 reCAPTCHA v2 solves, the daily cost is approximately $0.04-0.06 — under $2 per month for comprehensive AI Overview citation tracking.
Learn scalable Rust web scraping architecture with reqwest, scraper, async scraping, headless browser scraping, proxy rotation, and compliant CAPTCHA handling.

Learn the best techniques to scrape job listings without getting blocked. Master Indeed scraping, Google Jobs API, and web scraping API with CapSolver.
