ClasesSEO
ES EN
Optimización de motores de búsqueda SEO

API de inspección de URL de Search Console: cómo auditar la indexación en masa

8 min de lectura Read in English
Tabla de contenidos

El informe de indexación de Search Console agrupa miles de URLs y no te deja bajar al detalle. La API de inspección de URL sí: te devuelve, una por una, el canonical que eligió Google, si hay un noindex bloqueando la página y cuándo fue el último rastreo.

Es el mismo dato que ves al pegar una URL en la barra superior del panel, pero por HTTPS y en lote: deja de ser una revisión a mano y pasa a ser una consulta programada que guardas en una base de datos y comparas día a día.

Qué hace la API de inspección de URL (y qué no)

La llamada es un POST a https://searchconsole.googleapis.com/v1/urlInspection/index:inspect con dos campos obligatorios: la URL que quieres revisar y la propiedad a la que pertenece. La respuesta trae el bloque inspectionResult con el estado de indexación, el canonical, la fecha del último rastreo y los sitemaps que la referencian.

Hay un detalle que casi nadie tiene en cuenta: la API devuelve el estado de la copia que está en el índice de Google, no una prueba en vivo. La referencia oficial lo dice: no se puede probar la indexabilidad de una URL en directo. El botón "Probar URL publicada" del panel no tiene equivalente en la API.

Lo que la API no puede hacer

  • No envía nada a indexar ni pide un recrawl. Para eso está el botón manual de solicitar indexación o la Indexing API, que solo acepta JobPosting y BroadcastEvent dentro de un VideoObject.
  • No lee propiedades ajenas a la credencial: la cuenta de servicio debe estar añadida en esa propiedad.
  • No devuelve clics ni impresiones. Eso es Search Analytics, o la exportación a BigQuery si quieres cruzar los datos.

Inspección frente a API de Indexing

Es la confusión más común y la más cara: una lee estado, la otra notifica. Si montas un script contra index:inspect esperando acelerar la indexación, no va a pasar nada, porque ninguna de esas peticiones le avisa a Google de que el contenido cambió.

El valor real de la inspección es otro: es la única fuente que te dice, URL por URL y en lote, que Google eligió un canonical distinto al que declaraste.

Cuota: 2.000 inspecciones al día por propiedad

Los límites oficiales son 2.000 consultas diarias y 600 por minuto por sitio. A nivel de proyecto de Google Cloud el techo es mucho más alto (10.000.000 al día y 15.000 por minuto), así que el cuello de botella nunca es la cuenta: es la propiedad.

Y es por propiedad de verdad. Si tienes la misma web como propiedad de dominio y como prefijo de URL, cada una suma su propia cuota de 2.000. Google lo confirmó al anunciar la API en enero de 2022.

Por qué 2.000 casi nunca alcanzan (y por qué está bien)

Un sitio de 50.000 URLs necesitaría 25 días para una pasada completa. La API está pensada para muestreo y depuración, no para recorrer el sitio entero: si aceptas esa restricción desde el principio, diseñas la muestra antes de escribir el script.

Preparar el acceso en Google Cloud

Los pasos, en orden:

  1. Crear un proyecto en Google Cloud y habilitar la Google Search Console API.
  2. Crear credenciales OAuth2: cuenta de servicio para scripts programados, flujo de escritorio para pruebas locales.
  3. Pedir el scope https://www.googleapis.com/auth/webmasters.readonly.
  4. Agregar el correo de la cuenta de servicio como usuario de la propiedad en Search Console, con permiso de lectura o superior.

El paso 4 es el que se olvida: sin él la API responde error de permisos aunque el token sea válido.

siteUrl exacto: barra final y sc-domain

Este error rompe la mayoría de los primeros intentos. Una propiedad de prefijo de URL se escribe completa y con barra final: https://www.ejemplo.com/. Una propiedad de dominio se escribe sin esquema y sin barra: sc-domain:ejemplo.com. Si mezclas las dos formas, la petición falla por permisos y el mensaje no aclara que el problema es el formato.

La URL inspeccionada tiene que colgar de esa propiedad: si es de otro subdominio con la credencial de la principal, tampoco pasa.

La llamada: endpoint, body y script en Python

El body mínimo son dos campos. El tercero, languageCode, es opcional (formato BCP-47, por defecto en-US) y solo cambia el idioma de los mensajes traducidos de la respuesta.

from google.oauth2 import service_account
from googleapiclient.discovery import build
import os, time

SCOPES = ["https://www.googleapis.com/auth/webmasters.readonly"]
creds = service_account.Credentials.from_service_account_file(
    os.environ["GSC_SA_JSON"], scopes=SCOPES)
service = build("searchconsole", "v1", credentials=creds)

body = {
    "inspectionUrl": "https://ejemplo.com/blog/post-de-ejemplo/",
    "siteUrl": "sc-domain:ejemplo.com",
}
res = service.urlInspection().index().inspect(body=body).execute()
r = res["inspectionResult"]["indexStatusResult"]
print(r["verdict"], r.get("googleCanonical"), r.get("lastCrawlTime"))
time.sleep(0.1)

