O build passa, os testes passam, o site abre normal. Mesmo assim, o deploy tirou o site do Google. Isso acontece quando o robots.txt do staging é movido para produção ou uma variável de ambiente liga o noindex em todas as páginas. O Google só vê a falha na próxima rastreia, causando uma queda de tráfego e confirmada no Search Console.

Como Montar um Check de SEO no GitHub Pull Request

1. Uma Action que Lê o Diff

O primeiro método é uma Action que lê o diff do PR. Ela não depende de preview e verifica se há novos bloqueios de indexação no robots.txt ou em variáveis de ambiente. Se encontrar um noindex, ela falha.

Código da Action

```yaml
name: SEO no PR
on: pull_request
jobs:
seo:
runs-on: ubuntu-latest
steps:

  • uses: actions/checkout@v4

with:
fetch-depth: 0

  • name: Bloqueios novos de indexação

run: |
base=origin/${{ github.base_ref }}
arquivos='robots.txt public/robots.txt app/robots.ts app/layout.tsx next.config.js vercel.json _headers netlify.toml'
novas=$(git diff "$base"."HEAD" -- $arquivos | grep '^+' | grep -v '^+++' || true)
if echo "$novas" | grep -Eiq 'noindex|index: false'; then echo '::error::noindex novo neste PR'; exit 1 fi
if echo "$novas" | grep -Eiq 'disallow:
/ *$'; then echo '::error::robots.txt passa a bloquear o site inteiro'; exit 1 fi
```

2. Lighthouse CI no Preview

O segundo método usa o Lighthouse CI no preview. Se a Vercel ou a Netlify geram um preview por PR, o Lighthouse CI com a auditoria is-crawlable como erro detecta a página bloqueada pela meta tag, pelo cabeçalho ou pelo robots.txt. A pegadinha é que a Vercel e a Netlify mandam X-Robots-Tag: noindex em todo preview, de propósito. Sem tratar isso, o check fica vermelho em todo PR e o time desliga em uma semana.

Como Funciona

```yaml
name: Lighthouse CI
on: pull_request
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:

  • uses: actions/checkout@v4

with:
fetch-depth: 0

  • name: Executa o Lighthouse

run:./node_modules/.bin/lighthouse. --output=none --reporters=html

  • name: Verifica o X-Robots-Tag

run: |
xrobots=$(curl -s -I https://${{ github.event.pull_request.head.head }} | grep X-Robots-Tag)
if [ -n "$xrobots" ] && [ "$xrobots" == "X-Robots-Tag:noindex" ]; then echo '::error::X-Robots-Tag: noindex'; fi
```

3. Comparar o Preview com a Produção

O terceiro método é comparar o PR com o que já está no ar. Ignora o noindex do cabeçalho que todo preview tem e travar só o que mudou de verdade. Se o noindex está dentro de um if (VERCEL_ENV!== "production"), ele não travará.

Como Funciona

```yaml
name: Comparar Preview com Produção
on: pull_request
jobs:
compare-preview:
runs-on: ubuntu-latest
steps:

  • uses: actions/checkout@v4

with:
fetch-depth: 0

  • name: Executa o Lighthouse no Preview

run:./node_modules/.bin/lighthouse. --output=none --reporters=html

  • name: Executa o Lighthouse na Produção

run:./node_modules/.bin/lighthouse. --output=none --reporters=html

  • name: Compara os resultados

run: |
xrobots-preview=$(curl -s -I https://${{ github.event.pull_request.head.head }} | grep X-Robots-Tag)
xrobots-production=$(curl -s -I https://${{ github.event.pull_request.base.head }} | grep X-Robots-Tag)
if [ -n "$xrobots-preview" ] && [ "$xrobots-preview" == "X-Robots-Tag:noindex" ] && [ -n "$xrobots-production" ] && [ "$xrobots-production"!= "X-Robots-Tag:noindex" ]; then echo '::error::X-Robots-Tag: noindex no preview'; fi
```

Regras de Branch no GitHub

Para o check travar o merge, ele precisa ser obrigatório numa regra de branch. Isso funciona em repositório público em qualquer plano, mas em repositório privado só com GitHub Pro, Team ou Enterprise. No Free com repo privado, o check aparece e avisa, mas não impede o merge.

Como Configurar

```yaml
name: Requisitos de Branch
on: pull_request
jobs:
check-seo:
runs-on: ubuntu-latest
if: github.event.action == 'opened' || github.event.action == 'synchronize'
needs: [compare-preview]
steps:

  • uses: actions/checkout@v4

with:
fetch-depth: 0

  • name: Executa o Lighthouse no Preview

run:./node_modules/.bin/lighthouse. --output=none --reporters=html

  • name: Executa o Lighthouse na Produção

run:./node_modules/.bin/lighthouse. --output=none --reporters=html

  • name: Compara os resultados

run: |
xrobots-preview=$(curl -s -I https://${{ github.event.pull_request.head.head }} | grep X-Robots-Tag)
xrobots-production=$(curl -s -I https://${{ github.event.pull_request.base.head }} | grep X-Robots-Tag)
if [ -n "$xrobots-preview" ] && [ "$xrobots-preview" == "X-Robots-Tag:noindex" ] && [ -n "$xrobots-production" ] && [ "$xrobots-production"!= "X-Robots-Tag:noindex" ]; then echo '::error::X-Robots-Tag: noindex no preview'; fi
```

Comparação entre as Opções

A tabela abaixo compara as três opções:

| Método | Detalhes |
| --- | --- |
| 1. Uma Action que Lê o Diff | Verifica novos bloqueios de indexação no robots.txt ou variáveis de ambiente. Falha se encontrar noindex. |
| **2. Lighthouse CI no Preview | Verifica o X-Robots-Tag em ambos o preview e produção. Ignora noindex dentro de if (VERCEL_ENV!== "production"). |
| **3. Comparar o Preview com a Produção | Ignora noindex do cabeçalho e trava só o que mudou de verdade. Ignora noindex dentro de if (VERCEL_ENV!== "production"). |

Conclusão

O método mais completo é o 3, que ignora o noindex do cabeçalho e trava só o que mudou de verdade. O método 1 é simples e eficiente, mas pode deixar o noindex em variáveis de ambiente. O método 2 é rápido, mas pode gerar alarmes falso.

Um Caso Real

No nosso caso, um PR do nosso próprio site inseriu um noindex no feed do blog (/blog/rss.xml) pelo arquivo _headers da Cloudflare. O nosso check travou o PR mesmo assim, porque viu um noindex novo no _headers e não olhou pra qual caminho ele valia. A correção foi fazer cada linha nova do _headers levar junto o caminho do bloco em que cai, e ignorar o noindex quando o caminho é feed ou arquivo de dados (.xml.json.txt). Arquivo de teste e lockfile também ficaram de fora. Sem isso, o check vira inimigo do time.

Referências

  • [Check de SEO no Pull Request](https://varrida.com/blog/check-de-seo-no-pull-request?utm_source=tabnews&utm_medium=post&utm_campaign=check-seo-pr)
  • [Auditoria Grátis no GitHub
Check Github Montar Pull Request