Google AI Overviews now appear on 40%+ of informational queries and cite specific brands. If competitors get cited and you do not, you lose traffic you cannot see in traditional SEO tools. This tracker checks your target keywords daily, logs citation status, and alerts when competitors gain or lose citations.
Prerequisites
- Python 3.8+
- requests library
- A Scavio API key from scavio.dev
- Target keywords and domain to monitor
Walkthrough
Step 1: Scan keywords for AI Overview citations
Check each keyword for AI Overview presence and brand citation status.
import os, requests, json
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
DOMAIN = 'yourbrand.com'
COMPETITORS = ['competitor1.com', 'competitor2.com']
KEYWORDS = [
'best project management tool',
'project management software comparison',
'agile vs waterfall tools',
'remote team project management',
'project management for startups',
]
def scan_citations(keyword):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
aio = data.get('ai_overview', data.get('answer_box', {}))
aio_text = json.dumps(aio).lower() if aio else ''
result = {
'keyword': keyword,
'has_aio': bool(aio),
'brand_cited': DOMAIN.lower() in aio_text,
'competitors_cited': {c: c.lower() in aio_text for c in COMPETITORS}
}
return result
results = []
for kw in KEYWORDS:
r = scan_citations(kw)
results.append(r)
brand = 'CITED' if r['brand_cited'] else 'absent'
comps = sum(1 for v in r['competitors_cited'].values() if v)
print(f' [{brand:6}] {kw:45} | competitors: {comps}/{len(COMPETITORS)}')
print(f'\nCost: ${len(KEYWORDS) * 0.005:.3f}')Step 2: Calculate citation metrics and gaps
Compute your citation share vs competitors and identify gaps.
def citation_report(results):
total = len(results)
with_aio = sum(1 for r in results if r['has_aio'])
brand_cited = sum(1 for r in results if r['brand_cited'])
print(f'\n=== AI Citation Report - {DOMAIN} ===')
print(f' Keywords: {total}')
print(f' AI Overviews present: {with_aio} ({with_aio/total*100:.0f}%)')
print(f' Your brand cited: {brand_cited} ({brand_cited/with_aio*100:.0f}% of AIO)' if with_aio else ' No AI Overviews found')
# Competitor comparison
print(f'\n Citation Share:')
comp_counts = {c: sum(1 for r in results if r['competitors_cited'].get(c)) for c in COMPETITORS}
all_brands = {DOMAIN: brand_cited, **comp_counts}
for brand, count in sorted(all_brands.items(), key=lambda x: x[1], reverse=True):
bar = '#' * count
print(f' {brand:25} | {count:2} citations | {bar}')
# Gaps: keywords where competitors are cited but you are not
gaps = [r for r in results if r['has_aio'] and not r['brand_cited'] and any(r['competitors_cited'].values())]
if gaps:
print(f'\n Citation Gaps ({len(gaps)} keywords where competitors beat you):')
for g in gaps:
cited_comps = [c for c, v in g['competitors_cited'].items() if v]
print(f' "{g["keyword"]}" -> cited: {", ".join(cited_comps)}')
citation_report(results)Step 3: Store history and detect changes
Log daily results and alert when citation status changes.
def track_changes(results, history_file='citation_history.json'):
try:
with open(history_file) as f:
history = json.load(f)
except FileNotFoundError:
history = []
today = {
'date': datetime.now().strftime('%Y-%m-%d'),
'total': len(results),
'aio_count': sum(1 for r in results if r['has_aio']),
'cited': sum(1 for r in results if r['brand_cited']),
'keywords': {r['keyword']: r['brand_cited'] for r in results}
}
changes = []
if history:
prev = history[-1]
prev_kws = prev.get('keywords', {})
for kw, cited in today['keywords'].items():
if kw in prev_kws and prev_kws[kw] != cited:
change = 'GAINED' if cited else 'LOST'
changes.append(f'{change}: "{kw}"')
history.append(today)
with open(history_file, 'w') as f:
json.dump(history, f, indent=2)
print(f'\n=== Citation Changes ===')
if changes:
for c in changes:
print(f' {c}')
else:
print(f' No changes since last scan.')
print(f' History: {len(history)} scans saved')
track_changes(results)Python Example
import os, requests, json
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def check_cited(keyword, domain):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
aio = data.get('ai_overview', {})
cited = domain.lower() in json.dumps(aio).lower() if aio else False
print(f'{"CITED" if cited else "absent":6} | {keyword}')
for kw in ['best search api', 'serp api comparison']:
check_cited(kw, 'scavio.dev')
print('Cost: $0.010')JavaScript Example
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function checkCited(keyword, domain) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: keyword, country_code: 'us' })
}).then(r => r.json());
const aio = data.ai_overview || {};
const cited = JSON.stringify(aio).toLowerCase().includes(domain);
console.log(`${cited ? 'CITED' : 'absent'} | ${keyword}`);
}
await checkCited('best search api', 'scavio.dev');Expected Output
[CITED ] best project management tool | competitors: 1/2
[absent] project management software comparison | competitors: 2/2
[CITED ] agile vs waterfall tools | competitors: 0/2
[absent] remote team project management | competitors: 1/2
[absent] project management for startups | competitors: 0/2
Cost: $0.025
=== AI Citation Report - yourbrand.com ===
Keywords: 5
AI Overviews present: 4 (80%)
Your brand cited: 2 (50% of AIO)
Citation Gaps (1 keywords where competitors beat you):
"project management software comparison" -> cited: competitor1.com, competitor2.com