Le guide de Google sur l'optimisation générative des moteurs de recherche (Generative Engine Optimization) publié début 2026 a changé les règles du SEO. Les sites qui adoptent une structure priorisant l'AEO (Answer Engine Optimization), évitent les signaux d'autorité inauthentiques et fournissent des réponses concises et riches en entités sont favorisés dans les AI Overviews. Ce tutoriel construit un script d'audit automatisé qui vérifie vos pages selon les critères clés du GEO : titres structurés, schéma FAQ, blocs de réponses concises, absence de statistiques fabriquées et statut actuel de citation dans les AI Overviews. L'audit utilise l'API Scavio pour vérifier si vos pages apparaissent déjà dans les AI Overviews et identifier les lacunes.
Prérequis
- Python 3.9+ installé
- Bibliothèques requests et beautifulsoup4 installées
- Une clé API Scavio depuis scavio.dev
- Une liste d'URLs ou de requêtes cibles à auditer
Parcours
Étape 1: Définir la checklist d'audit GEO
Créez une liste de signaux de conformité GEO à tester sur chaque page. Ceux-ci correspondent directement aux recommandations du guide GEO publié par Google.
import os, requests
from bs4 import BeautifulSoup
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'
GEO_CHECKS = [
'has_faq_schema',
'has_concise_answer_block',
'uses_structured_headings',
'no_fabricated_stats',
'has_entity_mentions',
'appears_in_ai_overview',
]
def fetch_page(url: str) -> BeautifulSoup:
resp = requests.get(url, timeout=10)
return BeautifulSoup(resp.text, 'html.parser')Étape 2: Vérifier les signaux GEO sur la page
Analysez le HTML de la page et recherchez le schéma FAQ, les titres structurés, les paragraphes de réponse concis et le contenu riche en entités.
def audit_page_structure(soup: BeautifulSoup) -> dict:
results = {}
# FAQ schema check
scripts = soup.find_all('script', type='application/ld+json')
faq_found = any('FAQPage' in s.text for s in scripts)
results['has_faq_schema'] = faq_found
# Structured headings
h2s = soup.find_all('h2')
h3s = soup.find_all('h3')
results['uses_structured_headings'] = len(h2s) >= 2 and len(h3s) >= 1
# Concise answer blocks (paragraphs under 300 chars after an h2)
concise_blocks = 0
for h2 in h2s:
next_p = h2.find_next_sibling('p')
if next_p and len(next_p.get_text()) < 300:
concise_blocks += 1
results['has_concise_answer_block'] = concise_blocks >= 1
# Fabricated stats check
import re
text = soup.get_text()
suspicious = re.findall(r'\d{1,3}% of (?:users|companies|developers|people)', text)
results['no_fabricated_stats'] = len(suspicious) == 0
# Entity mentions
entities = len(re.findall(r'[A-Z][a-z]+ (?:API|SDK|framework|platform|tool)', text))
results['has_entity_mentions'] = entities >= 2
return resultsÉtape 3: Vérifier la présence dans AI Overview via SERP
Recherchez votre requête cible et vérifiez si votre domaine apparaît dans la section AI Overview des résultats SERP.
def check_ai_overview(query: str, target_domain: str) -> dict:
resp = requests.post(URL, headers=H,
json={'query': query, 'country_code': 'us', 'include_ai_overview': True})
data = resp.json()
ai_overview = data.get('ai_overview', {})
ai_text = ai_overview.get('text', '')
ai_sources = ai_overview.get('sources', [])
cited = any(target_domain in s.get('link', '') for s in ai_sources)
return {
'appears_in_ai_overview': cited,
'ai_overview_present': bool(ai_text),
'ai_sources_count': len(ai_sources),
}Étape 4: Exécuter l'audit complet et générer un rapport
Combinez toutes les vérifications en une seule fonction d'audit qui note chaque page et produit un rapport succès/échec.
def audit_url(page_url: str, query: str, domain: str) -> dict:
soup = fetch_page(page_url)
structure = audit_page_structure(soup)
ai_check = check_ai_overview(query, domain)
structure.update(ai_check)
passed = sum(1 for v in structure.values() if v is True)
total = len(GEO_CHECKS)
structure['score'] = f'{passed}/{total}'
structure['url'] = page_url
print(f'GEO Audit: {page_url}')
for check in GEO_CHECKS:
status = 'PASS' if structure.get(check) else 'FAIL'
print(f' [{status}] {check}')
print(f' Score: {passed}/{total}')
return structure
audit_url('https://scavio.dev/tutorials/how-to-fetch-google-search-results',
'fetch google search results api', 'scavio.dev')Exemple Python
import os, requests
from bs4 import BeautifulSoup
import re
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
def geo_audit(page_url, query, domain):
# Fetch page
soup = BeautifulSoup(requests.get(page_url).text, 'html.parser')
# On-page checks
scripts = soup.find_all('script', type='application/ld+json')
faq = any('FAQPage' in s.text for s in scripts)
h2s = soup.find_all('h2')
structured = len(h2s) >= 2
text = soup.get_text()
no_fake = len(re.findall(r'\d+% of (?:users|companies)', text)) == 0
# AI Overview check
resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'query': query, 'country_code': 'us', 'include_ai_overview': True})
ai = resp.json().get('ai_overview', {})
cited = any(domain in s.get('link', '') for s in ai.get('sources', []))
checks = {'faq_schema': faq, 'structured_headings': structured,
'no_fabricated_stats': no_fake, 'ai_overview_cited': cited}
passed = sum(1 for v in checks.values() if v)
print(f'GEO Audit: {page_url}')
for k, v in checks.items():
print(f' [{"PASS" if v else "FAIL"}] {k}')
print(f'Score: {passed}/{len(checks)}')
geo_audit('https://scavio.dev', 'scavio search api', 'scavio.dev')Exemple JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function geoAudit(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 ai = data.ai_overview || {};
const sources = ai.sources || [];
const cited = sources.some(s => (s.link || '').includes(domain));
const organic = data.organic_results || [];
const inTop10 = organic.some(r => (r.link || '').includes(domain));
console.log(`GEO Audit for: ${query}`);
console.log(` AI Overview present: ${!!ai.text}`);
console.log(` Cited in AI Overview: ${cited}`);
console.log(` In organic top 10: ${inTop10}`);
console.log(` AI sources: ${sources.length}`);
}
geoAudit('search api for developers', 'scavio.dev');Sortie attendue
GEO Audit: https://scavio.dev/tutorials/how-to-fetch-google-search-results
[PASS] has_faq_schema
[PASS] has_concise_answer_block
[PASS] uses_structured_headings
[PASS] no_fabricated_stats
[PASS] has_entity_mentions
[FAIL] appears_in_ai_overview
Score: 5/6