Back to articles

Coloque uma Auditoria SEO no Seu Pipeline de Deploy: API, Códigos de Saída e Receitas CI

SEOReport Team·
apici-cdautomationgithub-actionstechnical-seodevops

Uma receita funcional para auditar seu site a partir do CI: três endpoints REST, os campos de pontuação que um gate de build pode ler, e a diferença entre uma regressão real e um pequeno deslize de infraestrutura.

As regressões técnicas que custam mais visibilidade são invisíveis em uma revisão de código. Uma tag canonical que começa a apontar para o host errado, um bloco hreflang que perde sua auto-referência, um cabeçalho Content-Security-Policy removido de uma configuração de reverse-proxy, uma rota que move seu conteúdo para trás da hidratação — cada um desses embarca em um diff que parece bom e passa todos os testes que você tem. Eles surgem semanas depois, em um gráfico de tráfego, muito depois do commit que os causou ter sido rolado fora da vista. A correção é estrutural: execute a auditoria no deploy, não no dia em que alguém lembra de. Cada relatório SEOReport está disponível sobre REST, a resposta carrega um bloco de pontuação numérica, e um script shell pode transformar esse bloco em um código de saída. Esse é o mecanismo completo.

Quatro classes de regressão que apenas uma máquina detecta a tempo

As verificações do nosso motor mapeiam claramente para os modos de falha que sobrevivem à revisão humana, e vale a pena nomeá-las concretamente, porque são o que um gate realmente protege. Hreflang. O conjunto de verificações cobre auto-referência, links de retorno, x-default correção, URLs bem formadas, se cada alvo alternativo é indexável, e se o canonical do alvo concorda. Uma migração CMS que reescreve URL padrões pode quebrar links de retorno em todos os locais de uma vez, e nenhum local parece quebrado isoladamente. Canonicalização. Presença, indexabilidade do alvo, alvos sem redirecionamento, e canonicals off-site. A pior versão dessa falha é um canonical de staging enviado para produção — uma página que silenciosamente nomeia um host que você não quer indexar. Cabeçalhos de Segurança. Content-Security-Policy, HSTS, Referrer-Policy, X-Frame-Options, X-Content-Type-Options, e Permissions-Policy. Eles vivem na configuração de infraestrutura, não no código da aplicação, o que é exatamente por isso que desaparecem durante uma mudança de proxy ou edge-config e ninguém percebe. Render parity. Cada auditoria busca a página inicial duas vezes — plain HTTP, então um navegador real — e compara título, H1s, canonical, meta descrição, JSON-LD, e volume de texto do corpo entre os dois. Quando nossos dados render-parity data publicados chegaram a um veredicto, a maioria dos sites estava servindo uma página materialmente mais fina para qualquer coisa que lê HTML como entregue. Um ssr: false em um arquivo de configuração basta para mover um site para esse grupo. Todos os quatro são determinísticos, todos os quatro são baratos de verificar, e todos os quatro são o tipo de coisa que uma pessoa só inspeciona quando já está suspeita.

Três endpoints e um loop

A superfície API que um pipeline precisa é pequena. Autenticação é um token bearer: crie uma conta, emita uma chave do dashboard, e envie-a como Authorization: Bearer sr__live_your_api_key. A mesma chave abre REST e MCP; a referência completa está na página dos desenvolvedores.

graph TD A[Implantação concluída] --> B["POST /api/v1/reports"] B --> C["GET /api/v1/reports/:id/ready"] C -->|"ready: false"| C C -->|"error.code present"| D[Sinal de infraestrutura, sair 75] C -->|"ready: true"| E["GET /api/v1/reports/:id"] E --> F{Bloco de pontuação dentro do orçamento?} F -->|Sim| G[sair 0] F -->|Não| H[sair 1, compilação falha]

Enviar um relatório é um POST:

bash
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')

Duas coisas sobre esse corpo importam no CI especificamente. forceRerun existe porque o API reutiliza um snapshot existente quando há um disponível — sensato para uma pessoa clicando em um botão, errado para uma porta de implantação, que de outra forma avaliaria a versão anterior. A resposta indica o que aconteceu em submission.reusedSnapshot. Execuções frescas forçadas são uma capacidade de conta paga; uma chave sem essa autorização recebe um 403 nomeando a razão em vez de retornar silenciosamente dados obsoletos. O escopo da auditoria é inferido a partir do caminho URL. Uma origem simples executa uma auditoria de site completo; um URL com um caminho audita essa página isoladamente. Assim, um pipeline pode bloquear a página inicial em cada implantação e adicionar a rota específica que a alteração tocou, sem nenhum parâmetro extra. Então faça polling. GET /api/v1/reports/:id/ready é o endpoint de status barato — ele retorna ready, status, stage, pollAfterMs, e, quando uma execução falha, um objeto error:

