Resumen
Este flujo de trabajo genera un semanal SEO informe ese combines Google Search Console impresiones y clics, GA4 organic trafico y conversions, y live SERP datos de Scavio. El combined view reveals correlations entre posicionamiento cambios y business metricas ese son invisible cuando datos lives in separate paneles de control.
Desencadenador
Cron programar (cada Monday at 8:00 AM UTC)
Programación
Ejecuta cada Monday at 8:00 AM UTC
Pasos del flujo de trabajo
Pull GSC datos for el past semana
Consulta Google Search Console API for impresiones, clics, CTR, y promedio position per palabra clave.
Pull GA4 organic trafico datos
Consulta GA4 Reporting API for organic sesiones, tasa de rebote, y conversions per pagina de destino.
Obtener actual SERP positions
Call Scavio for cada tracked palabra clave to obtener el actual position, caracteristicas SERP, y AI Overview estado.
Join datos on palabra clave y URL
Combine GSC, GA4, y SERP datos en un unified fila per palabra clave showing el full picture de posicionamiento to conversion.
Generar informe con alertas
Marcar palabras clave donde drops in position correlate con drops in clics y sesiones. Salida as JSON for panel de control o correo electronico.
Implementacion en Python
import requests
import json
from pathlib import Path
from datetime import datetime
API_KEY = "your_scavio_api_key"
DOMAIN = "yourdomain.com"
def get_serp_data(keyword: 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, "ai_overview": True},
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 {
"serp_position": position,
"has_ai_overview": bool(data.get("ai_overview")),
"has_featured_snippet": bool(data.get("featured_snippet")),
"organic_count": len(data.get("organic", [])),
}
def generate_weekly_report(keywords: list[str], gsc_data: dict, ga4_data: dict) -> dict:
rows = []
for kw in keywords:
serp = get_serp_data(kw)
gsc = gsc_data.get(kw, {})
ga4 = ga4_data.get(kw, {})
row = {
"keyword": kw,
"serp_position": serp["serp_position"],
"has_ai_overview": serp["has_ai_overview"],
"gsc_impressions": gsc.get("impressions", 0),
"gsc_clicks": gsc.get("clicks", 0),
"gsc_ctr": gsc.get("ctr", 0),
"ga4_sessions": ga4.get("sessions", 0),
"ga4_conversions": ga4.get("conversions", 0),
}
# Alert: position dropped AND traffic dropped
row["alert"] = (
serp["serp_position"] is not None
and serp["serp_position"] > 10
and gsc.get("clicks", 0) < gsc.get("prev_clicks", gsc.get("clicks", 0)) * 0.8
)
rows.append(row)
alerts = [r for r in rows if r["alert"]]
date = datetime.utcnow().strftime("%Y-%m-%d")
return {"date": date, "keywords": len(rows), "alerts": len(alerts), "rows": rows}
# GSC and GA4 data would come from their respective APIs
gsc = {"best search API": {"impressions": 2400, "clicks": 180, "ctr": 0.075, "prev_clicks": 200}}
ga4 = {"best search API": {"sessions": 170, "conversions": 12}}
report = generate_weekly_report(["best search API"], gsc, ga4)
print(f"Weekly report: {report['keywords']} keywords, {report['alerts']} alerts")
for row in report["rows"]:
status = "ALERT" if row["alert"] else "OK"
print(f" [{status}] {row['keyword']}: #{row['serp_position']} | {row['gsc_clicks']} clicks | {row['ga4_sessions']} sessions")Implementacion en JavaScript
const API_KEY = "your_scavio_api_key";
const DOMAIN = "yourdomain.com";
async function getSerpData(keyword) {
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, ai_overview: true }),
});
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 { serpPosition: position, hasAiOverview: !!data.ai_overview };
}
async function weeklyReport(keywords, gscData, ga4Data) {
const rows = [];
for (const kw of keywords) {
const serp = await getSerpData(kw);
const gsc = gscData[kw] ?? {};
const ga4 = ga4Data[kw] ?? {};
rows.push({ keyword: kw, serpPosition: serp.serpPosition, hasAiOverview: serp.hasAiOverview, gscClicks: gsc.clicks ?? 0, ga4Sessions: ga4.sessions ?? 0, alert: serp.serpPosition > 10 });
}
console.log(`Report: ${rows.length} keywords, ${rows.filter((r) => r.alert).length} alerts`);
for (const r of rows) console.log(` [${r.alert ? "ALERT" : "OK"}] ${r.keyword}: #${r.serpPosition}`);
}
await weeklyReport(["best search API"], { "best search API": { clicks: 180 } }, { "best search API": { sessions: 170 } });Plataformas utilizadas
Búsqueda web con grafo de conocimiento, PAA y resúmenes de IA