Generative Engine Optimization performance cannot be measured by traditional rank tracking alone. In 2026, you need to track three surfaces: AI Overview citations, Knowledge Graph entity presence, and featured snippet capture. This tutorial builds a GEO performance dashboard that checks all three surfaces for a list of target queries, calculates a composite GEO score, and tracks changes over time. Each query check costs one Scavio credit at $0.005.
Prerequisites
- Python 3.9+ installed
- requests library installed
- A Scavio API key from scavio.dev
- A list of target queries to track
Walkthrough
Step 1: Define the GEO performance metrics
Set up the three surfaces to check for each query: AI Overview citation, Knowledge Graph presence, and featured snippet capture.
import os, requests, json, time
from datetime import datetime
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
URL = 'https://api.scavio.dev/api/v1/search'
TARGET_DOMAIN = 'scavio.dev'
QUERIES = [
'search api for ai agents',
'web search mcp server',
'serp api pricing comparison',
'tiktok data api',
'google search api alternative',
]Step 2: Check all three GEO surfaces per query
For each query, check AI Overview citation, Knowledge Graph mention, and featured snippet ownership. Return a structured result.
def measure_geo(query: str, domain: str) -> dict:
resp = requests.post(URL, headers=H,
json={'query': query, 'country_code': 'us', 'include_ai_overview': True})
data = resp.json()
# AI Overview
ai = data.get('ai_overview', {})
ai_sources = ai.get('sources', [])
ai_cited = any(domain in s.get('link', '') for s in ai_sources)
# Knowledge Graph
kg = data.get('knowledge_graph', {})
kg_present = domain in json.dumps(kg) if kg else False
# Featured Snippet
snippet = data.get('featured_snippet', {})
snippet_owned = domain in snippet.get('link', '') if snippet else False
# Organic position
organic = data.get('organic_results', [])
org_pos = next((r['position'] for r in organic if domain in r.get('link', '')), None)
# GEO score: 0-100
score = 0
if ai_cited: score += 40
if kg_present: score += 25
if snippet_owned: score += 25
if org_pos and org_pos <= 3: score += 10
return {
'query': query, 'ai_cited': ai_cited, 'kg_present': kg_present,
'snippet_owned': snippet_owned, 'organic_position': org_pos,
'geo_score': score,
}Step 3: Run the full GEO performance report
Check all queries and compute aggregate GEO metrics. Save the report for historical comparison.
def geo_report(queries: list, domain: str) -> dict:
results = []
for q in queries:
r = measure_geo(q, domain)
results.append(r)
print(f'[{r["geo_score"]:3d}] {q} | AI:{r["ai_cited"]} KG:{r["kg_present"]} Snip:{r["snippet_owned"]} Org:#{r["organic_position"]}')
time.sleep(0.5)
avg_score = sum(r['geo_score'] for r in results) / len(results)
ai_rate = sum(1 for r in results if r['ai_cited']) / len(results)
kg_rate = sum(1 for r in results if r['kg_present']) / len(results)
snip_rate = sum(1 for r in results if r['snippet_owned']) / len(results)
report = {
'date': datetime.now().strftime('%Y-%m-%d'),
'domain': domain,
'queries_checked': len(results),
'avg_geo_score': round(avg_score, 1),
'ai_citation_rate': round(ai_rate * 100, 1),
'kg_presence_rate': round(kg_rate * 100, 1),
'snippet_capture_rate': round(snip_rate * 100, 1),
'results': results,
}
print(f'\nGEO Performance Summary')
print(f' Avg GEO Score: {avg_score:.1f}/100')
print(f' AI Citation Rate: {ai_rate:.0%}')
print(f' Knowledge Graph Rate: {kg_rate:.0%}')
print(f' Featured Snippet Rate: {snip_rate:.0%}')
return report
geo_report(QUERIES, TARGET_DOMAIN)Python Example
import os, requests, time
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
def measure_geo(query, domain):
resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'query': query, 'country_code': 'us', 'include_ai_overview': True})
data = resp.json()
ai_cited = any(domain in s.get('link', '') for s in data.get('ai_overview', {}).get('sources', []))
snippet = data.get('featured_snippet', {})
snip_owned = domain in snippet.get('link', '') if snippet else False
score = (40 if ai_cited else 0) + (25 if snip_owned else 0)
print(f'[{score:3d}] {query} | AI:{ai_cited} Snip:{snip_owned}')
for q in ['search api for agents', 'serp api comparison']:
measure_geo(q, 'scavio.dev')
time.sleep(0.5)JavaScript Example
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function measureGeo(query, domain) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us', include_ai_overview: true })
});
const data = await resp.json();
const aiCited = (data.ai_overview?.sources || []).some(s => (s.link || '').includes(domain));
const snipOwned = (data.featured_snippet?.link || '').includes(domain);
const score = (aiCited ? 40 : 0) + (snipOwned ? 25 : 0);
console.log(`[${score}] ${query} | AI:${aiCited} Snip:${snipOwned}`);
}
(async () => {
for (const q of ['search api for agents', 'serp api comparison']) {
await measureGeo(q, 'scavio.dev');
}
})();Expected Output
[ 40] search api for ai agents | AI:True KG:False Snip:False Org:#4
[ 75] web search mcp server | AI:True KG:True Snip:True Org:#1
[ 0] serp api pricing comparison | AI:False KG:False Snip:False Org:#8
[ 40] tiktok data api | AI:True KG:False Snip:False Org:#5
[ 10] google search api alternative | AI:False KG:False Snip:False Org:#3
GEO Performance Summary
Avg GEO Score: 33.0/100
AI Citation Rate: 60%
Knowledge Graph Rate: 20%
Featured Snippet Rate: 20%