JavaScript SEO: CSR, SSR, SSG e renderização pelo Google
Sites construídos com frameworks JavaScript modernos convivem com um paradoxo estrutural: a mesma camada que entrega interatividade sofisticada pode esconder o conteúdo dos mecanismos de busca. A decisão entre renderizar no cliente (CSR), no servidor (SSR) ou em build time (SSG) não é uma escolha estética — é uma decisão arquitetural que impacta indexabilidade, crawl budget, performance percebida e o custo operacional da infraestrutura. Este guia consolida o modelo mental necessário para tomar essa decisão com base em critérios objetivos.
Como o Googlebot processa JavaScript: o modelo de duas ondas
O Googlebot não trata HTML e JavaScript da mesma forma. O processo acontece em duas etapas separadas no tempo, e entender essa separação é pré-requisito para diagnosticar qualquer problema de renderização.
Onda 1 — Crawl inicial O Googlebot faz uma requisição HTTP à URL e recebe o HTML bruto — exatamente o que aparece em "Exibir código-fonte" do navegador. Nessa fase, o crawler:
- Lê o HTML servido pelo servidor.
- Extrai links (
<a href>) para descobrir novas URLs. - Coleta metadados presentes no HTML inicial (title, meta description, canonical, hreflang).
- Indexa imediatamente o conteúdo que já está no HTML.
Se a página é CSR pura, o HTML retornado é essencialmente um shell vazio — algo como <div id="root"></div> com um bundle JavaScript. Nada de conteúdo, nada de links, nada de meta tags dinâmicas.
Onda 2 — Fila de renderização (Web Rendering Service) Páginas que dependem de JavaScript para montar conteúdo são adicionadas a uma fila de renderização processada pelo Web Rendering Service (WRS), baseado em Chromium. O WRS:
- Executa o JavaScript da página.
- Aguarda requisições de rede e mutações no DOM.
- Extrai o HTML final renderizado.
- Envia esse HTML de volta para o pipeline de indexação.
O intervalo entre a onda 1 e a onda 2 é variável. Pode ser rápido quando há recursos disponíveis, e pode se estender significativamente quando o WRS está sobrecarregado ou quando o site tem baixa prioridade de crawl. Durante esse intervalo, o conteúdo dependente de JS simplesmente não existe no índice.
Implicações práticas
- Links renderizados apenas via JS podem demorar para serem descobertos, atrasando a indexação de páginas internas.
- Meta tags dinâmicas (title, canonical, Open Graph) injetadas pelo cliente podem ser ignoradas se a onda 2 não executar corretamente.
- Erros de JavaScript, timeouts de API ou dependências bloqueantes durante a renderização podem resultar em conteúdo parcial ou vazio sendo indexado.
Comparação objetiva entre CSR, SSR e SSG
A tabela abaixo consolida os critérios que devem entrar na decisão arquitetural:
| Critério | CSR (Client-Side Rendering) | SSR (Server-Side Rendering) | SSG (Static Site Generation) | |---|---|---|---| | HTML na primeira resposta | Shell vazio + bundle JS | HTML completo renderizado no servidor por requisição | HTML completo pré-gerado em build | | Indexabilidade imediata | Dependente da onda 2 do WRS | Total — conteúdo disponível na onda 1 | Total — conteúdo disponível na onda 1 | | TTFB (Time to First Byte) | Baixo (arquivo estático) | Maior — precisa executar lógica e queries no servidor | Baixo (arquivo estático servido do CDN) | | FCP / LCP | Alto — precisa baixar, parsear e executar JS antes de pintar | Médio — HTML já vem pronto, mas servidor demora para responder | Baixo — HTML pronto + CDN próximo do usuário | | Crawl budget | Consome mais recursos do WRS por página | Eficiente — HTML pronto na primeira requisição | Extremamente eficiente | | Complexidade de infraestrutura | Baixa — hospedagem estática basta | Alta — requer servidor Node/edge, cache, invalidação | Média — pipeline de build + CDN | | Custo operacional | Baixo | Alto — CPU por requisição, cache warming | Baixo em runtime, custo em build | | Conteúdo dinâmico/personalizado | Natural | Natural | Requer ISR ou hidratação parcial | | Frequência de atualização suportada | Qualquer (via fetch) | Qualquer | Limitada pelo tempo de build (ou ISR) | | Casos ideais | Áreas autenticadas, dashboards internos | E-commerce grande, portais editoriais dinâmicos, personalização | Blogs, documentação, landing pages, catálogos estáveis |
Nenhuma estratégia é universalmente superior. O que importa é o alinhamento entre a natureza do conteúdo (estático, dinâmico, personalizado), a frequência de atualização e o valor de SEO daquela URL.
Diagnóstico: sintomas de problemas de indexação por renderização
Antes de decidir migrar arquitetura, é preciso confirmar que o problema é de renderização e não de outras camadas (crawl, canonical, thin content). Os sinais típicos de falha na onda 2 são:
Sintomas observáveis
- Páginas aparecem no Search Console como "Descoberta, atualmente não indexada" ou "Rastreada, atualmente não indexada" mesmo após semanas.
- Buscar
site:seudominio.com/paginano Google retorna a URL mas o snippet está vazio, genérico ou não reflete o conteúdo visível no navegador. - Consultar o cache do Google (quando disponível) mostra shell vazio ou HTML sem o conteúdo principal.
- Meta tags dinâmicas (title, description, Open Graph) definidas por JS não aparecem nos resultados de busca — o Google usa fallbacks ou nada.
- Links internos gerados por JS não são seguidos: páginas filhas ficam órfãs no índice.
- Rich results / dados estruturados injetados via JS não são reconhecidos.
Como confirmar o diagnóstico
- Comparar HTML bruto vs HTML renderizado
No terminal, use curl -A "Mozilla/5.0" https://seusite.com/pagina e inspecione o retorno. Se o conteúdo principal (títulos, texto, links) não estiver ali, você depende 100% da onda 2.
- URL Inspection no Google Search Console
Cole a URL, clique em "Testar URL ativa" e depois em "Ver página testada" → "HTML". Compare o HTML renderizado pelo WRS com o DOM que você vê no navegador. Diferenças significativas indicam problemas de renderização (erros JS, timeouts, recursos bloqueados).
- Screenshot do WRS
Ainda no URL Inspection, veja o screenshot da página renderizada pelo Google. Se estiver em branco, parcial ou com erros visíveis, o WRS não conseguiu renderizar corretamente.
- Chrome DevTools com JavaScript desabilitado
Abra DevTools → Command Palette → "Disable JavaScript" e recarregue. O que sobra é aproximadamente o que o Googlebot vê na onda 1. Se o conteúdo principal desaparece, você tem dependência crítica de JS.
- Logs do servidor filtrando por Googlebot
Filtre acessos por user-agent contendo Googlebot e verifique frequência de crawl, códigos de status e URLs acessadas. Queda no crawl ou erros 5xx recorrentes são sinais estruturais.
- Auditoria Lighthouse
Rode Lighthouse em modo mobile e analise a categoria SEO. Verifique também Performance para entender se o custo de renderização no cliente está atrasando LCP a ponto de comprometer a percepção de qualidade da página.
Seleção da estratégia por perfil do site
A escolha correta emerge de perguntas objetivas sobre o conteúdo, não de preferências técnicas. Use esta árvore de decisão:
Pergunta 1 — O conteúdo tem valor de SEO?
- Não (área autenticada, dashboard interno, ferramenta pós-login): CSR é aceitável. Priorize DX e simplicidade.
- Sim: siga para a pergunta 2.
Pergunta 2 — O conteúdo é o mesmo para todos os usuários?
- Sim, e muda com pouca frequência (blog, documentação, landing pages, páginas institucionais): SSG. Pré-gere em build, sirva do CDN, rebuild quando o conteúdo muda.
- Sim, mas muda com frequência intermediária (catálogo de produtos com preço/estoque, listagens editoriais): SSG com ISR (Incremental Static Regeneration) ou SSR com cache agressivo no CDN.
- Não, varia por usuário/geolocalização/sessão: siga para a pergunta 3.
Pergunta 3 — A personalização precisa estar no HTML inicial ou pode ser hidratada?
- No HTML inicial (preços regionais que afetam ranking, conteúdo A/B testado que precisa ser indexado): SSR com cache segmentado por variante.
- Pode ser hidratada depois (recomendações, saudação personalizada, carrinho): SSG/SSR para a estrutura base + CSR para as partes personalizadas. Essa é a abordagem de renderização híbrida.
Perfis típicos
- Blog / documentação / landing pages: SSG puro.
- E-commerce médio/grande: SSR com cache no CDN + ISR para páginas de produto, SSG para páginas institucionais.
- Portal de notícias: SSR com cache curto + ISR para arquivo.
- SaaS com marketing site + app: SSG/SSR para o marketing (indexável), CSR para a área logada.
- Marketplace com filtros complexos: SSR para páginas de listagem indexáveis + CSR para interações de filtro.
Verificação: confirmar que o Google está renderizando corretamente
Depois de implementar (ou antes de decidir mudar), verifique empiricamente:
1. URL Inspection — o teste canônico No Search Console, cole a URL, clique em "Testar URL ativa" e depois:
- HTML renderizado: compare com o DOM que você vê no navegador. O conteúdo principal precisa estar lá.
- Screenshot: deve refletir a página como usuários a veem.
- Recursos carregados: verifique se algum recurso crítico foi bloqueado por robots.txt ou falhou.
- Mensagens JavaScript no console: erros aqui indicam falhas silenciosas na renderização.
2. Teste de Rich Results Use o Rich Results Test para verificar se dados estruturados (JSON-LD, microdata) estão sendo detectados após a renderização. Se você injeta schema via JS, esse teste vai mostrar se o WRS consegue processar.
3. Comparação view-source vs DOM
Ctrl+Uno navegador mostra o HTML servido (o que o Googlebot vê na onda 1).- DevTools → Elements mostra o DOM final (o que o Googlebot vê na onda 2).
- A diferença entre os dois é exatamente o que depende de JavaScript para ser indexado.
4. Logs de servidor Filtre por user-agent contendo Googlebot, Googlebot-Image, Googlebot-Mobile. Observe:
- Frequência de crawl por seção do site.
- Códigos de status (5xx frequentes indicam problemas de SSR).
- URLs acessadas com mais frequência (sinaliza onde o Google está gastando crawl budget).
5. Métricas de performance comparadas Compare TTFB, FCP e LCP entre versões CSR/SSR/SSG do mesmo template. Se o TTFB do SSR estiver alto sem cache, o ganho de indexabilidade pode ser anulado pela lentidão. SSG e SSR com cache no CDN tendem a ter perfis de performance similares para usuários finais.
Configuração em frameworks JavaScript modernos
As diretrizes abaixo são estruturais — a API exata evolui com as versões dos frameworks; consulte a documentação vigente antes de implementar.
Next.js
- SSG (
getStaticProps): para páginas cujo conteúdo é conhecido em build time. Ideal para posts de blog, documentação, páginas institucionais.
``js export async function getStaticProps() { const data = await fetchFromCMS(); return { props: { data } }; } ``
- SSG com paths dinâmicos (
getStaticPaths): para gerar N páginas a partir de uma lista (produtos, artigos).
``js export async function getStaticPaths() { const posts = await getAllPosts(); return { paths: posts.map(p => ({ params: { slug: p.slug } })), fallback: 'blocking' }; } ` O fallback: 'blocking'` permite gerar páginas sob demanda na primeira requisição, útil quando o conjunto total é grande demais para pré-gerar tudo.
- ISR (Incremental Static Regeneration): adicione
revalidatepara regenerar páginas em background após um intervalo. Combina o melhor do SSG (velocidade, custo) com atualização automática.
``js return { props: { data }, revalidate: 3600 }; // regenera a cada 1h ``
- SSR (
getServerSideProps): para páginas que precisam de dados por requisição (personalização, dados em tempo real). Use com cache no CDN sempre que possível — SSR sem cache é a configuração mais cara e mais lenta.
``js export async function getServerSideProps({ req, res }) { res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300'); const data = await fetchData(); return { props: { data } }; } ``
- App Router (versões recentes do Next.js): as convenções mudam — Server Components são o padrão, e a decisão CSR/SSR/SSG é controlada por configurações de segmento (
dynamic,revalidate) e pela presença de"use client". Leia a documentação da versão instalada antes de aplicar padrões antigos.
Nuxt (Vue)
nuxt.configpermite escolher entressr: true(SSR),nitro.prerender(SSG) ou modo híbrido com regras por rota (routeRules).routeRulespermite definir por padrão de URL:{ '/blog/': { isr: 3600 }, '/admin/': { ssr: false } }.
Angular Universal
- Fornece SSR para Angular. Requer configuração de bootstrap dedicado no servidor e cuidado com APIs de navegador (window, document) que não existem em runtime Node.
Configuração transversal
- Cache no CDN (Vercel, Cloudflare, Fastly): para SSR, o cache em edge é o que torna a estratégia sustentável. Configure headers
Cache-Controlcoms-maxage(tempo de cache no CDN) estale-while-revalidate(servir versão antiga enquanto revalida em background). - Invalidação: SSG e ISR precisam de mecanismos de invalidação (webhooks do CMS, rebuild sob demanda, purge de CDN).
- Fallback e loading states: em SSG com fallback, projete estados de loading que não quebrem a experiência nem gerem CLS.
Remediação: sites CSR já em produção
Reescrever uma aplicação CSR inteira para SSR/SSG é um projeto grande. Existem estratégias graduais:
1. Migração progressiva por rota Migre primeiro as páginas de maior valor de SEO (home, categorias, produtos ou artigos mais buscados) para SSR/SSG, mantendo o resto em CSR. Frameworks como Next.js permitem coexistência natural. Priorize por:
- Volume de tráfego orgânico atual (ou potencial estimado por concorrentes).
- Valor de conversão da página.
- Frequência de atualização (páginas estáveis vão para SSG primeiro).
2. Dynamic rendering como paliativo Ferramentas como Rendertron, prerender.io ou soluções self-hosted detectam o user-agent Googlebot e servem uma versão pré-renderizada apenas para crawlers, enquanto usuários continuam recebendo o app CSR original.
- Vantagem: implementação rápida, não exige reescrever o app.
- Limitações: é uma camada extra de infraestrutura, precisa manter cache sincronizado, adiciona latência para o Googlebot e diverge o HTML servido para crawlers vs usuários — cenário que exige documentação e monitoramento constantes.
- Uso recomendado: solução ponte enquanto se planeja a migração arquitetural definitiva.
3. Hidratação seletiva / arquitetura de ilhas Em vez de reescrever tudo, adote uma arquitetura em que o HTML principal é renderizado no servidor (SSR/SSG) e apenas partes interativas são hidratadas no cliente. Frameworks como Astro, Qwik e as versões recentes de React (Server Components) suportam esse padrão nativamente. Reduz o custo de JS enviado ao cliente e melhora tanto SEO quanto performance.
4. Reescrita arquitetural Quando o app CSR foi construído sobre padrões incompatíveis com SSR (uso extensivo de window, localStorage em render, bibliotecas não-isomórficas), a reescrita pode ser mais previsível que a migração incremental. Considere quando:
- O time tem capacidade para o projeto sem paralisar features.
- A dívida técnica do app atual já demanda refatoração de qualquer forma.
- Métricas de SEO/performance justificam o investimento.
Ordem de execução recomendada
- Diagnosticar o problema atual (URL Inspection, logs, comparação view-source vs DOM) — confirme que é renderização, não outra causa.
- Priorizar URLs por valor de SEO.
- Escolher a estratégia por perfil (SSG, SSR, ISR, híbrida).
- Implementar em ambiente de staging e validar com URL Inspection antes de promover.
- Monitorar cobertura de indexação no Search Console nas semanas seguintes.
- Ajustar cache e revalidação conforme o comportamento real do crawler nos logs.
A decisão entre CSR, SSR e SSG não é permanente — sites maduros combinam as três estratégias por rota, otimizando cada URL para seu papel no funil e seu valor de SEO. O que não pode acontecer é escolher CSR por default para páginas cujo conteúdo precisa estar no índice do Google no dia seguinte à publicação.