Coloque una auditoría SEO en su canal de despliegue: API, códigos de salida y recetas CI
Una receta funcional para auditar su sitio desde CI: tres puntos finales REST, los campos de puntuación que una puerta de construcción puede leer y la diferencia entre una regresión real y un blip de infraestructura.
Las regresiones técnicas que cuestan más visibilidad son invisibles en una revisión de código. Una etiqueta canonical que comienza a apuntar al host incorrecto, un bloque hreflang que pierde su autorreferencia, un encabezado Content-Security-Policy eliminado de una configuración de reverse-proxy, una ruta que mueve su contenido detrás de la hidratación — cada uno de esos se envía en un diff que parece correcto y pasa todas las pruebas que tiene. Aparecen semanas después, en un gráfico de tráfico, mucho después del commit que los causó, desplazándose fuera de la vista. La solución es estructural: ejecute la auditoría en el despliegue, no el día que alguien lo recuerda. Cada informe SEOReport está disponible sobre REST, la respuesta lleva un bloque de puntuación numérica, y un script shell puede convertir ese bloque en un código de salida. Ese es todo el mecanismo.
Cuatro clases de regresión que solo una máquina detecta a tiempo
Las comprobaciones de nuestro motor se alinean limpiamente con los modos de falla que sobreviven a la revisión humana, y vale la pena nombrarlos concretamente, porque son lo que una puerta realmente protege.
Hreflang. El conjunto de comprobaciones cubre autorreferencia, enlaces de retorno, x-default corrección, URLs bien formadas, si cada objetivo alternativo es indexable y si el canonical del objetivo coincide. Una migración CMS que reescribe URL patrones puede romper enlaces de retorno en todos los locales a la vez, y ningún locale parece roto en aislamiento.
Canonicalización. Presencia, indexabilidad del objetivo, objetivos sin redirección y canonicals fuera del sitio. La peor versión de esta falla es un canonical de staging enviado a producción — una página que silenciosamente nombra un host que no desea que sea indexado.
Encabezados de seguridad. Content-Security-Policy, HSTS, Referrer-Policy, X-Frame-Options, X-Content-Type-Options y Permissions-Policy. Estos viven en la configuración de infraestructura, no en el código de la aplicación, lo que explica exactamente por qué desaparecen durante un cambio de proxy o configuración de edge y nadie se da cuenta.
Paridad de render. Cada auditoría recupera la página de inicio dos veces — plain HTTP, luego un navegador real — y compara título, H1s, canonical, meta descripción, JSON-LD y volumen de texto del cuerpo entre los dos. Cuando nuestros datos render-parity data publicados llegaron a un veredicto, la mayoría de los sitios servían una página materialmente más delgada a todo lo que lee HTML como entregado. Un ssr: false en un archivo de configuración basta para mover un sitio a ese grupo.
Los cuatro son deterministas, los cuatro son baratos de comprobar y los cuatro son el tipo de cosa que una persona solo inspecciona cuando ya está sospechosa.
Tres puntos finales y un bucle
La superficie API que necesita un canal es pequeña. La autenticación es un token bearer: cree una cuenta, emita una clave desde el dashboard, y envíela como Authorization: Bearer sr__live_your_api_key. La misma clave abre REST y MCP; la referencia completa vive en la página de desarrolladores.
Enviar un informe es un POST:
JOB_ID=$(curl -sS -X POST https://seoreport.dev/api/v1/reports \-H "Authorization: Bearer $SEOREPORT_API_KEY" \-H "Content-Type: application/json" \-d '{"url": "https://example.com", "forceRerun": true}' \| jq -r '.report.jobId')
Dos cosas sobre ese cuerpo importan en CI específicamente.
forceRerun existe porque el API reutiliza una instantánea existente cuando hay una disponible — sensato para una persona que hace clic en un botón, incorrecto para una puerta de despliegue, que de otro modo calificaría la versión anterior. La respuesta te indica qué ocurrió en submission.reusedSnapshot. Las ejecuciones frescas forzadas son una capacidad de cuenta paga; una clave sin ese derecho recibe un 403 que nombra la razón en lugar de devolver silenciosamente datos obsoletos.
El alcance de auditoría se infiere del camino URL. Un origen simple ejecuta una auditoría de sitio completo; un URL con una ruta audita esa página en aislamiento. Así, un pipeline puede bloquear la página de inicio en cada despliegue y añadir la ruta específica que tocó un cambio, sin ningún parámetro extra.
Luego poll. GET /api/v1/reports/:id/ready es el punto final de estado barato — devuelve ready, status, stage, pollAfterMs, y, cuando una ejecución falla, un objeto error:
for _ in $(seq 1 60); doREADY=$(curl -sS -H "Authorization: Bearer $SEOREPORT_API_KEY" \"https://seoreport.dev/api/v1/reports/$JOB_ID/ready")CODE=$(echo "$READY" | jq -r '.error.code // empty')if [ -n "$CODE" ]; thenecho "audit did not complete: $CODE"exit 75fi[ "$(echo "$READY" | jq -r '.ready')" = "true" ] && breaksleep 5done
Ese exit 75 es deliberado, y es la parte que la mayoría de las integraciones confunden.
Distinguir una regresión de una ejecución que nunca ocurrió
error.code lleva una razón legible por máquina y un retryable booleano. DNS_FAILURE, CRAWLER_BLOCKED, REDIRECT_LOOP, TLS_ERROR, NO_CONTENT y STALE_ENGINE_VERSION están marcados como no reintentos, porque reintentar produce la misma respuesta. La mayor parte de esa lista describe una condición en el sitio, y varias entradas —un bucle de redirección, un error TLS, una regla de bot que ahora bloquea rastreadores— son defectos de despliegue genuinos que merecen fallar una compilación. Los códigos fuera de ese conjunto son transitorios y merecen otro intento.
Una puerta que combina “el sitio regresó” y “la auditoría no pudo ejecutarse” en la misma compilación roja se desactiva dentro de un mes. Sepáralos en tus códigos de salida: 1 para un veredicto que pediste que la puerta impusiera, 75 — el convencional EX_TEMPFAIL — para una ejecución que no produjo ningún veredicto. La mayoría de los sistemas CI pueden configurarse para reintentar el segundo y avisar a un humano el primero.
Leyendo el bloque de puntuación
Una vez que ready es verdadero, GET /api/v1/reports/:id devuelve el objeto de informe. El bloque score es la parte que lee una puerta:
REPORT=$(curl -sS -H "Authorization: Bearer $SEOREPORT_API_KEY" \"https://seoreport.dev/api/v1/reports/$JOB_ID")echo "$REPORT" | jq '.report.score| {overall, totalChecks, passedChecks, failedChecks,warnChecks, inconclusiveChecks, failingCriticalChecks}'
Tres de esos campos llevan la mayor parte de la señal.
failingCriticalChecks es la cuenta de fallos que el motor clasifica como críticos — los que pueden eliminar páginas de un índice o ocultar contenido a un rastreador por completo. Para una primera puerta, este es el único número que necesitas, y > 0 es un umbral defensible en el primer día.
overall es la puntuación compuesta, útil como una rampa: almacena el valor del despliegue anterior y falla cuando el nuevo cae por más de una tolerancia que elijas. Esto captura la erosión lenta que ninguna verificación individual señala.
domainScores desglosa la puntuación por seo, ai, performance, security y brand, cada uno con su propio pass, fail y warn contadores. Los pisos por dominio permiten que equipos diferentes tengan presupuestos distintos — la puntuación de seguridad es una puerta significativa para quien controla la configuración de borde, independiente de lo que el equipo de contenido envíe.
inconclusiveChecks merece su propia regla: nunca la uses como puerta. Una verificación informa inconcluso cuando el motor no pudo alcanzar un veredicto defensible, y tratar eso como fallo entrena a todos a ignorar la puerta.
El bloque de puntuación proviene de la sección hero libre del informe, así que una puerta de compilación lo lee sin desbloquear los hallazgos completos. Cuando quieres la carga completa para archivo, GET /api/v1/reports/:id/result devuelve los resultados completos de un informe desbloqueado, y GET /api/v1/reports/:id/download?format=json devuelve el mismo objeto como un artefacto descargable — vale la pena adjuntarlo a la compilación para que la diferencia entre dos despliegues sea inspeccionable después.
Conectándolo a un flujo de trabajo
Nada de lo anterior es específico del proveedor CI. En GitHub Actions la puerta completa es un solo paso que llama al script que ya tienes:
- name: SEO audit gateenv:SEOREPORT_API_KEY: ${{ secrets.SEOREPORT_API_KEY }}AUDIT_URL: https://example.comrun: ./scripts/seo-gate.sh
Donde seo-gate.sh envía, vota y termina con la decisión:
CRITICAL=$(echo "$REPORT" | jq -r '.report.score.failingCriticalChecks // 0')SECURITY=$(echo "$REPORT" | jq -r \'.report.score.domainScores[] | select(.domain == "security") | .score')if [ "$CRITICAL" -gt 0 ]; thenecho "::error::$CRITICAL critical checks failing"exit 1fiecho "clean — security domain at $SECURITY"
Ejecútalo después de que termine el despliegue en lugar de contra un entorno de vista previa. Una vista previa URL suele estar detrás de autenticación básica o un desafío de bot, y una auditoría que no puede obtener la página informa CRAWLER_BLOCKED en lugar de una puntuación. Despliegue posterior contra el origen real es más sencillo y más cercano a lo que experimenta un rastreador.
Dos formas adyacentes valen la pena conocer. Si tu orquestación ya vive en una plataforma de scraping, nuestro actor Apify ejecuta el mismo motor en un horario sin ninguna de esta pegamento. Y para los agentes, la misma clave portadora autentica una conexión MCP en https://seoreport.dev/mcp, donde las herramientas de informe se anuncian en connect — un agente investigando una caída de tráfico puede ejecutar la auditoría y leer los hallazgos él mismo, lo cual está documentado junto con la superficie REST en la página de desarrolladores.
Lo que la puerta no cubre
Una puerta de despliegue responde a una pregunta: ¿introdujo esta versión una regresión. Está silenciosa sobre todo lo que cambia sin un despliegue — un certificado que expira, una configuración CDN editada en un panel, un script de terceros que comienza a bloquear la renderización, la migración de un competidor que cambia con qué colisiona tu canónico. El monitoreo por dominio es el complemento siempre activo a la puerta, y lee desde la misma cuenta y la misma clave descrita en la página de desarrolladores.
Comienza con la versión estrecha. Un endpoint, un campo, failingCriticalChecks > 0, y un honesto exit 75 cuando la auditoría no pudo ejecutarse en absoluto. Una puerta que dispara dos veces al año y es confiable ambas veces vale más que una completa que todos aprendieron a omitir.
Ver cómo se clasifica tu sitio
Get a free IA-powered SEO report with actionable findings and priority fixes for your website.
Sin registro obligatorio.