SEO para React

O React renderiza no lado do cliente por padrão, então os rastreadores veem um shell vazio até o JavaScript ser executado. Veja como o Google realmente processa aplicativos React, qual estratégia de renderização escolher e como corrigir roteamento, metadados e a armadilha de conteúdo duplicado por tempo limite de renderização.

Publicado pela primeira vez: 26 de jun. de 2026 · Última atualização: 22 de ago. de 2026 · Avançado
Idiomas

React não é ruim para SEO — mas a renderização no lado do cliente por padrão é. Fora da caixa (CRA, Vite + React), o servidor envia um shell vazio e o navegador constrói a página, então os rastreadores não veem nada até o JavaScript ser executado. O Google pode renderizar React via seu Web Rendering Service, mas a renderização é enfileirada, atrasada e pode expirar — Gary Illyes mostrou tempos limite de renderização deixando páginas apenas com boilerplate que são marcadas como duplicadas. Os contratos de renderização de rastreadores de IA variam por provedor, então conteúdo apenas com CSR adiciona um risco de cobertura. A solução é a estratégia de renderização: SSR ou SSG (mais facilmente com Next.js ou Remix) coloca o conteúdo no HTML inicial, hidratado com hydrateRoot (não createRoot) para que a saída do servidor e do cliente correspondam exatamente. Em seguida, use roteamento com History API, links reais <a href>, códigos de status corretos e metadados apropriados para a versão: React 19 eleva <title>/<meta>/<link> nativamente, caso contrário use react-helmet-async (nunca o original react-helmet, sem manutenção).

TL;DR — O problema de SEO do React não é o React — é a renderização no lado do cliente por padrão. CRA e Vite + React entregam um shell vazio e constroem o DOM no navegador, então o HTML bruto que um crawler busca não tem conteúdo. O Google pode renderizá-lo via o Web Rendering Service (Chromium evergreen), mas a renderização é enfileirada separadamente, pode ser atrasada e pode expirar — Gary Illyes documentou timeouts de renderização deixando páginas apenas com boilerplate que depois são sinalizadas como duplicadas. O Bing renderiza JS de forma menos confiável; a renderização por crawlers de IA varia conforme o provedor. A solução é a estratégia de renderização: SSR ou SSG (mais facilmente Next.js ou Remix) coloca o conteúdo no HTML inicial — e se você estiver hidratando marcação renderizada no servidor, use hydrateRoot (não createRoot) e trate qualquer incompatibilidade servidor/cliente como um bug, não um aviso para suprimir. Depois use roteamento via History API (não URLs com hash) e links reais <a href>. Para metadados <head>: React 19 eleva <title>/<meta>/<link> nativamente; no React 18 ou para necessidades avançadas, use react-helmet-async (nunca o react-helmet original não mantido). Defina códigos de status HTTP corretos. Não há bônus de ranqueamento para SSR — ele apenas torna o conteúdo confiavelmente indexável. Para os mecanismos gerais de renderização, veja os tópicos de JavaScript SEO e CMS headless.

O que realmente torna o React difícil para SEO

React é uma biblioteca JavaScript baseada em componentes, e por padrão — Create React App, Vite + React — ela roda no lado do cliente. O servidor retorna um documento quase vazio (famosamente apenas um <div id="root"></div>) mais um bundle de JavaScript, e o navegador executa esse JavaScript para construir o DOM. Compare isso com uma página renderizada no servidor (WordPress, um app Rails), onde o HTML completo — conteúdo, cabeçalhos, links — chega na primeira resposta.

Então a pergunta que decide tudo é: o que está no HTML bruto antes de qualquer JavaScript rodar? Para um app React padrão, a resposta é “quase nada.” Clique com o botão direito → Ver código-fonte em um app CRA e você verá o shell, não o conteúdo. Isso é exatamente o que um crawler recebe na primeira busca.

