Resumen
Este flujo de trabajo genera semanal SEO informes for todos agency clientes de raw SERP datos. It rastrea palabra clave posicionamientos, monitorea caracteristica SERP cambios, identifies competidor movements, y produces white-labeled informes in el agency's branding. Replaces per-client herramienta licenses con un flat API cost.
Desencadenador
Cron programar (cada Monday at 6:00 AM UTC)
Programación
Ejecuta cada Monday at 6:00 AM UTC
Pasos del flujo de trabajo
Cargar cliente configurations
Leer cada client's dominio, tracked palabras clave, y competidor dominios de el agency's cliente base de datos.
Rastrear posicionamientos for cada cliente
Call Scavio for cada client's palabras clave to obtener actual positions, caracteristicas SERP, y competidor presence.
Comparar contra anterior semana
Diff actual posicionamientos contra almacenado baselines to identificar improvements, drops, y caracteristica cambios.
Generar per-client informes
Construir un structured informe per cliente con posicionamiento resumen, notable cambios, y competidor movements.
Deliver informes
Enviar informes via correo electronico, subir to cliente portal, o push to white-label panel de control.
Implementacion en Python
import requests
import json
from pathlib import Path
from datetime import datetime
API_KEY = "your_scavio_api_key"
CLIENTS = [
{"name": "Client A", "domain": "clienta.com", "keywords": ["seo agency austin", "local seo services texas", "small business seo"]},
{"name": "Client B", "domain": "clientb.com", "keywords": ["saas marketing strategy", "b2b content marketing", "demand generation"]},
]
def track_keyword(keyword: str, domain: str) -> dict:
res = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "google", "query": keyword, "num": 20},
timeout=15,
)
res.raise_for_status()
data = res.json()
position = None
for item in data.get("organic", []):
if domain in item.get("link", ""):
position = item.get("position")
break
return {
"keyword": keyword,
"position": position,
"has_ai_overview": bool(data.get("ai_overview")),
"top_competitors": [r.get("link", "").split("/")[2] if "/" in r.get("link", "") else "" for r in data.get("organic", [])[:5]],
}
def generate_client_report(client: dict) -> dict:
results = [track_keyword(kw, client["domain"]) for kw in client["keywords"]]
ranked = [r for r in results if r["position"]]
avg_pos = sum(r["position"] for r in ranked) / max(len(ranked), 1)
return {
"client": client["name"],
"domain": client["domain"],
"date": datetime.utcnow().strftime("%Y-%m-%d"),
"keywords_tracked": len(results),
"keywords_ranking": len(ranked),
"avg_position": round(avg_pos, 1),
"top_ranking": min((r["position"] for r in ranked), default=None),
"ai_overview_exposure": sum(1 for r in results if r["has_ai_overview"]),
"results": results,
}
def run():
date = datetime.utcnow().strftime("%Y-%m-%d")
total_credits = sum(len(c["keywords"]) for c in CLIENTS)
for client in CLIENTS:
report = generate_client_report(client)
Path(f"report_{client['name'].lower().replace(' ', '_')}_{date}.json").write_text(json.dumps(report, indent=2))
print(f"{report['client']}: {report['keywords_ranking']}/{report['keywords_tracked']} ranking, avg #{report['avg_position']}")
print(f"\nTotal credits used: {total_credits}")
if __name__ == "__main__":
run()Implementacion en JavaScript
const API_KEY = "your_scavio_api_key";
const CLIENTS = [
{ name: "Client A", domain: "clienta.com", keywords: ["seo agency austin", "local seo services texas"] },
{ name: "Client B", domain: "clientb.com", keywords: ["saas marketing strategy", "b2b content marketing"] },
];
async function trackKeyword(keyword, domain) {
const res = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST",
headers: { "x-api-key": API_KEY, "content-type": "application/json" },
body: JSON.stringify({ platform: "google", query: keyword, num: 20 }),
});
if (!res.ok) throw new Error(`scavio ${res.status}`);
const data = await res.json();
let position = null;
for (const item of data.organic ?? []) {
if (item.link?.includes(domain)) { position = item.position; break; }
}
return { keyword, position, hasAiOverview: !!data.ai_overview };
}
for (const client of CLIENTS) {
const results = [];
for (const kw of client.keywords) results.push(await trackKeyword(kw, client.domain));
const ranked = results.filter((r) => r.position);
const avg = ranked.reduce((s, r) => s + r.position, 0) / Math.max(ranked.length, 1);
console.log(`${client.name}: ${ranked.length}/${results.length} ranking, avg #${Math.round(avg * 10) / 10}`);
}Plataformas utilizadas
Búsqueda web con grafo de conocimiento, PAA y resúmenes de IA