Resumen
Automatizado diario reporting on Generative Engine Optimizacion metricas. Rastrear cual palabras clave activar AI Overviews, si your marca es cited, y como competidor citacion share cambios sobre time.
Desencadenador
Diario cron at 07:00 UTC
Programación
Diario at 07:00 UTC
Pasos del flujo de trabajo
Cargar palabra clave portfolio
Leer palabras clave objetivo grouped by categoria (marca, categoria, competidor). Cada palabra clave tiene un objetivo nombre de marca to rastrear citaciones for.
Consulta con AI Overview extraccion
Search Google via Scavio con ai_overview enabled for cada palabra clave. Extraer el full AI Overview text y citacion lista.
Analizar marca citaciones
Verificar AI Overview text for menciones de marca y citacion URLs. Rastrear own marca, competidor marcas, y nuevo entrants.
Calcular share-of-voice
For cada palabra clave categoria, calcular que porcentaje of AI Overviews cite el objetivo marca vs competidores. Rastrear diario deltas.
Generar y enviar informe
Compile diario GEO/AEO informe con citacion counts, share-of-voice by categoria, y alertas for citacion gains/losses. Enviar via correo electronico o Slack.
Implementacion en Python
import requests, os, json
from datetime import date
from collections import defaultdict
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}
def check_aeo_citation(keyword, brands):
r = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'platform': 'google', 'query': keyword, 'ai_overview': True},
timeout=10).json()
aio = r.get('ai_overview', {}) or {}
aio_text = (aio.get('text', '') or '').lower()
citations = aio.get('citations', [])
brand_citations = {}
for brand in brands:
cited_in_text = brand.lower() in aio_text
cited_in_links = any(brand.lower() in (c.get('domain', '') or '').lower() for c in citations)
brand_citations[brand] = cited_in_text or cited_in_links
return {
'keyword': keyword,
'has_aio': bool(r.get('ai_overview')),
'brand_citations': brand_citations,
'citation_count': len(citations),
}
brands = ['OurBrand', 'CompetitorA', 'CompetitorB']
keywords = ['best crm software 2026', 'crm for startups', 'crm comparison 2026']
report = defaultdict(lambda: {'cited': 0, 'total': 0})
for kw in keywords:
result = check_aeo_citation(kw, brands)
if result['has_aio']:
for brand, cited in result['brand_citations'].items():
report[brand]['total'] += 1
if cited:
report[brand]['cited'] += 1
status = ', '.join(b for b, c in result['brand_citations'].items() if c) or 'none'
print(f"{kw}: {status}")
print(f"\n--- Share of Voice ({date.today()}) ---")
for brand, data in report.items():
sov = data['cited'] / data['total'] * 100 if data['total'] > 0 else 0
print(f" {brand}: {sov:.0f}% ({data['cited']}/{data['total']})")Implementacion en JavaScript
const H = {"x-api-key": process.env.SCAVIO_API_KEY, "Content-Type": "application/json"};
async function checkAeoCitation(keyword, brands) {
const r = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST", headers: H,
body: JSON.stringify({platform: "google", query: keyword, ai_overview: true})
}).then(r => r.json());
const aio = r.ai_overview || {};
const text = (aio.text || "").toLowerCase();
const citations = aio.citations || [];
const brandCitations = {};
for (const brand of brands) {
const inText = text.includes(brand.toLowerCase());
const inLinks = citations.some(c => (c.domain || "").toLowerCase().includes(brand.toLowerCase()));
brandCitations[brand] = inText || inLinks;
}
return {keyword, hasAio: Boolean(r.ai_overview), brandCitations, citationCount: citations.length};
}
(async () => {
const brands = ["OurBrand", "CompetitorA", "CompetitorB"];
const keywords = ["best crm software 2026", "crm for startups", "crm comparison 2026"];
const report = {};
brands.forEach(b => report[b] = {cited: 0, total: 0});
for (const kw of keywords) {
const result = await checkAeoCitation(kw, brands);
if (result.hasAio) {
for (const [brand, cited] of Object.entries(result.brandCitations)) {
report[brand].total++;
if (cited) report[brand].cited++;
}
const cited = Object.entries(result.brandCitations).filter(([,v]) => v).map(([k]) => k).join(", ") || "none";
console.log(`${kw}: ${cited}`);
}
}
console.log("\n--- Share of Voice ---");
for (const [brand, data] of Object.entries(report)) {
const sov = data.total > 0 ? (data.cited / data.total * 100).toFixed(0) : 0;
console.log(` ${brand}: ${sov}% (${data.cited}/${data.total})`);
}
})();Plataformas utilizadas
Búsqueda web con grafo de conocimiento, PAA y resúmenes de IA