Para ser preciso sobre onde a responsabilidade realmente está: a biblioteca React não é apenas CSR. O React DOM oferece renderização no cliente (createRoot), renderização no servidor (APIs de streaming e estáticas) e APIs de hidratação — a biblioteca suporta tudo isso. O problema do shell vazio é uma propriedade do toolchain padrão (Create React App, Vite + React sem servidor), que configura apenas as APIs do cliente e nada que renderize para HTML no servidor. Troque o toolchain — Next.js, Remix ou as próprias APIs de renderização no servidor do React — e a mesma biblioteca entrega HTML completo na primeira resposta.

Esta é a aplicação específica do React do problema mais amplo de JavaScript SEO — vá para lá para os modos gerais de falha (paridade, interação, estado, tempo). Aqui vou focar no que é específico do React e como corrigir.

Como o Google realmente processa um app React

O Google lida com JavaScript em três fases: crawl → render → index. O Googlebot busca a URL, o DOM renderizado é construído depois pelo Web Rendering Service (WRS) — uma versão evergreen do Chromium, o mesmo motor do Chrome — e então a saída renderizada é indexada e seus links extraídos. Evidence for this claim Google processes JavaScript pages through crawling, rendering, and indexing using its Web Rendering Service. Scope: Google Search rendering behavior. Confidence: high · Verified: Google: JavaScript SEO basics

A nuance importante é quando a renderização acontece. A renderização é intensiva em recursos, então ela é enfileirada separadamente do crawl inicial. Martin Splitt descreveu o fluxo claramente: “we do an HTTP request, and we get something back … some barebone HTML and all it does is load the JavaScript and run the JavaScript. Then, this HTML … goes into rendering. Rendering runs JavaScript — boom!, a lot of content happens that wasn’t there before.” (tradução) «fazemos uma requisição HTTP e recebemos algo de volta … algum HTML básico e tudo o que ele faz é carregar o JavaScript e executar o JavaScript. Então, esse HTML … vai para a renderização. A renderização executa JavaScript — boom!, muito conteúdo acontece que não estava lá antes.» Para uma página React CSR, o “boom” é sua página inteira — nada dela existe até que essa etapa de renderização rode.

Uma ressalva que vale carregar: não se apegue demais ao antigo modelo de “duas ondas de indexação”. O próprio Splitt recuou, chamando a onda de “uma simplificação excessiva.” A conclusão prática não é “existe uma Onda 2 formal com cronograma definido” — é que a renderização é uma etapa distinta, adiável e falível, e o CSR coloca 100% do seu conteúdo do lado errado dela.

Mais dois fatos sobre o renderizador que afetam especificamente aplicativos React:

  • Ele não tem estado. O Googlebot não retém localStorage, sessionStorage ou cookies entre carregamentos de página. Qualquer conteúdo ou roteamento que dependa de estado do lado do cliente é invisível para o rastreador.
  • Ele pode desistir. O renderizador impõe um tempo limite. Se o seu conteúdo principal carregar lentamente — bundles grandes, cascatas de chamadas de API — a renderização pode terminar antes que seu conteúdo chegue, e o Google indexa a página incompleta.

A armadilha do tempo limite de renderização (e por que ela cria duplicatas)

Esse modo de falha raramente é bem explicado, e é o mais prejudicial para aplicativos React. Gary Illyes descreveu isso diretamente: “I have a bunch of emails in my inbox where the issue is that the centerpiece took forever to load, so rendering timed out … and we were left with a bunch of pages that only had the boilerplate. With only the boilerplate, those pages are dups.” (tradução) «Tenho um monte de e-mails na minha caixa de entrada onde o problema é que a peça central demorou uma eternidade para carregar, então a renderização expirou … e ficamos com um monte de páginas que só tinham o boilerplate. Com apenas o boilerplate, essas páginas são duplicatas.»

Pense no que isso significa para um aplicativo React com CSR. Seu cabeçalho, navegação e rodapé são boilerplate que carrega rápido. Seu conteúdo real da página — a parte que torna cada URL única — é buscado e renderizado por JavaScript, e carrega lentamente. A renderização expira. O Google fica com cabeçalho + navegação + rodapé em cada URL. Agora cada página parece idêntica, e o Google as marca como duplicatas umas das outras no Search Console.

