SEO para JavaScript: como o Google indexa SPAs e sites em React

A fila de renderização em duas ondas do Google, as armadilhas do CSR, a diferença entre SSR, SSG e ISR e métodos práticos para verificar se o seu site em JavaScript está indexado corretamente.

Como o Google renderiza JavaScript: como funciona

Em uma página HTML comum, o Google dá um passo: baixa o HTML e vê o conteúdo na hora. Em uma página com JavaScript são três passos: baixar o HTML → carregar o bundle JS → executar o código em um Chromium headless para obter o DOM final.

O Google usa o próprio motor de navegador, baseado no Chromium e mantido sempre atualizado. Por isso o JavaScript moderno (ES2020+, import dinâmico, WebAssembly) é entendido pelo Googlebot. O problema não é o suporte à sintaxe, e sim o atraso na renderização e as limitações de recursos durante o rastreamento.

Três estratégias de renderização de JavaScript: SSR e SSG/ISR entregam HTML pronto, enquanto o CSR monta o DOM no navegador e cai na segunda onda de indexação.

Renderização em números

3–4 s

Tempo limite de renderização

Se o JS não for executado em cerca de 3–4 segundos, o Google indexa uma página parcialmente renderizada

≈ 150 ms

Tempo de CSS

Recursos que demoram mais de 150 ms para carregar podem bloquear a renderização e prejudicar a eficiência do rastreamento

2 ondas

Indexação

O conteúdo em JS chega ao índice com atraso em relação ao conteúdo em HTML — às vezes dias, às vezes semanas

100%

Evergreen do Google

O Googlebot é atualizado para a versão estável mais recente do Chromium — os recursos modernos de JS são totalmente suportados

Indexação em duas ondas: por que o conteúdo em JS chega ao índice depois

O Google divide o processo em duas etapas. A primeira onda é o rastreamento: o Googlebot baixa o HTML e todos os links encontrados. A segunda onda é a renderização: o bot coloca as páginas na fila de renderização, executa o JS e indexa o DOM final.

Entre uma onda e outra podem se passar de horas a semanas, dependendo da autoridade do site, do orçamento de rastreamento e do tamanho da fila de renderização do Google. Se os textos principais, os H1, as meta tags ou os links forem gerados só por JS, eles vão chegar ao índice com atraso.

Conclusão prática: todo conteúdo crítico para SEO (title, meta description, H1, links e dados estruturados) precisa estar na resposta HTML do servidor. Assim ele entra na primeira onda de indexação, sem atraso.
Duas ondas de indexação explicam por que páginas novas de SPA ‘somem’ do índice por 2–4 semanas depois da publicação, mesmo com o HTML acessível.

CSR — a principal armadilha de SEO

A renderização no cliente (CSR) acontece quando o servidor envia um <div id="root"></div> vazio e todo o HTML é montado no navegador depois que o bundle JS carrega. React, Vue e Angular no modo SPA funcionam assim por padrão.

Do ponto de vista de SEO, o CSR é um problema por vários motivos: 1) a renderização só acontece na segunda onda; 2) recursos bloqueados para o rastreador (scripts de terceiros, CDNs com bloqueio no robots.txt) não carregam, e a página fica renderizada pela metade; 3) qualquer erro de JS significa página em branco no índice.

html
<!-- CSR: what Google sees in the first wave -->
<html>
  <head>
    <title></title> <!-- empty -->
  </head>
  <body>
    <div id="root"></div> <!-- no content -->
    <script src="/bundle.js"></script>
  </body>
</html>
Erro crítico: gerar <title>, <meta name="description"> e <h1> apenas por JS no cliente. Na primeira rodada de rastreamento, o Google recebe valores vazios ou padrão e indexa a página sem eles.

SSR, SSG e ISR: qual escolher para SEO

A solução para os problemas do CSR é gerar o HTML no servidor. Há três abordagens principais, cada uma ideal para um cenário.

Três abordagens de renderização de JavaScript e seu impacto no SEO.