bash
for _ in $(seq 1 60); do
READY=$(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" ]; then
echo "audit did not complete: $CODE"
exit 75
fi
[ "$(echo "$READY" | jq -r '.ready')" = "true" ] && break
sleep 5
done

Esse exit 75 é deliberado, e é a parte que a maioria das integrações erra.

Diferencie uma regressão de uma execução que nunca aconteceu

error.code carrega um motivo legível por máquina e um booleano retryable. DNS_FAILURE, CRAWLER_BLOCKED, REDIRECT_LOOP, TLS_ERROR, NO_CONTENT e STALE_ENGINE_VERSION são marcados como não-repetíveis, porque repetir gera a mesma resposta. A maior parte dessa lista descreve uma condição no site, e várias entradas — um loop de redirecionamento, um erro TLS, uma regra de bot que agora bloqueia crawlers — são defeitos de implantação genuínos que valem a pena falhar a build. Códigos fora desse conjunto são transitórios e valem outra tentativa. Um gate que funde “o site regressou” e “a auditoria não pôde ser executada” em um mesmo build vermelho é desativado dentro de um mês. Mantenha-os separados nos códigos de saída: 1 para um veredicto que você pediu ao gate que faça cumprir, 75 — o convencional EX_TEMPFAIL — para uma execução que não produziu nenhum veredicto. A maioria dos sistemas CI pode ser configurada para repetir a segunda execução e chamar um humano para a primeira.

Lendo o bloco de pontuação

Assim que ready for verdadeiro, GET /api/v1/reports/:id retorna o objeto de relatório. O bloco score é a parte que o gate lê:

bash
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}'

Três desses campos carregam a maior parte do sinal. failingCriticalChecks é a contagem de falhas que o motor classifica como críticas — as que podem remover páginas de um índice ou ocultar conteúdo de um crawler completamente. Para um gate inicial, este é o único número que você precisa, e > 0 é um limite defensável no primeiro dia. overall é a pontuação composta, útil como um ratchet: armazene o valor da implantação anterior e falhe quando o novo cair mais do que uma tolerância que você escolher. Isso captura a erosão lenta que nenhuma verificação única sinaliza. domainScores divide a pontuação por seo, ai, performance, security e brand, cada um com seu próprio pass, fail e warn contagens. Paredes por domínio permitem que equipes diferentes tenham orçamentos diferentes — a pontuação de segurança é um gate significativo para quem controla a configuração de borda, independentemente de qualquer coisa que a equipe de conteúdo envie. inconclusiveChecks merece sua própria regra: nunca faça gate sobre ele. Uma verificação relata inconclusivo quando o motor não pode chegar a um veredicto defensável, e tratar isso como falha treina todos a ignorar o gate. O bloco de pontuação vem da seção hero livre do relatório, então um gate de build o lê sem desbloquear todos os achados. Quando você quer o payload completo para arquivamento, GET /api/v1/reports/:id/result retorna os resultados completos de um relatório desbloqueado, e GET /api/v1/reports/:id/download?format=json retorna o mesmo objeto como um artefato baixável — vale a pena anexar ao build para que a diferença entre duas implantações seja inspecionável depois.

Conectando ao fluxo de trabalho

Nada acima é específico do fornecedor CI. Em GitHub Actions o gate inteiro é um passo chamando o script que você já tem:

yaml
- name: SEO audit gate
env:
SEOREPORT_API_KEY: ${{ secrets.SEOREPORT_API_KEY }}
AUDIT_URL: https://example.com
run: ./scripts/seo-gate.sh

Onde seo-gate.sh submete, vota e termina com a decisão:

bash
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 ]; then
echo "::error::$CRITICAL critical checks failing"
exit 1
fi
echo "clean — security domain at $SECURITY"

Execute-o depois que a implantação terminar em vez de contra um ambiente de pré-visualização. Um pré-visualização URL costuma estar atrás de autenticação básica ou de um desafio de bot, e uma auditoria que não consegue buscar a página relata CRAWLER_BLOCKED em vez de uma pontuação. Pós-implantação contra a origem real é mais simples e mais próximo do que um rastreador experimenta. Dois formatos adjacentes valem a pena conhecer. Se sua orquestração já vive em uma plataforma de raspagem, nosso ator Apify executa o mesmo motor em um cronograma sem nenhuma dessas ligações. E para agentes, a mesma chave bearer autentica uma conexão MCP em https://seoreport.dev/mcp, onde as ferramentas de relatório são anunciadas no connect — um agente investigando uma queda de tráfego pode executar a auditoria e ler as descobertas sozinho, o que está documentado ao lado da superfície REST na página de desenvolvedores.

O que o portão não cobre

Um portão de implantação responde a uma pergunta: esta liberação introduziu uma regressão. Ele permanece silencioso sobre tudo que muda sem uma implantação — um certificado expirando, uma configuração CDN editada em um painel, um script de terceiros que começa a bloquear a renderização, a migração de um concorrente que muda com o que seu canônico colide. O monitoramento por domínio é o complemento sempre ativo ao portão, e lê da mesma conta e da mesma chave descrita na página de desenvolvedores. Comece com a versão estreita. Um endpoint, um campo, failingCriticalChecks > 0, e um honesto exit 75 quando a auditoria não pôde ser executada de forma alguma. Um portão que dispara duas vezes por ano e é confiável ambas as vezes vale mais do que um abrangente que todos aprenderam a pular.

Veja como seu site está classificado

Get a free IA-powered SEO report with actionable findings and priority fixes for your website.

Não é necessário cadastro.