A própria correção do Illyes é a parte acionável: “Try to restructure the js calls such that the content (including marginal boilerplate) loads first and see if that helps.” (tradução) «Tente reestruturar as chamadas de js para que o conteúdo (incluindo boilerplate marginal) carregue primeiro e veja se isso ajuda.» Mas a resposta mais durável é não depender da etapa de renderização para o seu conteúdo principal — o que significa SSR ou SSG.

Estratégias de renderização para React

Esta é a decisão de maior impacto. As opções, aproximadamente do pior para o melhor em SEO:

  • CSR (React padrão). O servidor envia o shell; o navegador constrói tudo. O conteúdo é atrasado pela fila de renderização e exposto ao tempo limite. Pior para SEO. Adequado para dashboards autenticados que você não quer indexados de qualquer forma. Evidence for this claim Client-only React rendering constructs UI in the browser; server rendering APIs produce HTML before browser hydration. Scope: React rendering mechanics; SEO impact depends on what the initial response contains. Confidence: high · Verified: React: hydrateRoot React: Server APIs
  • Pré-renderização. Renderização em tempo de build sem um framework SSR completo — ferramentas como react-snap ou um serviço de pré-renderização rastreiam seu aplicativo e salvam HTML estático. Mais leve; funciona para sites mais simples e majoritariamente estáticos.
  • SSG (Geração de Site Estático). HTML construído uma vez no momento do deploy e servido como arquivos estáticos. Mais rápido, conteúdo sempre presente no HTML bruto. Limitado para conteúdo altamente dinâmico ou por usuário; sites grandes têm builds lentos.
  • SSR (Renderização no Servidor). O servidor executa React por requisição e envia HTML completo. Conteúdo imediatamente disponível para rastreadores; sempre atualizado. Custa um servidor Node.js e um TTFB ligeiramente maior.
  • Híbrido / ISR (Regeneração Estática Incremental). Um recurso do Next.js que regenera páginas estáticas em segundo plano — velocidade estática com atualização periódica.
EstratégiaConteúdo no HTML inicial?Risco de SEOMelhor para
CSR (React puro)NãoMais altoDashboards logados, aplicativos não indexados
Pré-renderizaçãoSim (tempo de build)BaixoSites pequenos, majoritariamente estáticos
SSGSim (tempo de build)Mais baixoBlogs, documentação, marketing
SSRSim (por requisição)BaixoConteúdo atualizado e dinâmico
ISR / híbridoSimBaixoConteúdo que muda a cada hora/dia

E uma estratégia para evitar em novos builds: renderização dinâmica — detectar o user-agent do crawler e servir a ele uma versão pré-renderizada enquanto os usuários recebem CSR. O Google agora chama isso de “a workaround and not a long-term solution” (tradução) «um paliativo, e não uma solução de longo prazo» que “creates additional complexities and resource requirements,” (tradução) «cria complexidades e requisitos adicionais de recursos», e recomenda renderização no servidor, renderização estática ou hidratação em vez disso. (O Bing recomendou renderização dinâmica em 2018, mas essa orientação está desatualizada — desde 2019 o Bingbot renderiza via Microsoft Edge / Chromium, e SSR/SSG é a escolha certa lá também.)

Há um mito que vale a pena eliminar aqui: SSR não é um impulso de ranqueamento. Como John Mueller disse, “there are no SEO ranking bonuses for implementing it one way or another” (tradução) «não há bônus de ranqueamento de SEO por implementar de um jeito ou de outro» — os diferentes métodos de renderização são “just different ways of making the content indexable.” (tradução) «apenas maneiras diferentes de tornar o conteúdo indexável». O valor do SSR é a indexabilidade confiável (e frequentemente melhores Core Web Vitals graças a um First Contentful Paint mais rápido), não uma alavanca mágica de ranqueamento.

A hidratação deve corresponder exatamente — isso é um limite de bug, não uma técnica de SEO

