SEO para Angular

Como tornar aplicativos Angular rastreáveis e indexáveis com SSR, pré-rendering, renderização híbrida, hydration, meta tags e links reais.

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

SEO para Angular começa com HTML real na primeira resposta: use @angular/ssr ou pré-rendering em vez de um shell CSR vazio. Combine rotas pré-renderizadas e renderizadas no servidor com renderização híbrida, faça hydration do HTML do servidor e cuide de títulos, descrições, URLs History, links <a href> e JSON-LD. O Google consegue renderizar JavaScript, mas a renderização é enfileirada e outros rastreadores podem não executar JS; renderização dinâmica é uma solução provisória, não uma estratégia.

TL;DR — SEO para Angular é uma decisão arquitetural com várias funções: coloque HTML real na resposta em vez de um shell renderizado no cliente. O Angular moderno (v17+) incorpora SSR à CLI como @angular/ssr (o sucessor integrado e renomeado do Angular Universal). Faça o pré-rendering de rotas estáticas, renderize rotas dinâmicas no servidor, combine as duas abordagens com renderização híbrida e faça hydration para que o HTML do servidor seja reutilizado, não reconstruído. Depois cuide do essencial: títulos e descrições exclusivos pelos serviços Title/Meta (ou pela TitleStrategy do roteador), roteamento HTML5 History — nunca HashLocationStrategy — links reais <a href>, JSON-LD injetado com segurança e verificação pelo URL Inspection. A renderização dinâmica é uma solução provisória reconhecida pelo Google, não uma estratégia.

Evidence for this claim Modern Angular documents @angular/ssr as its server-side and hybrid rendering package. Scope: Current Angular documentation; historical Angular Universal details are not required for this claim. Confidence: high · Verified: Angular: Server-side and hybrid rendering

O padrão é o problema: renderização no lado do cliente

Um build Angular comum envia um index.html cujo body é essencialmente <app-root></app-root> mais tags de script. Sem executar JavaScript, um rastreador não vê títulos, texto nem links — o conteúdo é montado no navegador depois que o pacote é carregado. Este é o mesmo problema central que descrevo em JavaScript SEO: a web deixou de usar apenas HTML, e CSR é a extremidade mais arriscada desse espectro.

(Os detalhes de implementação deste guia — APIs RenderMode, gatilhos de hydration e replay de eventos — refletem o Angular v22. Os recursos específicos de versão abaixo são datados: renomeação do SSR na v17, replay de eventos na v18 e hydration incremental nas v19–v20.)

CSR cria três problemas distintos de SEO:

  1. Indexação atrasada e menos confiável. O Google processa aplicativos JS em três fases — “Crawling, Rendering, and Indexing” (tradução) «rastreamento, renderização e indexação» — e a renderização é adiada para uma fila. Seu conteúdo não existe para indexação até que essa renderização aconteça.
  2. Core Web Vitals piores. O LCP sofre porque o navegador precisa baixar e executar um pacote antes de pintar conteúdo significativo.
  3. Rastreadores que não são do Google veem o shell. O Bingbot é muito menos consistente ao renderizar JS, e bots de prévias sociais/de links geralmente não renderizam nada — portanto, tags Open Graph e conteúdo injetado no cliente nunca chegam a eles.

Como o Googlebot realmente trata um aplicativo Angular

O Googlebot é evergreen — renderiza com uma versão atual do mecanismo V8 do Chrome e se atualiza junto com os lançamentos do Chrome. Evidence for this claim Googlebot uses an evergreen version of Chromium for rendering. Scope: Google Search rendering engine; this does not remove application-level rendering risks. Confidence: high · Verified: Google: Evergreen Googlebot Então ele consegue executar Angular. Mas o comportamento tem limites concretos que vale considerar no design:

  • A renderização entra em uma fila; não é imediata. O Google documenta fases distintas de rastreamento, renderização e indexação, mas não publica um prazo fixo para a etapa de renderização alcançar o rastreamento. O resumo usado pelo setor é “duas ondas” — o HTML bruto é indexado primeiro (um shell vazio para Angular em CSR), e o DOM renderizado é indexado depois, quando essa renderização acontece. SSR/pré-rendering contorna a espera: o HTML está completo no primeiro fetch, então não há uma etapa de renderização separada aguardando para esse conteúdo.
  • O renderizador não mantém estado. Não há cookies, localStorage ou sessionStorage entre carregamentos; ele recusa solicitações de permissão. Não condicione conteúdo ao estado do cliente.
  • Ele não clica nem rola a página, e renderiza em uma viewport muito alta. Conteúdo atrás de uma interação não será visto.
  • Os recursos são armazenados em cache agressivamente — use nomes de arquivo com fingerprint de conteúdo (o padrão do Angular, main.<hash>.js) para que pacotes atualizados não sejam servidos como obsoletos.

@angular/ssr — o que é e a história do nome

