Un tableau de bord d'audit SEO regroupe les données de classement, la présence de fonctionnalités SERP et les positions des concurrents dans une vue unique qui se met à jour à la demande. Les outils commerciaux comme Ahrefs ou SEMrush facturent des centaines d'euros par mois pour cette fonctionnalité. Ce tutoriel construit un tableau de bord léger en Flask qui interroge l'API Scavio pour chaque mot-clé, calcule les métriques et les restitue sous forme d'API JSON pouvant alimenter n'importe quel frontend. Le tableau de bord suit votre classement, les classements des concurrents, la propriété des extraits optimisés, la présence des aperçus IA et la couverture des questions connexes.
Prérequis
- Python 3.10 ou supérieur
- pip install requests flask
- Une clé API Scavio
- Un domaine et une liste de mots-clés à auditer
Parcours
Étape 1: Définir la configuration de l'audit
Configurez le domaine cible, les domaines concurrents et les mots-clés à suivre. Cette configuration pilote l'ensemble du tableau de bord.
CONFIG = {
"domain": "mysite.com",
"competitors": ["competitor-a.com", "competitor-b.io"],
"keywords": [
"api documentation best practices",
"rest api design guide",
"graphql vs rest 2026",
]
}Étape 2: Auditer un seul mot-clé
Récupérez les données SERP pour un mot-clé et extrayez toutes les métriques pertinentes : classement, classements des concurrents, fonctionnalités SERP et statut de l'aperçu IA.
def audit_keyword(keyword: str, config: dict) -> dict:
r = requests.post(ENDPOINT, headers={"x-api-key": API_KEY},
json={"query": keyword, "country_code": "us", "ai_overview": True})
r.raise_for_status()
data = r.json()
organic = data.get("organic_results", [])
my_rank = next((r["position"] for r in organic if config["domain"] in r.get("link", "")), None)
comp_ranks = {}
for c in config["competitors"]:
comp_ranks[c] = next((r["position"] for r in organic if c in r.get("link", "")), None)
return {
"keyword": keyword,
"my_rank": my_rank,
"competitor_ranks": comp_ranks,
"has_featured_snippet": bool(data.get("featured_snippet")),
"has_ai_overview": bool(data.get("ai_overview")),
"paa_count": len(data.get("people_also_ask", [])),
"total_results": len(organic),
}Étape 3: Construire l'API du tableau de bord
Créez un endpoint Flask qui exécute l'audit complet et renvoie les résultats au format JSON.
from flask import Flask, jsonify
app = Flask(__name__)
@app.route("/audit")
def audit():
results = [audit_keyword(kw, CONFIG) for kw in CONFIG["keywords"]]
summary = {
"domain": CONFIG["domain"],
"keywords_tracked": len(results),
"keywords_ranked": sum(1 for r in results if r["my_rank"]),
"avg_position": round(sum(r["my_rank"] for r in results if r["my_rank"]) / max(sum(1 for r in results if r["my_rank"]), 1), 1),
"ai_overview_pct": f"{sum(1 for r in results if r['has_ai_overview']) / len(results) * 100:.0f}%",
}
return jsonify({"summary": summary, "keywords": results})Étape 4: Exécuter le tableau de bord
Démarrez le serveur Flask et accédez à l'audit à l'adresse http://localhost:5000/audit.
if __name__ == "__main__":
app.run(port=5000, debug=True)Exemple Python
import os
import requests
from flask import Flask, jsonify
API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
ENDPOINT = "https://api.scavio.dev/api/v1/search"
CONFIG = {"domain": "mysite.com", "competitors": ["comp-a.com"], "keywords": ["api design guide", "rest vs graphql"]}
def audit(kw: str) -> dict:
r = requests.post(ENDPOINT, headers={"x-api-key": API_KEY},
json={"query": kw, "country_code": "us", "ai_overview": True})
r.raise_for_status()
d = r.json()
organic = d.get("organic_results", [])
rank = next((r["position"] for r in organic if CONFIG["domain"] in r.get("link", "")), None)
return {"keyword": kw, "rank": rank, "ai_overview": bool(d.get("ai_overview")), "paa": len(d.get("people_also_ask", []))}
app = Flask(__name__)
@app.route("/audit")
def run_audit():
results = [audit(kw) for kw in CONFIG["keywords"]]
return jsonify(results)
if __name__ == "__main__":
app.run(port=5000)Exemple JavaScript
const API_KEY = process.env.SCAVIO_API_KEY || "your_scavio_api_key";
const ENDPOINT = "https://api.scavio.dev/api/v1/search";
const http = require("http");
const CONFIG = { domain: "mysite.com", keywords: ["api design guide", "rest vs graphql"] };
async function audit(kw) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ query: kw, country_code: "us", ai_overview: true })
});
const d = await res.json();
const organic = d.organic_results || [];
const rank = organic.find(r => r.link.includes(CONFIG.domain))?.position || null;
return { keyword: kw, rank, aiOverview: !!d.ai_overview, paa: (d.people_also_ask || []).length };
}
http.createServer(async (req, res) => {
if (req.url === "/audit") {
const results = await Promise.all(CONFIG.keywords.map(audit));
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(results, null, 2));
}
}).listen(5000);Sortie attendue
GET /audit
{
"summary": {
"domain": "mysite.com",
"keywords_tracked": 3,
"keywords_ranked": 2,
"avg_position": 5.5,
"ai_overview_pct": "67%"
},
"keywords": [
{"keyword": "api design guide", "my_rank": 4, "has_ai_overview": true, "paa_count": 4},
{"keyword": "rest vs graphql", "my_rank": 7, "has_ai_overview": true, "paa_count": 3},
{"keyword": "graphql vs rest 2026", "my_rank": null, "has_ai_overview": false, "paa_count": 2}
]
}