Las resúmenes de IA de Google ahora aparecen en más del 30% de las consultas comerciales, y las marcas citadas en esos resúmenes capturan clics sin clasificarse en el top 10 tradicional. Para rastrear si su marca aparece en los resúmenes de IA es necesario verificar cada palabra clave objetivo con el parámetro include_ai_overview y analizar la respuesta en busca de menciones de marca. Este tutorial crea un rastreador de visibilidad GEO diario a $0,005 por verificación de palabra clave.
Requisitos previos
- Python 3.8+
- solicita biblioteca
- Una clave API de Scavio de scavio.dev
- Una lista de palabras clave objetivo para monitorear
Guia paso a paso
Paso 1: Configurar la configuración de seguimiento GEO
Defina los términos de su marca y las palabras clave objetivo para monitorear las citas de AI Overview.
import os, requests, json, sqlite3
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
BRAND_TERMS = ['scavio', 'scavio.dev', 'scavio api']
KEYWORDS = ['best serp api 2026', 'search api for agents', 'google search api python',
'web scraping alternative', 'ai agent search tool']
db = sqlite3.connect('geo_visibility.db')
db.execute('''CREATE TABLE IF NOT EXISTS checks (
keyword TEXT, checked_at TEXT, has_ai_overview INTEGER,
brand_cited INTEGER, citation_text TEXT, position INTEGER
)''')
db.commit()
print(f'Tracking {len(KEYWORDS)} keywords for {len(BRAND_TERMS)} brand terms')Paso 2: Verifique la presencia de AI Overview y las citas de marca
Consulta cada palabra clave con include_ai_overview y analiza las menciones de marca.
def check_keyword(keyword, brand_terms):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us',
'include_ai_overview': True}).json()
ao = data.get('ai_overview', {})
ao_text = json.dumps(ao).lower() if ao else ''
cited = any(b in ao_text for b in brand_terms)
org = data.get('organic_results', [])
pos = next((r['position'] for r in org
if any(b in r.get('link', '').lower() for b in brand_terms)), None)
now = datetime.now().isoformat()
db.execute('INSERT INTO checks VALUES (?,?,?,?,?,?)',
(keyword, now, 1 if ao else 0, 1 if cited else 0,
ao_text[:500] if cited else '', pos))
db.commit()
return {'keyword': keyword, 'has_ao': bool(ao), 'cited': cited, 'position': pos}
for kw in KEYWORDS:
r = check_keyword(kw, BRAND_TERMS)
status = 'CITED' if r['cited'] else ('AO present' if r['has_ao'] else 'No AO')
print(f' {kw:35} | {status:12} | Organic: #{r["position"] or "-"}')Paso 3: Generar un informe de visibilidad diario
Agregue los resultados de las comprobaciones en una puntuación diaria de visibilidad GEO.
def daily_report():
today = datetime.now().strftime('%Y-%m-%d')
rows = db.execute(
"SELECT keyword, has_ai_overview, brand_cited, position FROM checks WHERE checked_at LIKE ?",
(f'{today}%',)).fetchall()
total = len(rows)
ao_count = sum(1 for r in rows if r[1])
cited_count = sum(1 for r in rows if r[2])
avg_pos = [r[3] for r in rows if r[3]]
print(f'\nGEO Visibility Report - {today}')
print(f' Keywords checked: {total}')
print(f' AI Overviews present: {ao_count}/{total} ({ao_count/total*100:.0f}%)')
print(f' Brand cited in AO: {cited_count}/{total} ({cited_count/total*100:.0f}%)')
if avg_pos:
print(f' Avg organic position: {sum(avg_pos)/len(avg_pos):.1f}')
print(f' Cost: ${total * 0.005:.3f}')
return {'date': today, 'total': total, 'ao_rate': ao_count/total, 'citation_rate': cited_count/total}
daily_report()Paso 4: Seguimiento de las tendencias de citas a lo largo del tiempo
Compare puntuaciones diarias para detectar ganancias o pérdidas de visibilidad GEO.
def trend_report(days=7):
rows = db.execute(
'SELECT DATE(checked_at) as d, AVG(has_ai_overview), AVG(brand_cited) FROM checks GROUP BY d ORDER BY d DESC LIMIT ?',
(days,)).fetchall()
print(f'\nGEO Visibility Trend ({len(rows)} days):')
for date, ao_rate, cite_rate in rows:
bar_ao = '#' * int(ao_rate * 20)
bar_cite = '#' * int(cite_rate * 20)
print(f' {date} | AO: {ao_rate*100:5.1f}% {bar_ao:20} | Cited: {cite_rate*100:5.1f}% {bar_cite:20}')
if len(rows) >= 2:
change = (rows[0][2] - rows[-1][2]) * 100
direction = 'UP' if change > 0 else 'DOWN' if change < 0 else 'FLAT'
print(f' Citation rate {direction} {abs(change):.1f}pp over {len(rows)} days')
trend_report()Ejemplo en Python
import os, requests, json
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def check_geo(keyword, brand):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us', 'include_ai_overview': True}).json()
ao = data.get('ai_overview', {})
cited = brand.lower() in json.dumps(ao).lower() if ao else False
print(f'{keyword}: AO={bool(ao)}, Brand cited={cited}. Cost: $0.005')
check_geo('best serp api 2026', 'scavio')Ejemplo en JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function checkGeo(keyword, brand) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: keyword, country_code: 'us', include_ai_overview: true })
}).then(r => r.json());
const ao = data.ai_overview || {};
const cited = JSON.stringify(ao).toLowerCase().includes(brand.toLowerCase());
console.log(`${keyword}: AO=${!!data.ai_overview}, Cited=${cited}`);
}
checkGeo('best serp api 2026', 'scavio').catch(console.error);Salida esperada
Tracking 5 keywords for 3 brand terms
best serp api 2026 | CITED | Organic: #4
search api for agents | AO present | Organic: #6
google search api python | No AO | Organic: #8
web scraping alternative | AO present | Organic: #12
ai agent search tool | CITED | Organic: #5
GEO Visibility Report - 2026-05-19
Keywords checked: 5
AI Overviews present: 4/5 (80%)
Brand cited in AO: 2/5 (40%)
Avg organic position: 7.0
Cost: $0.025