A renderização no servidor executa o Angular em um servidor Node a cada solicitação e devolve HTML completamente renderizado; o navegador então faz hydration (anexa listeners de eventos ao DOM existente em vez de renderizar novamente). Todo rastreador — Googlebot, Bingbot e bots sociais — recebe HTML completo na primeira solicitação, sem precisar de uma segunda onda.

O nome confunde, então seja preciso: “Angular Universal” era a solução histórica de SSR, distribuída como um pacote externo (@nguniversal/express-engine). Com o Angular v17 (novembro de 2023), o SSR foi integrado diretamente à CLI do Angular e ao Application Builder e renomeado como @angular/ssr; o repositório Angular Universal agora está em modo de manutenção. Evidence for this claim Modern Angular documents @angular/ssr as its server-side and hybrid rendering package. Scope: Current Angular documentation; historical Angular Universal details are not required for this claim. Confidence: high · Verified: Angular: Server-side and hybrid rendering A configuração agora é feita com uma única linha:

# New project with SSR enabled
ng new my-app --ssr

# Add SSR to an existing project
ng add @angular/ssr

Isso substitui o antigo ng add @nguniversal/express-engine. A mesma ideia, agora como ferramenta de primeira classe.

Pré-rendering (geração estática / SSG)

O pré-rendering gera HTML estático para as rotas durante o build, então nenhum servidor é executado no momento da solicitação — você pode fazer o deploy em uma CDN. Ele oferece o TTFB/FCP/LCP mais rápido e o menor custo operacional. Na v17+ você o configura por rota em um arquivo de rotas do servidor (app.routes.server.ts) usando RenderMode.Prerender, e outputMode: 'static' produz um aplicativo totalmente estático.

A restrição: os dados precisam estar disponíveis no momento do build, não pode haver conteúdo por usuário e sites muito grandes significam builds lentos. É ideal para páginas de marketing, documentação e posts de blog — exatamente o conteúdo que mais precisa ranquear e ser citado.

Renderização híbrida — escolha um modo por rota

O grande avanço da v17+ é que o modo de renderização é uma decisão por rota, configurada em app.routes.server.ts:

  • RenderMode.Prerender — rotas estáticas (home, sobre, posts de blog).
  • RenderMode.Server — rotas dinâmicas, por solicitação (resultados de busca, painéis com dados recentes).
  • RenderMode.Client — rotas somente internas que você não quer indexar (interfaces administrativas, telas autenticadas). CSR é realmente adequado aqui.

Esta é a regra prática de decisão: faça pré-rendering do que é estático, renderize no servidor o que precisa estar atualizado e só recorra à renderização no cliente para o que não deve entrar no índice.

Hydration — a armadilha que destrói o CLS

O SSR ingênuo tem um defeito: o servidor envia HTML e depois o navegador o descarta e renderiza tudo novamente, causando um flash e trabalho desperdiçado. Hydration corrige isso — o navegador restaura o aplicativo renderizado pelo servidor e reutiliza o DOM correspondente em vez de destruí-lo e recriá-lo, conectando apenas a interatividade. Ative-a em app.config.ts:

provideClientHydration()

Pré-requisito: hydration é um complemento do lado do cliente para SSR, não uma chave independente. provideClientHydration() só faz algo em uma rota que já é renderizada no servidor (ou pré-renderizada) — não transforma o shell de uma rota RenderMode.Client em HTML de servidor. Ative SSR/pré-rendering primeiro para a rota.

Duas capacidades mais recentes importam para a UX relacionada ao SEO — nenhuma delas muda a indexação na Busca:

  • Replay de eventos (v18+): captura interações do usuário compatíveis que acontecem antes do fim da hydration e as reproduz quando ela termina. Reduz cliques perdidos para os tipos de interação que suporta; é um recurso de UX/interatividade, não de SEO, e não altera o que o Google indexa.
  • Hydration incremental (prévia para desenvolvedores na v19, estável na v20): depende de SSR, hydration, views adiáveis e replay de eventos em conjunto — não é um recurso independente. É alimentada por blocos @defer com gatilhos de hydration que controlam quais limites permanecem desidratados na renderização inicial; um limite hydrate never permanece desidratado no primeiro carregamento, mas não fica necessariamente impedido de carregar suas dependências em renderizações posteriores no cliente (por exemplo, após uma mudança de rota). O efeito relevante para SEO é indireto: menos JavaScript hidratado de início pode ajudar o LCP, mas a configuração do gatilho é um detalhe de renderização, não um mecanismo de tempo do rastreador.

A armadilha crítica: colocar @if (isPlatformBrowser(...)) diretamente em um template faz o servidor e o cliente renderizarem marcação diferente — uma incompatibilidade de hydration — que produz mudança de layout e prejudica o CLS. Use afterNextRender() para trabalho exclusivo do navegador em vez de ramificar o template com base na plataforma.

Títulos e meta tags — os serviços integrados do Angular

O Angular não consegue vincular diretamente ao texto do elemento <title>, então você gerencia as tags do head por meio de dois serviços de @angular/platform-browser:

  • TitlesetTitle() / getTitle().
  • MetaaddTag(), addTags(), updateTag(), getTag(), removeTag(), com seletores como name='description' ou property='og:title'.

