Aperçu
L'optimisation pour les moteurs génératifs (GEO) devient cruciale alors que les AI Overviews dominent les SERP. Ce workflow s'exécute chaque lundi, prend vos pages les plus performantes, vérifie si elles apparaissent dans les AI Overviews, et signale les écarts de conformité tels que l'absence de données structurées, des citations faibles ou un balisage d'entités manquant. À 0,005 $ par crédit, auditer 50 pages coûte environ 0,25 $ par semaine. Les résultats sont exportés sous forme de liste priorisée de correctifs afin que votre équipe de contenu sache exactement quoi mettre à jour.
Déclencheur
Cron lundi 6h UTC
Planification
Tous les lundis à 6h
Étapes du workflow
Charger l'inventaire des pages
Lire la liste des pages principales et leurs mots-clés cibles à partir d'un fichier CSV ou d'une base de données.
Rechercher chaque mot-clé via Scavio
Pour chaque mot-clé, appeler la recherche Scavio sur Google pour capturer l'intégralité des SERP, y compris les données AI Overview.
Détecter la présence d'AI Overview
Analyser la réponse pour vérifier si votre URL apparaît dans la section AI Overview ou uniquement dans les résultats organiques traditionnels.
Évaluer la conformité GEO
Évaluer chaque page selon les signaux GEO : données structurées, densité de citations, mentions d'entités et sources autoritaires.
Générer la liste des correctifs
Classer les pages par gravité des écarts de conformité et exporter un tableur priorisé avec les correctifs recommandés spécifiques.
Implémentation Python
import requests, os, json, csv
from pathlib import Path
from datetime import date
API_KEY = os.environ["SCAVIO_API_KEY"]
SH = {"x-api-key": API_KEY, "Content-Type": "application/json"}
PAGES_FILE = Path("top_pages.csv")
def search_keyword(keyword: str) -> dict:
resp = requests.post(
"https://api.scavio.dev/api/v1/search",
headers=SH,
json={"query": keyword, "platform": "google"},
timeout=15,
)
resp.raise_for_status()
return resp.json()
def check_ai_overview(serp: dict, target_url: str) -> dict:
ai_overview = serp.get("ai_overview", {})
in_overview = False
if ai_overview:
sources = ai_overview.get("sources", [])
in_overview = any(target_url in s.get("url", "") for s in sources)
organic = serp.get("organic", [])
organic_pos = next((i + 1 for i, r in enumerate(organic) if target_url in r.get("url", "")), None)
return {"in_ai_overview": in_overview, "organic_position": organic_pos}
def run_audit():
results = []
with open(PAGES_FILE) as f:
reader = csv.DictReader(f)
for row in reader:
keyword = row["keyword"]
url = row["url"]
serp = search_keyword(keyword)
presence = check_ai_overview(serp, url)
score = 100
if not presence["in_ai_overview"]:
score -= 40
if presence["organic_position"] is None:
score -= 30
elif presence["organic_position"] > 5:
score -= 15
results.append({
"keyword": keyword,
"url": url,
"geo_score": score,
**presence,
})
results.sort(key=lambda r: r["geo_score"])
out = Path(f"geo_audit_{date.today()}.json")
out.write_text(json.dumps(results, indent=2))
print(f"Audit complete: {len(results)} pages checked")
for r in results[:10]:
print(f" [{r['geo_score']}] {r['keyword']} - AI Overview: {r['in_ai_overview']}")
return results
run_audit()Implémentation JavaScript
const SH = {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'};
const fs = await import('fs');
const pages = fs.readFileSync('top_pages.csv', 'utf8').trim().split('\n');
const header = pages.shift().split(',');
const rows = pages.map(line => {
const cols = line.split(',');
return {keyword: cols[header.indexOf('keyword')], url: cols[header.indexOf('url')]};
});
async function searchKeyword(keyword) {
const r = await fetch('https://api.scavio.dev/api/v1/search', {method:'POST', headers:SH, body:JSON.stringify({query:keyword, platform:'google'})});
return r.json();
}
function checkAiOverview(serp, targetUrl) {
const aiOverview = serp.ai_overview || {};
const inOverview = (aiOverview.sources || []).some(s => (s.url || '').includes(targetUrl));
const organicPos = (serp.organic || []).findIndex(r => (r.url || '').includes(targetUrl));
return {inAiOverview: inOverview, organicPosition: organicPos >= 0 ? organicPos + 1 : null};
}
const results = [];
for (const row of rows) {
const serp = await searchKeyword(row.keyword);
const presence = checkAiOverview(serp, row.url);
let score = 100;
if (!presence.inAiOverview) score -= 40;
if (presence.organicPosition === null) score -= 30;
else if (presence.organicPosition > 5) score -= 15;
results.push({keyword:row.keyword, url:row.url, geoScore:score, ...presence});
}
results.sort((a,b) => a.geoScore - b.geoScore);
fs.writeFileSync('geo_audit_'+new Date().toISOString().split('T')[0]+'.json', JSON.stringify(results, null, 2));
console.log('Audit complete: '+results.length+' pages');
results.slice(0,10).forEach(r => console.log(' ['+r.geoScore+'] '+r.keyword+' - AI Overview: '+r.inAiOverview));Plateformes utilisées
Recherche web avec graphe de connaissances, PAA et aperçus IA