L'optimisation des moteurs génératifs (GEO) mesure la visibilité de votre marque dans les résultats de recherche générés par IA. Ce tutoriel construit un pipeline de reporting automatisé qui suit votre visibilité GEO sur des mots-clés, compare avec les concurrents et génère des rapports hebdomadaires. Chaque analyse de mot-clé coûte 0,005 $.
Prérequis
- Python 3.8+
- bibliothèque requests
- Une clé API Scavio de scavio.dev
- Mots-clés cibles et domaines concurrents
Parcours
Étape 1: Définir les métriques de visibilité GEO
Mesurer plusieurs signaux qui indiquent à quel point votre contenu est classé dans les résultats génératifs.
import os, requests, json
from datetime import datetime
from collections import defaultdict
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
BRAND = 'scavio.dev'
COMPETITORS = ['tavily.com', 'serpapi.com']
KEYWORDS = [
'best search api for ai agents',
'web search api comparison',
'mcp search tool setup',
'serp api free tier',
'search api for rag pipeline',
]
def geo_score_keyword(keyword, domain):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}, timeout=10).json()
ai = data.get('ai_overview', data.get('answer_box', {}))
organic = data.get('organic_results', [])
featured = data.get('featured_snippet', {})
paa = data.get('people_also_ask', [])
domain_l = domain.lower()
# Score components (0-100 each)
ai_score = 30 if (ai and domain_l in json.dumps(ai).lower()) else 0
org_pos = next((i+1 for i, r in enumerate(organic) if domain_l in r.get('link', '').lower()), None)
org_score = max(0, 30 - (org_pos - 1) * 3) if org_pos else 0
feat_score = 20 if (featured and domain_l in json.dumps(featured).lower()) else 0
paa_score = 20 if any(domain_l in json.dumps(q).lower() for q in paa) else 0
total = ai_score + org_score + feat_score + paa_score
return {'keyword': keyword, 'total': total, 'ai': ai_score, 'organic': org_score,
'featured': feat_score, 'paa': paa_score, 'organic_pos': org_pos}
print(f'GEO Visibility Scan for {BRAND}\n')
scores = [geo_score_keyword(kw, BRAND) for kw in KEYWORDS]
for s in scores:
pos = f'#{s["organic_pos"]}' if s['organic_pos'] else '-'
print(f' {s["keyword"][:40]:40} | GEO: {s["total"]:3} | Pos: {pos}')
avg = sum(s['total'] for s in scores) / len(scores)
print(f'\nAverage GEO Score: {avg:.0f}/100 | Cost: ${len(KEYWORDS) * 0.005:.3f}')Étape 2: Comparer avec les concurrents
Exécuter la même analyse GEO pour les domaines concurrents et les classer.
def competitive_geo(keywords, brand, competitors):
all_domains = [brand] + competitors
domain_scores = defaultdict(list)
for kw in keywords:
for domain in all_domains:
score = geo_score_keyword(kw, domain)
domain_scores[domain].append(score)
print(f'\n=== GEO Competitive Analysis ===')
rankings = []
for domain, keyword_scores in domain_scores.items():
avg = sum(s['total'] for s in keyword_scores) / len(keyword_scores)
ai_pct = sum(1 for s in keyword_scores if s['ai'] > 0) / len(keyword_scores) * 100
rankings.append({'domain': domain, 'avg_geo': avg, 'ai_citation_pct': ai_pct})
rankings.sort(key=lambda x: x['avg_geo'], reverse=True)
for i, r in enumerate(rankings, 1):
marker = ' <-- you' if r['domain'] == brand else ''
print(f' {i}. {r["domain"]:25} | GEO: {r["avg_geo"]:5.1f} | AI cited: {r["ai_citation_pct"]:.0f}%{marker}')
return rankings
rankings = competitive_geo(KEYWORDS, BRAND, COMPETITORS)
print(f'\nTotal cost: ${len(KEYWORDS) * (1 + len(COMPETITORS)) * 0.005:.3f}')Étape 3: Générer le rapport GEO hebdomadaire
Compiler toutes les données dans un rapport hebdomadaire formaté avec des tendances et des recommandations.
def weekly_geo_report(brand, scores, rankings):
print(f'\n{"=" * 60}')
print(f' WEEKLY GEO VISIBILITY REPORT')
print(f' Brand: {brand} | Date: {datetime.now().strftime("%Y-%m-%d")}')
print(f'{"=" * 60}')
avg_geo = sum(s['total'] for s in scores) / len(scores)
ai_cited = sum(1 for s in scores if s['ai'] > 0)
print(f'\n Overall GEO Score: {avg_geo:.0f}/100')
print(f' AI Citations: {ai_cited}/{len(scores)} keywords')
print(f' Competitive Rank: {next((i+1 for i, r in enumerate(rankings) if r["domain"] == brand), "?")} of {len(rankings)}')
# Breakdown
print(f'\n Score Breakdown:')
print(f' AI Overview: {sum(s["ai"] for s in scores)/len(scores):.0f}/30')
print(f' Organic: {sum(s["organic"] for s in scores)/len(scores):.0f}/30')
print(f' Featured: {sum(s["featured"] for s in scores)/len(scores):.0f}/20')
print(f' People Ask: {sum(s["paa"] for s in scores)/len(scores):.0f}/20')
# Opportunities
weak = [s for s in scores if s['total'] < 30]
if weak:
print(f'\n Improvement Opportunities:')
for s in weak:
print(f' - {s["keyword"][:40]} (GEO: {s["total"]})')
print(f'\n Weekly cost: ${len(KEYWORDS) * (1 + len(COMPETITORS)) * 0.005 * 7:.2f}')
weekly_geo_report(BRAND, scores, rankings)Exemple Python
import os, requests, json
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def geo_check(keyword, domain):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}, timeout=10).json()
ai = data.get('ai_overview', data.get('answer_box', {}))
cited = domain.lower() in json.dumps(ai).lower() if ai else False
org = next((i+1 for i, r in enumerate(data.get('organic_results', [])) if domain in r.get('link', '')), None)
print(f'{keyword[:35]:35} | AI: {cited} | Organic: {org or "-"}')
geo_check('best search api 2026', 'scavio.dev')Exemple JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: 'best search api 2026', country_code: 'us' })
}).then(r => r.json());
const ai = data.ai_overview || data.answer_box || {};
const cited = JSON.stringify(ai).toLowerCase().includes('scavio');
console.log(`GEO visibility: AI cited=${cited}`);Sortie attendue
GEO Visibility Scan for scavio.dev
best search api for ai agents | GEO: 60 | Pos: #3
web search api comparison | GEO: 30 | Pos: #5
mcp search tool setup | GEO: 50 | Pos: #2
serp api free tier | GEO: 27 | Pos: #7
search api for rag pipeline | GEO: 47 | Pos: #4
Average GEO Score: 43/100 | Cost: $0.025
=== GEO Competitive Analysis ===
1. scavio.dev | GEO: 43.0 | AI cited: 40%
2. serpapi.com | GEO: 38.0 | AI cited: 20%
3. tavily.com | GEO: 32.0 | AI cited: 20%
============================================================
WEEKLY GEO VISIBILITY REPORT
Brand: scavio.dev | Date: 2026-05-21
============================================================
Overall GEO Score: 43/100
AI Citations: 2/5 keywords
Competitive Rank: 1 of 3
Weekly cost: $0.53