Comparação das abordagens de renderização

AbordagemHTML no servidorSEODados dinâmicos
CSRNãoRuimTotal
SSRSim (a cada requisição)ExcelenteAlta
SSGSim (no build)ExcelenteNão (exige rebuild)
ISRSim (por temporizador)ExcelenteVia revalidação
Abordagens de renderização e casos de uso adequados:
AbordagemIdeal para
CSRSPAs autenticadas, dashboards
SSRPáginas personalizadas, catálogos
SSGBlog, landing pages, documentação
ISRCatálogos de preços, notícias

SSR (renderização no servidor) — o HTML é gerado no servidor a cada requisição. Dá o máximo de atualização dos dados, mas aumenta a carga do servidor. No Next.js, o generateMetadata e os componentes async do App Router já oferecem SSR por padrão.

SSG (geração de sites estáticos) — o HTML é gerado uma vez, no build, e servido como arquivo estático. Tem o TTFB mais rápido e é ideal para SEO. A desvantagem é que qualquer mudança nos dados exige um novo build.

ISR (regeneração estática incremental) — um modelo híbrido: as páginas são geradas de forma estática, mas, após um período de revalidação (revalidate: 3600), o servidor as regenera em segundo plano na requisição seguinte. No Next.js, essa é a abordagem padrão para a maioria das páginas.

typescript
// Next.js App Router — SSG + ISR
export const revalidate = 3600; // revalidate every hour

export async function generateMetadata(): Promise<Metadata> {
  return {
    title: 'Product Catalogue',
    description: 'Full range with up-to-date prices',
  };
}

// All critical content is server-rendered:
export default async function CatalogPage() {
  const products = await fetchProducts(); // server fetch
  return (
    <main>
      <h1>Product Catalogue</h1>
      {products.map(p => <ProductCard key={p.id} {...p} />)}
    </main>
  );
}

Links dinâmicos e navegação

