Tempo de leitura: 12 minutos
Angular e Vue funcionam para SEO quando cada página chega pronta no HTML, com SSR no Angular e com o Nuxt no Vue. Porém, sem isso, toda URL devolve o mesmo HTML quase vazio. O Googlebot executa o JavaScript depois, numa fila, mas um robô de IA que lê só o HTML inicial fica sem o texto.
Em resumo
- O Angular renderiza no navegador por padrão. Por isso, o SEO no Angular começa com
ng add @angular/ssr, que liga SSR e pré-renderização por rota. - No Vue, o caminho mais direto para o SEO é o Nuxt, que renderiza no servidor por padrão e aceita regras por rota.
- No entanto, mesmo com SSR, o conteúdo de
@defersem gatilhohydrate, no Angular, e o de<ClientOnly>, no Nuxt, ficam fora do HTML. - Para testar o SEO no Angular ou no Vue, baixe a página com o user agent do GPTBot e procure o texto e o title. Uma raiz vazia, como
<app-root></app-root>, indica página montada no navegador.
Este guia segue a documentação do Angular 22.2, do Vue 3.5 e do Nuxt 4.6.
Angular e Vue sem SSR são ruins para SEO?
Para o Google, não necessariamente, mas há atraso e risco. Para um robô que lê só o HTML inicial, porém, a resposta é sim. Isso porque, sem SSR, o Angular e o Vue entregam o mesmo HTML quase vazio em toda URL. Assim, o texto, o title de cada página e os links só aparecem depois que o JavaScript roda.
De acordo com o guia de estratégias de renderização do Angular, o CSR é o padrão do framework. Para o SEO, o mesmo guia classifica o CSR do Angular como ruim, porque o conteúdo fica invisível para os robôs até o JavaScript rodar. Além disso, num projeto do Angular CLI sem SSR, toda rota devolve o mesmo index.html, com a tag <app-root></app-root> vazia e um title com o nome do projeto.
Da mesma forma, a documentação do Vue avisa que SPAs só com renderização no cliente são um problema quando o SEO importa. Isso porque o navegador recebe uma página quase vazia. Por exemplo, num app criado com o create-vue, toda rota devolve um <div id="app"></div> vazio e o mesmo title, Vite App. O guia de SSR do Vue explica o limite do Google e do Bing:
“Hoje, o Google e o Bing indexam bem aplicações JavaScript síncronas. A palavra-chave aí é síncronas. Se o app começa com um indicador de carregamento e depois busca o conteúdo via Ajax, o robô não vai esperar você terminar.” (tradução nossa)
Documentação do Vue, guia de SSR (2026)
Para os robôs de IA, no entanto, o quadro é menos claro. De fato, as páginas da OpenAI, da Anthropic e do Perplexity sobre seus robôs não dizem se eles executam JavaScript. Num estudo de 2024 da Vercel, que vende hospedagem, com a consultoria MERJ, os robôs testados da OpenAI, da Anthropic e do Perplexity não executaram JavaScript. Em setembro de 2026, porém, um relato sugeriu mudança nos robôs da OpenAI, ainda sem confirmação. Por isso, vale a regra do comparativo de SSR e CSR para SEO e IA: o conteúdo precisa estar no HTML inicial.
Dá para fazer SEO no Angular e no Vue sem servidor?
Sim, com a pré-renderização, que gera as páginas no build e dispensa um servidor rodando o app. Aliás, o guia de SSR do Vue indica esse caminho, o SSG, para o SEO de poucas páginas de marketing, como home, sobre e contato. No Angular, o mesmo vale com RenderMode.Prerender e outputMode: "static". Por outro lado, quando reescrever o front não cabe no prazo, a pré-renderização como serviço, no modelo do Prerender.io, compra tempo.