Você não precisa de uma biblioteca de terceiros para o básico. Um serviço de SEO compartilhado é o padrão mais limpo:

@Injectable({ providedIn: 'root' })
export class SeoService {
  private title = inject(Title);
  private meta = inject(Meta);

  updatePage(title: string, description: string) {
    this.title.setTitle(title);
    this.meta.updateTag({ name: 'description', content: description });
    this.meta.updateTag({ property: 'og:title', content: title });
  }
}

Especificamente para títulos, a TitleStrategy do roteador (Angular v14+) permite definir um title diretamente na configuração da rota, para que o título da página seja atualizado automaticamente na navegação — sem código por componente. E não defina document.title = ... manualmente; use o serviço Title para que funcione corretamente sob SSR.

Estrutura de URL

  • Use o roteamento padrão da API History do HTML5 (PathLocationStrategy) — URLs limpas como /products/shoes. Ele precisa de <base href="/"> em index.html.
  • Nunca use HashLocationStrategy / useHash: true para conteúdo público. Identificadores de fragmento depois de # são removidos antes da solicitação HTTP, então o servidor nunca os vê e o Googlebot não consegue resolver #/products de modo confiável — seu site inteiro pode acabar como uma única URL.
  • Links reais <a href> para navegação, inclusive para rotas carregadas de forma preguiçosa. Lazy loading é adequado para performance, mas os links para essas rotas ainda precisam ser âncoras rastreáveis, não manipuladores de clique.

Dados estruturados (JSON-LD)

O Google aceita a injeção de JSON-LD com JavaScript. O padrão robusto no Angular é um serviço que cria um <script type="application/ld+json"> e o anexa a document.head, usando o token de injeção DOCUMENT do Angular em vez de tocar em document globalmente (o que quebra no servidor). Mantenha todo o schema em um só lugar — não o divida entre o HTML estático e o DOM renderizado — e valide com o Rich Results Test e o URL Inspection.

Renderização dinâmica — uma solução provisória antiga, não um plano

A renderização dinâmica entrega uma versão pré-renderizada aos bots (via Puppeteer, Rendertron ou prerender.io) e a SPA completa aos usuários. O Google é explícito: “dynamic rendering is a workaround and not a long-term solution” (tradução) «a renderização dinâmica é uma solução provisória, não uma solução de longo prazo», e há “better solutions than dynamic rendering” (tradução) «soluções melhores que a renderização dinâmica» — especificamente renderização no servidor, renderização estática ou hydration. Ela não é automaticamente cloaking, desde que você entregue conteúdo substancialmente semelhante, mas acrescenta outro servidor de renderização, cria risco de divergência de conteúdo e não faz nada pelos Core Web Vitals de usuários reais. Em um novo build Angular, escolha @angular/ssr ou pré-rendering.

Erros comuns de SEO no Angular

  1. Roteamento com hash (URLs com #) — o site inteiro parece uma única URL.
  2. Ausência de chamadas Title/Meta — todas as páginas compartilham um título e uma descrição.
  3. Ausência de SSR/pré-rendering — o conteúdo só existe depois da onda de renderização adiada.
  4. Bloqueio de .js/.css em robots.txt — o Google não consegue renderizar e indexa um shell vazio.
  5. Retorno de 200 em uma página de não encontrado — um soft 404; retorne um 404 real ou adicione noindex.
  6. document.title = ... em vez do serviço Title.
  7. isPlatformBrowser() dentro de @if no template — incompatibilidade de hydration → CLS.
  8. Acesso a window/localStorage/document em código executado no servidor — falhas de SSR.
  9. Divisão do schema entre HTML bruto e DOM renderizado.
  10. Teste em desenvolvimento local em vez de usar URL Inspection — confiar em suposições, não no Googlebot.

Testando Angular para SEO

  • URL Inspection (Search Console) é a fonte de verdade: a visualização da página rastreada mostra o HTML renderizado — o DOM depois que o Googlebot executou o JavaScript, que é o que é indexado — além de mensagens do console JS e recursos bloqueados. Execute o Live Test para uma renderização sob demanda.
  • Use curl na URL para ver o HTML bruto, antes do JS — um shell vazio significa CSR sem SSR.
  • Rich Results Test valida dados estruturados.
  • Ahrefs Site Audit (com renderização JS ativada) e Screaming Frog (modo JS) comparam DOM bruto e renderizado em escala.
  • Lighthouse / PageSpeed Insights medem o impacto da sua escolha de renderização nos Core Web Vitals.

Angular não é ruim para SEO — é apenas diferente. Coloque HTML real na resposta, gerencie suas meta tags, mantenha URLs e links rastreáveis e deixe as próprias ferramentas do Google arbitrarem o que foi renderizado. Este tópico fica ao lado de JavaScript SEO e das questões de renderização de headless CMS neste cluster — a lição subjacente é a mesma em todos: o modo de renderização decide quase tudo.

Add an expert note

Pin an expert quote

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