O Googlebot entende links apenas no formato <a href="/url">. Links implementados com onClick, button, data-href ou window.location são invisíveis para o rastreador. Isso significa que páginas acessíveis só por esse tipo de navegação podem não ser indexadas.

  • Use <a href> em todos os links de navegação, e não button onClick com router.push()
  • Paginação por parâmetros de URL (?page=2): o Googlebot rastreia essas URLs se elas aparecerem no HTML
  • Roteador de SPA: o <Link> do Next.js e o <Link> do React Router geram tags <a> corretas no servidor
  • Navegação por hash (#anchor) não cria URLs separadas no índice; não use para conteúdo que deva ranquear de forma independente
  • Menus dinâmicos: se os itens do menu são renderizados por uma API depois do carregamento da página, o Google pode não descobri-los antes da renderização
Verificação: no Google Search Console → Inspeção de URL → ‘Ver como o Googlebot’ mostra quais links o rastreador encontrou na página. Se um link dinâmico não aparecer na lista, o Googlebot não consegue vê-lo.

Lazy load e rolagem infinita

Imagens com loading="lazy" são carregadas pelo Googlebot: o rastreador moderno oferece suporte ao carregamento lento (lazy loading). Mas há uma condição: a imagem precisa estar no DOM com o atributo src correto durante o SSR. Se o src for definido pelo JavaScript no navegador, o rastreador verá uma tag vazia.

A rolagem infinita precisa de um caminho rastreável até cada item relevante. Ofereça URLs sequenciais e links comuns que funcionem sem que o usuário clique em um botão; depois, use a Inspeção de URL ou um rastreamento para verificar se o HTML renderizado expõe o conteúdo pretendido.

PadrãoO Googlebot vê?Recomendação
<img src="/img.webp" loading="lazy">SimUse
<img data-src="/img.webp"> (JS define o src)NãoEvite
Rolagem infinita sem URLSó a primeira telaAdicione paginação
Conteúdo atrás do botão ‘Mostrar mais’NãoMostre parte no HTML
Conteúdo em abas (abas ocultas)Sim, com atrasoDuplique no HTML

Diagnóstico: como verificar a renderização do JavaScript

A pergunta-chave do diagnóstico é: ‘O que o Googlebot vê na minha página?’ Há várias ferramentas para responder a isso.

Ferramentas de diagnóstico

  • Google Search Console → Inspeção de URL: mostra uma captura de tela da página depois da renderização pelo Googlebot, a lista de recursos e os links descobertos. É o método de verificação mais direto.
  • ‘Ver como o Googlebot’ no GSC: executa o rastreador de verdade e devolve o HTML depois da renderização. Compare com o HTML de origem.
  • curl ou wget: obtêm o HTML bruto, sem JS. Se as principais meta tags e o conteúdo estiverem na saída do curl, eles vão estar na primeira onda de indexação.
  • Desative o JS no Chrome DevTools (F12 → Ctrl+Shift+P → ‘Disable JavaScript’): uma forma rápida de ver a página como o rastreador a veria, sem renderização.
  • Screaming Frog com renderização: a configuração ‘Spider > Configuration > Rendering > Googlebot’ permite rastrear o site com renderização de JS e ver os links encontrados depois da renderização.
Exemplo de configuração do Next.js para SSR/SSG:
bash
# Check what Google sees without JS rendering:
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
  https://example.com/page

# Find all title / meta description / h1 in HTML response:
curl -s https://example.com/page | grep -E '<title>|<meta name="description"|<h1'

Checklist de SEO para JavaScript

Verificações principais

  • Title e meta description estão presentes na resposta HTML do servidor (SSR/SSG), e não são gerados por JS
  • H1, H2 e o texto principal são acessíveis sem JavaScript
  • Links de navegação usam <a href>, e não onClick / button
  • Dados estruturados (JSON-LD) estão no <head> da resposta HTML
  • Imagens têm src estático no HTML; loading="lazy" só para imagens que não são o LCP
  • O robots.txt não bloqueia os arquivos JS/CSS necessários para a renderização
  • Nenhum erro de JS quebra a renderização (verifique o Console do Chrome DevTools na página)
  • Core Web Vitals: LCP, INP e CLS atingem os valores de referência do Google
  • Paginação por parâmetros de URL, e não só pelo estado do JS
  • URLs canônicas (<link rel="[canonical](/glossary/canonical)">) no HTML, e não definidas via JS

FAQ

O Google consegue indexar JavaScript?
Sim. O Googlebot usa o Chromium Evergreen e consegue executar JS moderno. O problema não é o suporte, e sim o atraso: a renderização acontece na segunda onda, que pode vir dias ou semanas depois do rastreamento do HTML.
Um site em React/Next.js é indexado bem automaticamente?
Next.js com SSR/SSG: sim, quando configurado corretamente. Um SPA React simples (Create React App, Vite sem SSR) é CSR por padrão, o que é ruim para SEO. O fundamental é gerar no servidor as meta tags, o H1 e o conteúdo principal.
Preciso de pré-renderização ou de renderização dinâmica?
A renderização dinâmica (mostrar HTML diferente para o Googlebot e para os usuários) é uma abordagem ultrapassada. O Google a permite, mas não recomenda. O caminho certo é SSR ou SSG, que entregam o mesmo HTML completo para todos.
Posso usar React.lazy e divisão de código (code splitting)?
Sim. A divisão de código com React.lazy e import dinâmico melhora o desempenho e não prejudica o SEO, desde que o conteúdo crítico (H1, texto principal) já esteja no HTML inicial. Componentes carregados sob demanda ainda serão buscados pelo Googlebot durante a renderização.
Como verifico se o meu site está indexado corretamente?
Use o Google Search Console → Inspeção de URL. Solicite a renderização e compare a captura de tela com o que um usuário comum vê. Além disso, verifique com curl se o title, o h1 e a meta description estão no HTML da resposta, sem JS.

Check it with SpiderHead

Free and local: run the audit on your own machine.

Try it