Como ativar o SSR no Angular?
Num projeto novo, crie o app com ng new --ssr. Já num projeto existente, rode ng add @angular/ssr. O comando cria o servidor e, por padrão, pré-renderiza todas as rotas no build. Em seguida, o arquivo app.routes.server.ts define, rota a rota, se o HTML sai do build, do servidor a cada pedido ou só do navegador.
Aliás, o @angular/ssr reúne o antigo Angular Universal, que na versão 17 passou para o Angular CLI, conforme o repositório do Universal. Portanto, um tutorial que manda instalar o Universal trata de uma versão anterior.
ng add @angular/ssr
// src/app/app.routes.server.ts
import {RenderMode, ServerRoute} from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{path: '', renderMode: RenderMode.Prerender}, // home: HTML gerado no build
{path: 'produtos/:id', renderMode: RenderMode.Server}, // HTML gerado a cada pedido
{path: 'conta/**', renderMode: RenderMode.Client}, // área logada: só no navegador
{path: '**', renderMode: RenderMode.Server},
];
A escolha segue a matriz do próprio Angular para o SEO. Ou seja, SSG para conteúdo estático, SSR para conteúdo dinâmico e CSR só onde o SEO não importa, como em áreas logadas. Conforme o guia de SSR do Angular, alguns detalhes mudam o resultado:
- Rotas com parâmetro: para pré-renderizar
produtos/:id, a funçãogetPrerenderParamsdefine quais URLs o build gera. - Hospedagem sem Node: a opção
outputMode: "static", noangular.json, gera o HTML de cada rota no build, sem arquivo de servidor. - Redirecionamentos: no SSR, o
redirectTovira redirecionamento HTTP. Pelo código do pacote de SSR do Angular, o padrão é 302, e a rota de servidor aceitastatus: 301. Na pré-renderização, porém, vira meta refresh no HTML. - Página inexistente: na página de erro, defina o status 404 com o token
RESPONSE_INIT, para que a URL inexistente não responda 200.
Nuxt resolve o SEO de um site em Vue?
Em geral, sim. Para o SEO, o Nuxt usa renderização universal por padrão. Ou seja, o servidor roda o Vue e devolve a página completa, e o navegador assume na hidratação. Assim, texto, links e meta tags chegam no HTML inicial, que qualquer robô lê, inclusive os de IA que não executam JavaScript.
De acordo com a documentação do Nuxt, a renderização universal é o padrão também para otimizar a indexação. Com ssr: false, por outro lado, o Nuxt passa a montar a página no navegador, e a mesma documentação avisa que indexar conteúdo assim leva mais tempo. Além disso, a documentação do Vue recomenda um framework só quando o site precisa de SSR e lista Nuxt, Vike, Astro e Quasar.
O Nuxt também permite escolher o modo de cada rota, com as routeRules:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // HTML gerado no build
'/blog/**': { swr: 3600 }, // cache de 1 hora, refeito em segundo plano
'/conta/**': { ssr: false }, // área logada: só no navegador
},
})
O isr funciona como o swr, mas guarda a página na CDN, hoje só na Netlify e na Vercel. Para hospedagem estática, o nuxt generate pré-renderiza o site: o rastreador do Nitro parte da home e das rotas sem parâmetro e segue os links <a href>. Por isso, uma página com parâmetro que nenhuma outra linka fica sem HTML.
| Modo | Angular | Nuxt |
|---|---|---|
| HTML a cada pedido (SSR) | RenderMode.Server | Padrão |
| HTML no build (SSG) | RenderMode.Prerender | prerender: true |
| Só no navegador (CSR) | RenderMode.Client | ssr: false |
| Site todo estático | outputMode: "static" | nuxt generate |
Vale migrar uma SPA em Vue para o Nuxt quando as páginas públicas precisam de busca e de IA. Enquanto isso, a área logada pode seguir só no navegador, com ssr: false. O Nuxt, aliás, cumpre no Vue o papel que o Next.js cumpre no React.
O módulo Nuxt SEO vale a pena?
Vale quando o site precisa de sitemap, robots.txt, Schema.org e imagens de Open Graph sem montar cada peça. O módulo Nuxt SEO, o @nuxtjs/seo, instala de uma vez nove módulos, entre eles esses e um verificador de links. Ainda assim, ele não é obrigatório, já que o Nuxt gera as tags de SEO com useSeoMeta e useHead.
Trata-se de um módulo de terceiros, mantido por Harlan Wilton e listado no diretório de módulos do Nuxt. Atualmente, a versão 6 exige o Nuxt 4.6.1 ou mais novo.
O que fica fora do HTML no Angular e no Nuxt, mesmo com SSR?
Fica fora tudo o que o framework adia para o navegador. No Angular, por exemplo, isso inclui o conteúdo de @defer sem gatilho hydrate e o código em afterNextRender. No Vue e no Nuxt, entram o conteúdo de <ClientOnly>, os dados buscados com server: false e o que nasce em onMounted. Portanto, um robô sem JavaScript não vê nada disso.
| Padrão no código | Vai no HTML do servidor? | O que fazer |
|---|---|---|
Angular: @defer sem hydrate | Não, só o @placeholder | Acrescentar hydrate on viewport |
Angular: afterNextRender | Não, roda só no navegador | Deixar ali só o que não é conteúdo |
Nuxt: <ClientOnly> | Não, só o fallback | Usar em widget sem texto importante |
Nuxt: useFetch com server: false | Não, chega após a hidratação | Buscar no servidor, o padrão |
Vue e Nuxt: busca em onMounted | Não, o gancho não roda no SSR | No Nuxt, trocar por useFetch |
De acordo com o guia de @defer do Angular, no SSR e na pré-renderização o bloco sai só com o @placeholder, ou vazio. Para que o conteúdo vá no HTML, acrescente um gatilho hydrate. Ele funciona porque a hidratação incremental vem ligada quando o app usa provideClientHydration().
@defer (hydrate on viewport) {
<app-avaliacoes />
} @placeholder {
<p>Avaliações dos clientes</p>
}
Num teste nosso com o Angular 22.2, o mesmo bloco sem o gatilho hydrate saiu do servidor só com o placeholder. Com hydrate on viewport, no entanto, saiu com o texto das avaliações.
Como gerar meta tags por página no Angular e no Vue?
No Angular, use o title de cada rota e os serviços Title e Meta. Da mesma forma, para o SEO no Nuxt, use useSeoMeta e useHead. Com SSR ou pré-renderização, as tags saem no <head> do HTML de cada URL. Sem isso, elas só existem depois que o JavaScript roda, e um robô sem JavaScript vê o title padrão do index.html.
// src/app/produto.ts
import {Component, inject} from '@angular/core';
import {Meta, Title} from '@angular/platform-browser';
@Component({
selector: 'app-produto',
template: `<h1>Tênis de corrida azul</h1>`,
})
export class Produto {
constructor() {
inject(Title).setTitle('Tênis de corrida azul | Loja Exemplo');
inject(Meta).updateTag({name: 'description', content: 'Tênis leve para treinos de 5 a 21 km.'});
}
}
Para o SEO no Angular, o que conta é a tag nascer no servidor. De fato, no nosso teste com SSR, title e description saíram no HTML do servidor. Para o canonical, aliás, o guia de SSR do Angular mostra um serviço que cria o link com o token DOCUMENT.
<!-- app/pages/produtos/[id].vue -->
<script setup lang="ts">
const route = useRoute()
useSeoMeta({
title: 'Tênis de corrida azul | Loja Exemplo',
description: 'Tênis leve para treinos de 5 a 21 km.',
})
useHead({
link: [{ rel: 'canonical', href: `https://www.exemplo.com.br${route.path}` }],
})
</script>
Para as meta tags de SEO, a documentação do Nuxt recomenda o useSeoMeta, que tem tipos para mais de 100 tags. Com dados do CMS, por exemplo, passe funções, como title: () => produto.value?.nome. Num app Vue com Vite, porém, as tags de SEO criadas por JavaScript só existem para quem renderiza a página.
E o streaming experimental do Nuxt?
No Nuxt 4.5 ou mais novo, o streaming de SSR é experimental e vem desligado. Quando ligado, porém, ele envia o <head> antes do fim da renderização. Assim, tags registradas depois de um await viram scripts que corrigem a página no navegador, conforme a documentação de recursos experimentais. Quem recebe o streaming sem executar JavaScript, portanto, não as vê.
Já os robôs reconhecidos pelo botRegex recebem a página inteira, sem streaming, e a documentação cita só Googlebot e Bingbot como exemplos. No código do Nuxt 4.6, o padrão reconhece nomes terminados em bot, como GPTBot, ClaudeBot e PerplexityBot. Num teste nosso com o user agent oficial, porém, o padrão deixou de fora o Perplexity-User. Esse robô abre páginas a pedido do usuário, como mostra o guia dos robôs do Perplexity e do Claude. Por isso, chame useSeoMeta antes de qualquer await ou desligue o streaming nas rotas públicas, com streaming: false. Outra saída é incluir o Perplexity-User no botRegex, que substitui o padrão inteiro.
Como testar o que os robôs de IA recebem?
Baixe a página com o user agent de um robô de IA e procure no HTML o texto principal, o title e a meta description. Se a resposta traz só a raiz vazia do app, como <app-root></app-root> no Angular ou <div id="app"></div> no Vue, a página depende de JavaScript.
URL="https://www.exemplo.com.br/produtos/tenis-azul"
UA="Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot"
curl -sL -A "$UA" "$URL" > gptbot.html
grep -c "Tênis de corrida azul" gptbot.html # texto principal: 0 = ausente
grep -o '<title>[^<]*</title>' gptbot.html # title desta página, não o padrão do app
grep -c 'name="description"' gptbot.html # meta description: 0 = ausente
grep -oE '<app-root></app-root>|<div id="app"></div>' gptbot.html # raiz vazia = CSR
Rode no terminal do Linux, do macOS ou no Git Bash do Windows. O user agent vem da documentação da OpenAI. Além disso, no Nuxt com streaming, repita o teste com o user agent do Perplexity-User e compare as respostas.
No SEO do Angular e do Vue, o teste mira a primeira resposta do servidor, que é o que um robô sem JavaScript lê. O teste sai do seu IP, então não reproduz bloqueios de firewall feitos por IP. Para o Google, o teste em tempo real da Inspeção de URL, no Search Console, mostra uma captura de tela da página renderizada. O checklist completo, com logs e Search Console, está no guia de SEO de JavaScript para robôs de IA.
As três primeiras checagens servem também para sites em React e em Next.js. Afinal, o HTML pronto é a base do SEO que sustenta a visibilidade da marca no Google e na IA.
Perguntas frequentes
Não com esse nome. Na versão 17, o Angular Universal passou para o Angular CLI, com o código no pacote @angular/ssr, e o repositório antigo hoje está arquivado. Para ativar o SSR no Angular, use ng add @angular/ssr num projeto existente ou ng new --ssr num projeto novo.
Pode deixar, porque o servidor roda o Angular a cada pedido, como avisa a documentação. A pré-renderização evita esse custo: o HTML sai pronto do build e pode ficar numa CDN. Com outputMode: "static", o Angular gera o HTML de cada rota no build, sem servidor Node.
Nenhum dos dois leva vantagem por padrão, porque o Angular e o Vue renderizam no navegador e entregam ao robô um HTML quase vazio. Com SSR ou pré-renderização, os dois entregam a página completa: no Angular, pelo pacote @angular/ssr, e no Vue, pelo Nuxt. Portanto, a escolha pode seguir a equipe e o projeto.
Fontes principais
- Angular, Server and hybrid rendering, guia de SSR e pré-renderização (2026).
- Angular, Rendering strategies in Angular (2026).
- Angular, @defer e o comportamento no SSR (2026).
- Vue.js, Server-Side Rendering (2026).
- Vue.js, Ways of Using Vue (2026).
- Nuxt, Rendering Modes (2026).
- Nuxt, SEO and Meta (2026).
- Nuxt, streaming de SSR experimental (2026).


