Les performances d'optimisation des moteurs génératifs ne peuvent pas être mesurées uniquement par le suivi traditionnel des classements. En 2026, vous devez suivre trois surfaces : les citations dans AI Overview, la présence d'entités dans le Knowledge Graph et la capture d'extraits vedettes. Ce tutoriel construit un tableau de bord de performance GEO qui vérifie ces trois surfaces pour une liste de requêtes cibles, calcule un score GEO composite et suit les changements dans le temps. Chaque vérification de requête coûte un crédit Scavio à 0,005 $.
Prérequis
- Python 3.9+ installé
- bibliothèque requests installée
- Une clé API Scavio depuis scavio.dev
- Une liste de requêtes cibles à suivre
Parcours
Étape 1: Définir les métriques de performance GEO
Configurer les trois surfaces à vérifier pour chaque requête : citation dans AI Overview, présence dans le Knowledge Graph et capture d'extraits vedettes.
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',
]Étape 2: Vérifier les trois surfaces GEO par requête
Pour chaque requête, vérifier la citation dans AI Overview, la mention dans le Knowledge Graph et la propriété d'extrait vedette. Retourner un résultat structuré.
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,
}Étape 3: Exécuter le rapport complet de performance GEO
Vérifier toutes les requêtes et calculer les métriques GEO agrégées. Enregistrer le rapport pour comparaison historique.
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)Exemple Python
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)Exemple JavaScript
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');
}
})();Sortie attendue
[ 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%