Claude no tiene datos de keywords. Si le pides palabras clave, predice cadenas que parecen plausibles, pero no consulta el comportamiento real de busqueda. La solucion a la que llega todo el mundo en Reddit es siempre la misma: darle al modelo una fuente de datos. Puedes conectar el MCP de Semrush (mcp.semrush.com, exige un plan Pro de 139,95 $/mes) o el MCP de Ahrefs (requiere el plan Lite de 129 $/mes) para el volumen de busqueda. Pero para las senales del lado de la SERP, quien posiciona de verdad, las preguntas de People Also Ask, las busquedas relacionadas que el propio Google sugiere, una SERP API sale mas barata y le da al modelo texto real sobre el que razonar. Este tutorial conecta el endpoint de Google de Scavio a un bucle de expansion de keywords. Aclaracion honesta: una SERP API no devuelve volumen de busqueda mensual; para esos numeros sigues necesitando DataForSEO (0,0006 $ por SERP, deposito minimo de 50 $) o Semrush. Lo que si te devuelve es el paisaje real de la SERP, y eso es lo que hace que las sugerencias de temas del modelo sean reales en lugar de inventadas.
Requisitos previos
- Una API key de Scavio (50 creditos gratis al registrarte, sin tarjeta)
- Python 3.9+ o Node 18+
- Saber llamar a un LLM por encima (Claude, GPT o local)
Guia paso a paso
Paso 1: Trae la SERP en vivo de tu keyword semilla
Llama al endpoint de Google con light_request en false. Eso te devuelve los resultados organicos, el knowledge graph, People Also Ask y las busquedas relacionadas en una sola respuesta. Cuesta 2 creditos (0,01 $) en lugar de 1, y esos bloques extra son justo las senales de keywords que buscas.
import os, requests
H = {"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}", "Content-Type": "application/json"}
r = requests.post("https://api.scavio.dev/api/v1/google",
headers=H, json={"query": "serp api", "light_request": False}).json()
paa = [q["question"] for q in r["data"].get("people_also_ask", [])]
related = [s["query"] for s in r["data"].get("related_searches", [])]
print(paa, related)Paso 2: Construye una lista de candidatas que el modelo no invento
People Also Ask te da keywords long-tail con forma de pregunta. Las busquedas relacionadas te dan expansiones laterales que Google asocia a la semilla. Los titulos organicos del top te dicen el angulo que la competencia ya cubre. Concatena las tres en un grupo de candidatas: son datos reales, no una conjetura.
titles = [o["title"] for o in r["data"]["organic_results"][:10]]
candidates = list(dict.fromkeys(paa + related + titles))Paso 3: Pasale las candidatas al modelo para agrupar, no para inventar
Ahora el modelo tiene una tarea en la que de verdad es bueno: agrupar consultas reales en clusters tematicos y cubos de intencion. Esta razonando sobre datos que tu trajiste, asi que no puede alucinar una keyword que no existe en la SERP. Pidele que agrupe por intencion (informacional, comercial, navegacional) y que marque los huecos donde ningun titulo de competidor responde a una pregunta de PAA.
prompt = f"""Cluster these real Google queries into topic groups by search intent.
Flag any People Also Ask question with no matching competitor title (content gap).
Queries: {candidates}"""
# send prompt to your LLM of choicePaso 4: Itera sobre los huecos para profundizar
Coge cada pregunta de hueco de contenido, vuelve a pasarla por el paso 1 como nueva semilla y obtendras un segundo anillo de PAA y busquedas relacionadas. Con dos o tres iteraciones armas un mapa tematico completo anclado por entero en datos de SERP en vivo. Cachea las respuestas de SERP durante un dia: los resultados para la misma consulta rara vez se mueven en 24 horas, asi evitas volver a gastar creditos.
Ejemplo en Python
import os, requests
H = {"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}", "Content-Type": "application/json"}
def serp_signals(seed):
r = requests.post("https://api.scavio.dev/api/v1/google",
headers=H, json={"query": seed, "light_request": False}).json()
d = r["data"]
paa = [q["question"] for q in d.get("people_also_ask", [])]
related = [s["query"] for s in d.get("related_searches", [])]
titles = [o["title"] for o in d.get("organic_results", [])[:10]]
return list(dict.fromkeys(paa + related + titles))
seeds = ["serp api"]
keyword_map = {s: serp_signals(s) for s in seeds}
print(keyword_map)Ejemplo en JavaScript
const H = { Authorization: `Bearer ${process.env.SCAVIO_API_KEY}`, "Content-Type": "application/json" };
async function serpSignals(seed) {
const res = await fetch("https://api.scavio.dev/api/v1/google", {
method: "POST", headers: H,
body: JSON.stringify({ query: seed, light_request: false }),
});
const { data } = await res.json();
const paa = (data.people_also_ask || []).map(q => q.question);
const related = (data.related_searches || []).map(s => s.query);
const titles = (data.organic_results || []).slice(0, 10).map(o => o.title);
return [...new Set([...paa, ...related, ...titles])];
}
console.log(await serpSignals("serp api"));Salida esperada
Una lista de cadenas de consulta reales: preguntas de PAA ("What is a SERP API used for?"), busquedas relacionadas ("free serp api", "google serp api python") y los 10 titulos mejor posicionados, todo extraido en vivo de Google en lugar de predicho por el modelo.