Un panel de auditoría de SEO consolida los datos de clasificación, la presencia de funciones SERP y las posiciones de la competencia en una vista única que se actualiza según demanda. Las herramientas comerciales como Ahrefs o SEMrush cobran cientos de dólares al mes por esta capacidad. Este tutorial crea un panel de Flask liviano que consulta la API de Scavio para cada palabra clave, calcula métricas y las representa como una API JSON que puede alimentar cualquier interfaz. El panel realiza un seguimiento de su clasificación, las clasificaciones de la competencia, la propiedad de fragmentos destacados, la presencia de descripción general de IA y la cobertura de La gente también pregunta.
Requisitos previos
- Python 3.10 o superior
- matraz de solicitudes de instalación de pip
- Una clave API de Scavio
- Una lista de dominios y palabras clave para auditar
Guia paso a paso
Paso 1: Definir la configuración de auditoría
Configure el dominio de destino, los dominios de la competencia y las palabras clave para realizar un seguimiento. Esta configuración controla todo el tablero.
CONFIG = {
"domain": "mysite.com",
"competitors": ["competitor-a.com", "competitor-b.io"],
"keywords": [
"api documentation best practices",
"rest api design guide",
"graphql vs rest 2026",
]
}Paso 2: Auditar una sola palabra clave
Obtenga datos SERP para una palabra clave y extraiga todas las métricas relevantes: clasificación, clasificaciones de la competencia, funciones SERP y estado general de la 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),
}Paso 3: Cree la API del panel
Cree un punto final de Flask que ejecute la auditoría completa y devuelva resultados como 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})Paso 4: Ejecute el panel
Inicie el servidor Flask y acceda a la auditoría en http://localhost:5000/audit.
if __name__ == "__main__":
app.run(port=5000, debug=True)Ejemplo en 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)Ejemplo en 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);Salida esperada
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}
]
}