Resumen
Las victorias de posicionamiento más rápidas son las keywords por las que Google ya muestra tus páginas en la página 3 o 4, porque la coincidencia de intención está demostrada y solo necesitas cerrar una brecha, no ganarte la relevancia desde cero. Google Search Console te dice para qué consultas recibes impresiones en la posición 11-40; esas son las keywords a tiro de piedra (striking distance). La mitad que falta, y que el hilo de r/DoSEO no dejaba de preguntar, es qué hacer después: añadir la keyword como un H2 casi nunca la mueve. Este flujo saca la lista a tiro de piedra de GSC y luego usa una API de SERP para ver exactamente quién ocupa la página 1 de cada consulta y qué cubren sus páginas, de modo que la actualización que hagas se base en la competencia real y no en una suposición. Ejecútalo cada dos semanas y trabaja la lista de arriba abajo por impresiones.
Desencadenador
Programado: cada 2 semanas, o después de cualquier actualización de contenido relevante
Programación
Quincenal (cron: 0 9 */14 * *)
Pasos del flujo de trabajo
Saca de GSC las consultas a tiro de piedra
Consulta la API de Search Console para los últimos 28 días, dimensión = query, y quédate con las filas cuya posición media esté entre 11 y 40 y con impresiones que importen (digamos 50+). Son keywords para las que Google ya te considera relevante. Ordena por impresiones de forma descendente; la cima de esa lista es donde un salto de página 3 a página 1 gana más clics.
Mira quién domina la página 1 de cada consulta
Para cada consulta a tiro de piedra, llama al endpoint de Google de Scavio con light_request: false. Obtienes los primeros resultados orgánicos más people-also-ask y related searches. Los bloques de PAA y related searches son el mapa de la brecha: muestran los subtemas que satisfacen los resultados de la página 1 y que tu página probablemente no. Este es el paso que convierte 'mete la keyword en algún sitio' en 'cubre estas tres subpreguntas que los ganadores responden y tú no.'
Compara tu página con la cobertura de la página 1
Contrasta los subtemas que aparecen en PAA/related searches y los títulos de los resultados de la página 1 con tu página actual. Marca los conceptos que te faltan. Si tres de los cinco primeros resultados responden 'X frente a Y' y tu página nunca menciona Y, esa es una sección concreta que añadir, no una keyword que espolvorear.
Actualiza la página buscando cobertura, no densidad
Reescribe para responder de verdad las subpreguntas que faltan con sustancia real: una comparativa, un ejemplo de código, una regla de decisión. Atiborrar de keywords un H2 es lo que el hilo dijo con razón que no funciona. La profundidad en las subintenciones es lo que mueve una página en posición 15 hacia arriba. Mantén una página por intención para no canibalizarte entre URLs casi duplicadas.
Vuelve a medir en el siguiente ciclo
Dos semanas después, vuelve a extraer GSC y comprueba si las consultas actualizadas subieron y empezaron a convertir impresiones en clics. Conserva las que se movieron, vuelve a comparar las que se estancaron (normalmente una brecha más profunda o un competidor más fuerte) y añade a la lista las nuevas consultas a tiro de piedra que hayan aparecido.
Implementacion en Python
import os, requests
SCAVIO = {"Authorization": f"Bearer {os.environ['SCAVIO_API_KEY']}",
"Content-Type": "application/json"}
def striking_distance(gsc_rows):
"""gsc_rows: list of {'query','position','impressions'} from the
Search Console API. Keep position 11-40 with 50+ impressions."""
rows = [r for r in gsc_rows
if 11 <= r["position"] <= 40 and r["impressions"] >= 50]
return sorted(rows, key=lambda r: -r["impressions"])
def page1_gap(query):
r = requests.post("https://api.scavio.dev/api/v1/google", headers=SCAVIO,
json={"query": query, "light_request": False}, timeout=30).json()
return {
"query": query,
"page1": [o["title"] for o in r.get("organic", [])[:5]],
"also_asked": [q.get("question") for q in r.get("people_also_ask", [])],
"related": r.get("related_searches", []),
}
def build_worklist(gsc_rows):
return [page1_gap(row["query"]) for row in striking_distance(gsc_rows)[:25]]
if __name__ == "__main__":
demo = [{"query": "serp api for agents", "position": 17, "impressions": 420}]
for item in build_worklist(demo):
print(item)Implementacion en JavaScript
const SCAVIO = { Authorization: `Bearer ${process.env.SCAVIO_API_KEY}`,
"Content-Type": "application/json" };
function strikingDistance(rows) {
return rows
.filter((r) => r.position >= 11 && r.position <= 40 && r.impressions >= 50)
.sort((a, b) => b.impressions - a.impressions);
}
async function page1Gap(query) {
const r = await fetch("https://api.scavio.dev/api/v1/google", {
method: "POST", headers: SCAVIO,
body: JSON.stringify({ query, light_request: false }),
}).then((r) => r.json());
return {
query,
page1: (r.organic || []).slice(0, 5).map((o) => o.title),
alsoAsked: (r.people_also_ask || []).map((q) => q.question),
related: r.related_searches || [],
};
}
async function buildWorklist(gscRows) {
const list = strikingDistance(gscRows).slice(0, 25);
return Promise.all(list.map((row) => page1Gap(row.query)));
}Plataformas utilizadas
Búsqueda web con grafo de conocimiento, PAA y resúmenes de IA