La investigación de keywords con IA es poco fiable porque el modelo inventa términos verosímiles que nadie busca: el ejemplo de r/SEO de Claude sugiriendo "platos de cerámica de fabricación lenta" y "vajilla de cerámica desparejada" para una tienda de alfarería resume todo el problema en una línea. La solución es el anclaje: dale al LLM preguntas reales de People Also Ask, búsquedas relacionadas y títulos de competidores de una SERP en vivo y luego restríngelo a expandir solo desde ahí. Este tutorial extrae esa señal del endpoint de Google de Scavio y se la entrega a cualquier modelo como un brief anclado. El modelo deja de adivinar y empieza a trabajar con términos que la SERP demuestra que existen.
Requisitos previos
- Python 3.8+ o Node 18+ instalado
- Una clave de API de Scavio desde scavio.dev (50 créditos gratis al registrarte)
- requests instalado (pip install requests) para Python
- Cualquier API de LLM (el paso de anclaje es agnóstico al modelo)
Guia paso a paso
Paso 1: Extrae la SERP completa para tu término semilla
Llama a https://api.scavio.dev/api/v1/google con light_request:false (2 créditos) para que la respuesta incluya los bloques questions (People Also Ask) y related_searches junto a los resultados orgánicos. Son consultas reales que la propia Google muestra: la verdad de fondo que al modelo le falta.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}", "Content-Type": "application/json"}
def serp(seed):
r = requests.post("https://api.scavio.dev/api/v1/google",
headers=H, json={"query": seed, "light_request": False})
r.raise_for_status()
return r.json().get("data", {})Paso 2: Extrae la señal real de consultas
Saca el bloque questions, related_searches y los títulos orgánicos top. Juntos son el vocabulario que tus compradores y competidores usan de verdad, no la suposición del modelo. Para la tienda de alfarería, esto devuelve términos como 'platos de cerámica hechos a mano' que la gente real busca, no frases inventadas.
def signal(data):
return {
"paa": [q.get("question") for q in data.get("questions", [])],
"related": data.get("related_searches", []),
"titles": [o.get("title") for o in data.get("organic", [])[:10]],
}Paso 3: Construye un prompt de anclaje restringido
Entrega al modelo la señal real y prohíbe inventar de forma explícita. La instrucción importa: expande solo desde las preguntas, búsquedas relacionadas y títulos provistos; no generes keywords que no estén ancladas en estos datos. Esta única restricción es la que mata el fallo de 'platos de cerámica de fabricación lenta'.
def grounding_prompt(seed, sig):
return f'''You are doing keyword research for: {seed}.
Use ONLY the real search data below. Do not invent keywords.
People Also Ask: {sig['paa']}
Related searches: {sig['related']}
Competitor titles: {sig['titles']}
Return 20 keyword clusters grounded strictly in the terms above.'''Paso 4: Genera y verifica contra la fuente
Ejecuta el prompt en tu LLM y luego verifica: cada keyword que el modelo devuelva debería rastrearse hasta un término en el PAA, las búsquedas relacionadas o los títulos. Descarta lo que no. Este paso de verificación es un seguro barato: pilla al modelo cuando recae en inventar.
def verify(keywords, sig):
pool = " ".join(sig["paa"] + sig["related"] + sig["titles"]).lower()
return [k for k in keywords if any(w in pool for w in k.lower().split())]Paso 5: Localiza el anclaje para mercados fuera de EE. UU.
El hilo de r/SEO también señaló el sesgo estadounidense de la salida de IA ('cambia tu vida' para un público suizo). El anclaje también arregla esto: pasa una pista de país o idioma a la llamada de la SERP para que la señal real venga del mercado correcto y luego restringe el modelo a ella. Los datos, no el sesgo de entrenamiento del modelo, fijan el vocabulario regional.
def localized_serp(seed, country="ch"):
r = requests.post("https://api.scavio.dev/api/v1/google",
headers=H, json={"query": seed, "light_request": False, "country": country})
return r.json().get("data", {})Ejemplo en Python
import os, requests
H = {"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}", "Content-Type": "application/json"}
def grounded_keywords(seed):
data = requests.post("https://api.scavio.dev/api/v1/google", headers=H,
json={"query": seed, "light_request": False}).json().get("data", {})
sig = {
"paa": [q.get("question") for q in data.get("questions", [])],
"related": data.get("related_searches", []),
"titles": [o.get("title") for o in data.get("organic", [])[:10]],
}
# feed sig to your LLM with: 'expand only from these real terms, do not invent'
return sig
print(grounded_keywords("handmade ceramic dinner plates"))Ejemplo en JavaScript
const H = { Authorization: `Bearer ${process.env.SCAVIO_API_KEY}`, 'Content-Type': 'application/json' };
async function groundedKeywords(seed) {
const res = await fetch('https://api.scavio.dev/api/v1/google', {
method: 'POST', headers: H,
body: JSON.stringify({ query: seed, light_request: false }),
}).then(r => r.json());
const data = res.data || {};
return {
paa: (data.questions || []).map(q => q.question),
related: data.related_searches || [],
titles: (data.organic || []).slice(0, 10).map(o => o.title),
};
}
groundedKeywords('handmade ceramic dinner plates').then(console.log);Salida esperada
{'paa': ['Are handmade plates food safe?', 'How much do ceramic dinner plates cost?', ...],
'related': ['handmade ceramic dinnerware set', 'stoneware dinner plates handmade', ...],
'titles': ['Handmade Ceramic Dinner Plates - ...', ...]}
# Real search terms the model can expand from - no invented 'slow made ceramic plates'.