SSR e SSG ambos entregam ao navegador HTML que já contém seu conteúdo. O React então precisa anexar-se a essa marcação no cliente, e isso é uma API diferente de uma renderização simples no cliente:

  • createRoot renderiza o React em um nó do DOM do zero — sem marcação existente esperada. Use-o para aplicativos somente CSR.
  • hydrateRoot anexa o React ao HTML que react-dom/server já gerou, e espera que a primeira renderização do cliente produza uma saída idêntica à que o servidor enviou. Se você está usando SSR/SSG, você quer hydrateRoot, não createRoot — chamar createRoot em marcação renderizada no servidor significa que o React a descarta e re-renderiza do zero, jogando fora exatamente o benefício de SEO que você configurou SSR/SSG para obter.
Evidence for this claim hydrateRoot attaches React to HTML previously generated by React on the server; the initial client output should match the server output. Scope: hydration Confidence: high · Verified: hydrateRoot

Incompatibilidades entre a saída do servidor e do cliente são um risco real em aplicativos React que fazem correções de SEO — um Date.now() em um título, um formato dependente de localidade, um ramo if (typeof window !== 'undefined'). A própria documentação do React é direta sobre o que acontece então: ela avisa sobre incompatibilidades em desenvolvimento, mas “there are no guarantees that attribute differences will be patched up in case of mismatches.” (tradução) «não há garantias de que as diferenças de atributos serão corrigidas em caso de incompatibilidade». A orientação é tratar incompatibilidades como bugs e corrigi-las — não suprimir o aviso e assumir paridade de conteúdo. Para SEO especificamente: não assuma que seu conteúdo renderizado e metadados correspondem ao que o servidor enviou apenas porque a página parece correta no navegador. Compare o HTML do servidor com o DOM pós-hidratação diretamente (a verificação View Source vs. Inspect Element da seção de testes abaixo é a versão rápida disso) em vez de confiar em um console limpo.

React Router e estrutura de URL

O React Router lida com a navegação no navegador sem idas e voltas ao servidor, o que é aceitável para SEO se configurado corretamente:

  • Use a History API, não roteamento por hash. BrowserRouter usa pushState e produz URLs limpas e rastreáveis (/products). HashRouter produz /#/products, e o Google não consegue resolver URLs baseadas em hash de forma confiável — o antigo esquema de crawling AJAX que as fazia funcionar está obsoleto. Use a History API.
  • O servidor também deve lidar com essas URLs. Com o roteamento pela History API, cada “página” precisa de uma URL real à qual o servidor possa responder — crítico para SSR, e necessário para que um acesso direto ou atualização em /products não retorne 404.
  • <Link> renderiza uma âncora real. O componente <Link> do React Router gera um <a href>, que é rastreável. Navegação construída com manipuladores onClick sem uma âncora não é rastreável — o Google só segue links <a href> reais.

Gerenciando metadados: react-helmet, react-helmet-async e as tags nativas do React 19

Até o React 18, o React nunca atualizava o <head> do documento nativamente em mudanças de rota — cada <title>, meta description, canonical e tags Open Graph / Twitter de cada rota tinham que ser definidos por uma biblioteca. O React 19 mudou isso: componentes podem renderizar tags <title>, <meta> e <link> diretamente, e o React as eleva para <head> por conta própria — funcionando com aplicativos somente cliente, SSR com streaming e Server Components. O React 19.2 é a versão estável atual em meados de 2026, então isso agora se aplica a qualquer aplicativo em uma versão atual do React.

Isso significa que a resposta certa depende da sua versão do React e do que você realmente precisa:

  • React 19, aplicativo autônomo, apenas tags básicas. Renderize <title>/<meta>/<link> em seus componentes diretamente — nenhuma biblioteca necessária.
  • React 19, mas você precisa de htmlAttributes/bodyAttributes, serialização de context para SSR, onChangeClientState, prioritizeSeoTags ou titleTemplate. A elevação nativa não cobre isso — use react-helmet-async. A própria documentação dele destaca isso diretamente: sem essas necessidades específicas, você pode não precisar do pacote no React 19.
  • React 18 ou anterior, aplicativo autônomo. A elevação nativa ainda não existe — use react-helmet-async. Ele é mantido ativamente (versão principal 3, e detecta sua versão do React em tempo de execução) e suporta SSR.
  • O react-helmet original. Não use, em nenhuma versão do React. Ele não é mantido — nenhum lançamento desde 2020 — e tem bugs conhecidos sob a renderização concorrente do React 18.
  • Aplicativos Next.js. Use a própria Metadata API do Next (o export metadata / generateMetadata no App Router) independentemente da versão do React — não adicione Helmet, e também não confie na elevação nativa de tags do React. O framework é dono do documento em um aplicativo Next.js.