Dos notas de producción: guarda el JSON de la cuenta de servicio fuera del repositorio y lee la ruta desde una variable de entorno; y deja el sleep corto pero presente, porque 2.000 URLs sin pausa te acercan al límite de 600 por minuto.

Leer la respuesta campo por campo

Lo útil vive en inspectionResult.indexStatusResult. Estos son los campos que conviene guardar:

  • verdict: PASS, FAIL o NEUTRAL. PARTIAL está reservado y ya no se usa.
  • coverageState: el texto que ves en el panel.
  • robotsTxtState: ALLOWED o DISALLOWED.
  • indexingState: INDEXING_ALLOWED, BLOCKED_BY_META_TAG o BLOCKED_BY_HTTP_HEADER.
  • pageFetchState: SUCCESSFUL, SOFT_404, NOT_FOUND, ACCESS_DENIED, ACCESS_FORBIDDEN, SERVER_ERROR, REDIRECT_ERROR, BLOCKED_4XX, INTERNAL_CRAWL_ERROR, INVALID_URL o BLOCKED_ROBOTS_TXT.
  • lastCrawlTime: fecha RFC 3339, ausente si la página nunca se rastreó bien.
  • googleCanonical y userCanonical: el que eligió Google y el que declaraste tú.
  • crawledAs: MOBILE o DESKTOP.
  • sitemap y referringUrls: de dónde conoce Google la página.

mobileUsabilityResult está marcado como obsoleto. No lo conviertas en KPI de un dashboard nuevo: el dato ya no se actualiza y te va a dar falsos positivos para siempre.

coverageState es texto localizado, no un código

Si envías languageCode: "es-ES", coverageState vuelve traducido ("Rastreada, actualmente no indexada"). Un if coverageState == "..." se rompe en cuanto cambias de idioma o Google retoca la redacción. Filtra por los enums (verdict, indexingState, pageFetchState) y usa el texto solo para mostrar en pantalla.

Los cuatro diagnósticos que de verdad resuelven

Google eligió otro canonical

Cuando googleCanonical no coincide con userCanonical tienes contenido compitiendo consigo mismo: canonical contradictorio entre versiones, parámetros duplicados o dos páginas casi idénticas. Es el dato que ningún informe agregado te da por URL.

Rastreada, actualmente no indexada

Se ve como indexingState: INDEXING_ALLOWED con verdict: NEUTRAL. No es un bloqueo técnico: es un problema de calidad o de contenido fino. Se arregla con contenido, no con etiquetas.

Bloqueada por noindex

Aquí la distinción importa. BLOCKED_BY_META_TAG es el noindex que está en el HTML de la página; BLOCKED_BY_HTTP_HEADER es el que va en la cabecera del servidor y no aparece en el código fuente, que es justo donde nadie lo busca.

404, soft 404 y errores de redirección

pageFetchState separa tres cosas que en un informe agregado se ven parecidas: NOT_FOUND (404 real), SOFT_404 (responde 200 pero parece vacía) y REDIRECT_ERROR (bucle o cadena rota). Con esa separación priorizas por plantilla y no por anécdota.

Errores frecuentes y su causa real

  • 401: credenciales o scopes mal pedidos; casi siempre falta webmasters.readonly.
  • 403: la cuenta no tiene permiso sobre esa propiedad, o la URL no cuelga de ella.
  • 429: cuota superada. Backoff exponencial, no reintentos en bucle.
  • 400: body mal formado, inspectionUrl sin https:// o siteUrl con barra donde no toca.

Si richResultsResult o ampResult vuelven vacíos, no es un fallo del script: el análisis simplemente no aplica a esa página.

Cómo priorizar tus 2.000 inspecciones diarias

Un orden que funciona: plantillas nuevas y despliegues recientes; URLs con impresiones pero sin clics; páginas donde cambió el canonical o una redirección; una muestra aleatoria fija del resto para detectar regresiones; y las URLs que acabas de pedir indexar.

Guarda histórico (fecha, url, verdict, canonical) en una tabla. Sin serie temporal la API es una foto del día y no puedes responder la pregunta que importa: desde cuándo está así.

Cuándo la API es la herramienta equivocada

Para volumen, el informe de indexación del panel y el sitemap ya te dan el agregado. Para saber qué rastrea Googlebot de verdad, los logs del servidor son mejores: traen todas las peticiones y no tienen cuota. Y para avisar de un cambio usa IndexNow o la solicitud manual de indexación; la inspección no le avisa a nadie.

Si lo que necesitas es entender por qué una página no entra, cruza la respuesta con meta robots y noindex, con los errores 404 y soft 404 y con las páginas huérfanas. Y para cruzar la inspección con clics e impresiones, la exportación de Search Console a BigQuery es el camino natural.

La API de inspección de URL es, al final, una lupa por URL: responde lo que el informe agregado no responde, página por página.

Fuentes: referencia de urlInspection.index.inspect, límites de uso de la API y anuncio de la URL Inspection API (enero 2022).

Usamos cookies para mejorar tu experiencia y analizar el tráfico del sitio. Al continuar navegando aceptas su uso.

Privacidad