Uma regra de confiabilidade vem do JavaScript SEO em geral e se aplica não importa qual das opções acima você use: metadados em nível de HTML superam metadados injetados por JS. Uma tag canonical injetada por JavaScript no lado do cliente é muito menos confiável do que uma presente no HTML renderizado no servidor — o que é outro argumento para SSR/SSG.

Crawlers de IA tornam isso urgente

A novidade de 2026: o comportamento de renderização para GPTBot (OpenAI), ClaudeBot (Anthropic), PerplexityBot e outros agentes é específico do provedor e da versão. Um aplicativo React CSR entrega a cada crawler o mesmo shell vazio que o primeiro fetch do Googlebot vê, e a documentação atual dos provedores não estabelece uma etapa de renderização compartilhada que o preencha. À medida que os mecanismos generativos se tornam uma superfície de descoberta maior, SSR/SSG deixa de ser uma preocupação exclusiva do Google: HTML bruto maximiza a cobertura sem assumir uma limitação universal do crawler. (O tópico de CMS headless cobre essa realidade dos crawlers de IA em mais profundidade.)

Testando o que o Google realmente vê

Não confie no seu navegador — o Inspetor do DevTools mostra o DOM renderizado (pós-JavaScript), que é exatamente o que um crawler sem JS não vê. Use as ferramentas certas:

  • Ver código-fonte vs. Inspecionar elemento. Ver código-fonte é o HTML bruto (o que os crawlers recebem antes do JS). Inspecionar elemento é o DOM renderizado. Se o conteúdo está em Inspecionar, mas falta no Ver código-fonte, ele depende de JavaScript.
  • Ferramenta de inspeção de URL (Search Console) — a verificação mais autoritativa. Execute um teste ao vivo e observe o HTML renderizado, a captura de tela e os recursos da página / mensagens do console para ver o que o Google realmente renderizou e o que falhou ao carregar.
  • Teste de resultados avançados — uma verificação rápida do HTML renderizado sem verificar o site.
  • Desative o JavaScript no DevTools e recarregue — uma simulação rápida de um crawler que não executa JS (e um bom proxy para o que os crawlers de IA veem).
  • Relatório de cobertura do Search Console — “Descoberto, atualmente não indexado” pode sinalizar um acúmulo na fila de renderização; clusters de páginas duplicadas podem sinalizar a armadilha do boilerplate de timeout de renderização.
  • Crawlers com renderização JS — Ahrefs Site Audit e Screaming Frog (modo de renderização JS) renderizam páginas em escala para que você possa comparar bruto vs. renderizado em todo o site.

Next.js e Remix (a resposta prática)

Se SEO importa e você está em React CSR puro, migrar para um framework que renderiza no servidor geralmente é a jogada certa. Next.js é feito para isso — SSR e SSG prontos para uso, ISR, App Router, uma Metadata API integrada, divisão automática de código e otimização de imagens. Remix é a alternativa baseada em padrões web, construída em fetch/Request/Response com SSR por padrão e uma forte história de progressive enhancement. O Next.js tem um mergulho profundo próprio — estou sendo breve aqui de propósito. O ponto para SEO em React é mais restrito: o framework existe para tirar seu conteúdo da etapa de renderização apenas no navegador e colocá-lo no HTML inicial.

React é bom para SEO quando você trata a renderização como uma decisão de arquitetura, e não como algo pensado depois. Escolha SSR ou SSG para qualquer coisa que precise ranquear, mantenha seus links e roteamento honestos, gerencie metadados por rota e deixe as próprias ferramentas do Google — não o seu navegador — dizerem o que realmente foi renderizado.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.