SEO Angular
Comment rendre les applications Angular explorables et indexables — @angular/ssr contre le pré-rendu et le rendu hybride, l’hydratation, les services Title/Meta, le routage History API et le test de ce que Googlebot restitue réellement.
Langues
Le SEO Angular repose sur une décision : servir du vrai HTML plutôt qu’une coquille rendue côté client. Angular moderne (v17+) intègre le SSR au CLI sous la forme de @angular/ssr : pré-rendez les routes statiques, rendez les routes dynamiques côté serveur et hydratez-les pour ne pas jeter le HTML. Appliquez ensuite les fondamentaux : titres et descriptions uniques via les services Title et Meta d’Angular, routage History HTML5 (jamais d’URL avec hash), vrais liens <a href> et vérification avec l’Inspection d’URL. Le rendu dynamique est un dépannage, pas une stratégie ; AngularJS est par ailleurs un framework différent.
TL;DR — Par défaut, Angular construit la page dans le navigateur avec JavaScript : le HTML brut vu en premier par un moteur de recherche est donc presque vide. La solution consiste à envoyer du HTML réel et terminé, avec le rendu côté serveur intégré (
@angular/ssr) ou le pré-rendu d’Angular. Appliquez ensuite les fondamentaux : un titre et une description uniques par page, des URL propres (sans#) et de vrais liens<a href>.
Le problème en une phrase
Une application Angular par défaut envoie au navigateur une petite coquille HTML — en gros un
<div> vide — avec un gros paquet JavaScript. Le navigateur exécute ce JavaScript,
puis la page se remplit de contenu. C’est le rendu côté client (CSR).
Le problème est que, lorsque le moteur de recherche télécharge cette URL pour la première fois, il ne voit que la coquille vide. Google peut exécuter le JavaScript pour voir le contenu réel, mais il le fait plus tard, lors d’une étape séparée, et pas toujours de façon fiable. Evidence for this claim Google can render JavaScript but processes rendering as a stage after crawling. Scope: Google Search rendering; other crawler behavior is not covered by this record. Confidence: high · Verified: Google: JavaScript SEO basics Les autres robots — Bing et ceux qui alimentent les aperçus sociaux — ne savent souvent pas exécuter le JavaScript. Ils ne voient donc rien.
La solution : envoyer du HTML terminé
Au lieu de laisser le navigateur (ou le robot) construire la page, construisez-la à l’avance ou sur un serveur et envoyez le HTML complet. Angular propose deux grandes méthodes :
- Rendu côté serveur (SSR) — un serveur exécute Angular pour chaque requête et renvoie la page complète. C’est adapté au contenu qui change souvent. Evidence for this claim Angular supports server-side rendering and build-time prerendering through its SSR tooling. Scope: Current Angular SSR and prerender features. Confidence: high · Verified: Angular: Server-side and hybrid rendering
- Pré-rendu — Angular construit des fichiers HTML statiques pour vos pages lors du build : aucun serveur n’est alors nécessaire. C’est l’option la plus rapide, idéale pour les articles de blog et les pages marketing.
Angular moderne (version 17 et ultérieure) intègre ces deux méthodes dans son outillage. Ajoutez
le SSR en une commande : ng add @angular/ssr. Vous avez peut-être entendu l’ancien
nom Angular Universal : c’était la même idée sous la forme d’un module complémentaire
séparé. Angular l’a intégré au cœur en v17 et l’a renommé.
Les autres fondamentaux
- Donnez à chaque page un titre et une description uniques. Angular ne le fait pas à
votre place : définissez-les dans le code avec les services intégrés
TitleetMeta. Sans cela, toutes les pages partagent le même titre. - Utilisez des URL propres, pas des URL avec hash. Le routage par défaut d’Angular produit
de belles URL comme
/products/shoes. Évitez l’ancien style avec hash (/#/products) : les moteurs gèrent mal la partie qui suit#. - Utilisez de vrais liens. La navigation doit employer des liens
<a href>, et non des boutons ou des gestionnaires click, sinon Google ne peut pas les suivre.
L’erreur la plus fréquente
« Google ne peut pas indexer Angular » est un mythe : Google sait rendre du JavaScript. Mais c’est plus lent et moins fiable que d’envoyer directement du HTML réel, et les robots non Google ne savent pas forcément le faire. Pour tout ce que vous voulez rendre trouvable, faites du rendu serveur ou pré-rendez la page.
Vous voulez la version approfondie — rendu hybride par route, hydratation, services SEO avec du code et méthode de test de ce que Google voit réellement ? Passez à l’onglet Advanced.
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 renderingTL;DR — Le SEO Angular est une décision d’architecture qui prend plusieurs formes : faire entrer du HTML réel dans la réponse plutôt qu’une coquille rendue côté client. Angular moderne (v17+) intègre le SSR au CLI sous
@angular/ssr, successeur intégré et renommé d’Angular Universal. Pré-rendez les routes statiques, rendez les routes dynamiques côté serveur, combinez-les avec le rendu hybride et hydratez l’application pour réutiliser le HTML serveur au lieu de le reconstruire. Appliquez ensuite les fondamentaux : titres et descriptions uniques avec les servicesTitle/Meta(ouTitleStrategydu routeur), routage History HTML5 — jamaisHashLocationStrategy— vrais liens<a href>, JSON-LD injecté proprement et vérification dans l’Inspection d’URL. Le rendu dynamique est un dépannage reconnu par Google, pas une stratégie.
Le problème du défaut : le rendu côté client
Un build Angular standard fournit un index.html dont le corps est essentiellement
<app-root></app-root> avec des balises script. Sans exécuter JavaScript, un robot ne voit
ni titres, ni texte, ni liens : le contenu est assemblé dans le navigateur après le chargement
du paquet. C’est le même problème central que celui décrit dans
JavaScript SEO : le Web s’est éloigné du HTML simple,
et le CSR se situe à l’extrémité la plus risquée du spectre.
(Les détails d’implémentation de ce guide — API RenderMode, déclencheurs d’hydratation et relecture d’événements — correspondent à Angular v22. Les fonctionnalités selon la version sont datées : renommage du SSR en v17, relecture d’événements en v18, hydratation incrémentale en v19–v20.)
Le CSR crée trois problèmes SEO distincts :
- Indexation retardée et moins fiable. Google traite les applications JS en trois phases — “Crawling, Rendering, and Indexing.” (traduction) « exploration, rendu et indexation » — et le rendu est placé dans une file. Votre contenu n’existe pas pour l’indexation avant ce rendu.
- Core Web Vitals moins bons. Le LCP souffre parce que le navigateur doit télécharger et exécuter un paquet avant d’afficher du contenu utile.
- Les robots non Google voient la coquille. Bingbot est beaucoup moins constant pour le rendu JS, et les robots d’aperçu social ou de lien ne rendent généralement rien : les balises Open Graph et le contenu injectés côté client ne les atteignent pas.
Comment Googlebot traite réellement une application Angular
Googlebot est evergreen : il rend les pages avec une version actuelle du moteur V8 de Chrome et évolue avec les versions de 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 Il peut donc exécuter Angular. Mais son comportement a des limites importantes à prendre en compte :
- Le rendu est mis en file, pas immédiat. Google documente des phases distinctes d’exploration, de rendu et d’indexation et ne publie pas de calendrier fixe indiquant quand le rendu rattrape l’exploration. Le secteur parle de « deux vagues » : le HTML brut est indexé d’abord (coquille vide pour Angular en CSR), puis le DOM rendu est indexé lorsque le rendu a lieu. Le SSR et le pré-rendu évitent cette attente : le HTML est complet dès la première requête, sans second passage à attendre pour ce contenu.
- Le moteur est sans état. Aucun cookie,
localStoragenisessionStoragen’est conservé entre les chargements ; les demandes d’autorisation sont refusées. Ne conditionnez pas le contenu à l’état du client. - Il ne clique pas et ne fait pas défiler la page, et il rend dans une fenêtre très haute. Le contenu placé derrière une interaction ne sera pas vu.
- Les ressources sont fortement mises en cache : utilisez des noms de fichiers empreints
du contenu (par défaut Angular :
main.<hash>.js) afin que les bundles mis à jour ne soient pas servis depuis un cache périmé.
@angular/ssr — ce que c’est et l’historique du nom
Le rendu côté serveur exécute Angular sur un serveur Node pour chaque requête et renvoie du HTML entièrement rendu, que le navigateur hydrate ensuite (il attache les écouteurs d’événements au DOM existant au lieu de le restituer). Chaque robot — Googlebot, Bingbot, robots sociaux — reçoit du HTML complet dès la première requête, sans seconde vague.
Le nom prête à confusion, alors soyez précis : « Angular Universal » était la solution SSR
historique, distribuée comme paquet externe (@nguniversal/express-engine). Avec
Angular v17 (novembre 2023), le SSR a été intégré directement au CLI Angular et à
l’Application Builder, puis renommé @angular/ssr ; le dépôt Angular Universal
est désormais en maintenance. 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 La configuration tient maintenant en une ligne :
# New project with SSR enabled
ng new my-app --ssr
# Add SSR to an existing project
ng add @angular/ssrCette commande remplace l’ancien ng add @nguniversal/express-engine. Même idée,
outillage de première classe.
Pré-rendu (génération statique / SSG)
Le pré-rendu produit du HTML statique pour les routes au moment du build, sans serveur au
moment de la requête : vous pouvez déployer sur un CDN. Il fournit les valeurs TTFB/FCP/LCP les
plus rapides et le coût opérationnel le plus bas. En v17 et ultérieur, configurez-le par route
dans un fichier de routes serveur (app.routes.server.ts) avec
RenderMode.Prerender, et outputMode: 'static' produit une application
entièrement statique.
La contrainte est simple : les données doivent être disponibles au build, il ne doit pas y avoir de contenu par utilisateur et les très grands sites allongent les builds. C’est idéal pour les pages marketing, la documentation et les articles de blog — exactement le type de contenu qui doit le plus souvent être classé et cité.
Rendu hybride — choisir un mode par route
La grande avancée de v17+ est que le mode de rendu est une décision par route, configurée
dans app.routes.server.ts :
RenderMode.Prerender— routes statiques (accueil, à propos, articles de blog).RenderMode.Server— routes dynamiques par requête (résultats de recherche, tableaux de bord avec données fraîches).RenderMode.Client— routes internes que vous ne voulez de toute façon pas indexer (interfaces d’administration, écrans authentifiés). Le CSR est réellement adapté ici.
La règle pratique est donc : pré-rendez ce qui est statique, rendez côté serveur ce qui doit être frais et ne recourez au rendu client que pour ce qui ne doit pas entrer dans l’index.
Hydratation — le piège qui dégrade le CLS
Le SSR naïf a un défaut : le serveur envoie le HTML, puis le navigateur le jette et
reconstruit la page depuis zéro, ce qui crée un flash et du travail inutile. L’hydratation
corrige cela : le navigateur restaure l’application rendue par le serveur et réutilise le DOM
correspondant au lieu de le détruire et de le recréer ; il ne fait que brancher l’interactivité.
Activez-la dans app.config.ts :
provideClientHydration()Prérequis : l’hydratation est un complément côté client du SSR, pas un interrupteur
autonome. provideClientHydration() n’agit que sur une route déjà rendue côté serveur
(ou pré-rendue) ; il ne peut pas transformer la coquille d’une route RenderMode.Client
en HTML serveur. Activez d’abord le SSR ou le pré-rendu pour la route.
Deux capacités plus récentes comptent pour l’UX liée au SEO — aucune ne modifie l’indexation :
- Relecture d’événements (v18+) : capture les interactions utilisateur prises en charge avant la fin de l’hydratation et les rejoue une fois celle-ci terminée. Cela réduit les clics perdus pour les types d’interaction couverts ; c’est une fonction d’UX/interactivité, pas de SEO, et cela ne change pas ce que Google indexe.
- Hydratation incrémentale (aperçu développeur v19, stable en v20) : dépend du SSR, de
l’hydratation, des vues différables et de la relecture d’événements ensemble ; ce n’est pas
une fonction autonome. Elle repose sur des blocs
@deferavec des déclencheurs d’hydratation qui contrôlent les limites qui restent déshydratées lors du rendu initial ; une limitehydrate neverreste déshydratée au premier chargement mais n’est pas forcément empêchée de charger ses dépendances lors des rendus client ultérieurs (par exemple après un changement de route). L’effet SEO est indirect : moins de JavaScript hydraté au départ peut aider le LCP, mais la configuration des déclencheurs relève du rendu, pas du calendrier des robots.
Piège critique : placer @if (isPlatformBrowser(...)) directement dans un modèle
fait produire au serveur et au client des balises différentes — un mismatch d’hydratation —
ce qui crée un décalage de mise en page et dégrade le CLS. Utilisez
afterNextRender() pour le travail réservé au navigateur au lieu de conditionner le
modèle à la plateforme.
Titres et balises meta — les services intégrés d’Angular
Angular ne peut pas lier directement le texte de l’élément <title>, vous gérez donc
les balises d’en-tête avec deux services de @angular/platform-browser :
Title—setTitle()/getTitle().Meta—addTag(),addTags(),updateTag(),getTag(),removeTag(), avec des sélecteurs commename='description'ouproperty='og:title'.
Vous n’avez pas besoin d’une bibliothèque tierce pour les fondamentaux. Un service SEO partagé est le modèle propre :
@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 });
}
}Pour les titres, le TitleStrategy du routeur (Angular v14+) permet de définir
directement un title dans la configuration de route afin que le titre se mette à jour
automatiquement lors de la navigation — sans code par composant. Ne définissez pas
document.title = ... à la main : utilisez le service Title pour qu’il
fonctionne correctement avec le SSR.
Structure des URL
- Utilisez le routage History HTML5 par défaut (
PathLocationStrategy) — des URL propres comme/products/shoes. Il exige<base href="/">dansindex.html. - **N’utilisez jamais
HashLocationStrategy/useHash: truepour du contenu public. Les identifiants de fragment après#sont retirés avant la requête HTTP : le serveur ne les voit jamais et Googlebot ne peut pas résoudre de manière fiable#/products, ce qui peut réduire tout le site à une seule URL. - De vrais liens
<a href>pour la navigation, y compris vers les routes chargées paresseusement. Le chargement différé est bon pour les performances, mais les liens vers ces routes doivent rester des ancres explorables, pas des gestionnaires click.
Données structurées (JSON-LD)
Google accepte l’injection de JSON-LD avec JavaScript. Le modèle Angular robuste est un service
qui crée un <script type="application/ld+json"> et l’ajoute à
document.head, en utilisant le jeton d’injection DOCUMENT d’Angular plutôt
que de toucher globalement à document (ce qui casse côté serveur). Gardez tout le
schéma au même endroit — ne le séparez pas entre le HTML statique et le DOM rendu — puis validez
avec le test des résultats enrichis et l’Inspection d’URL.
Rendu dynamique — dépannage ancien, pas stratégie
Le rendu dynamique sert une version pré-rendue aux robots (via Puppeteer, Rendertron ou
prerender.io) et la SPA complète aux utilisateurs. Google indique explicitement que
“dynamic rendering is a workaround and not a long-term solution,” (traduction)
« le rendu dynamique est un dépannage et non une solution à long terme », et qu’il existe
“better solutions than dynamic rendering” (traduction) « de meilleures solutions que le
rendu dynamique » — notamment le rendu côté serveur, le rendu statique ou l’hydratation. Ce
n’est pas automatiquement du cloaking tant que le contenu servi reste substantiellement
semblable, mais cela ajoute un serveur de rendu, risque de faire diverger le contenu et ne
change rien aux Core Web Vitals des vrais utilisateurs. Pour un nouveau build Angular,
préférez @angular/ssr ou le pré-rendu.
Erreurs Angular SEO courantes
- Routage par hash (
#) : tout le site ressemble à une seule URL. - Aucun appel
Title/Meta: toutes les pages partagent un titre et une description. - Aucun SSR/pré-rendu : le contenu n’existe qu’après la vague de rendu différée.
- Bloquer
.js/.cssdansrobots.txt: Google ne peut pas rendre la page et indexe une coquille vide. - Renvoyer
200sur une vue introuvable : soft 404 ; renvoyez un vrai404ou ajouteznoindex. document.title = ...au lieu du serviceTitle.isPlatformBrowser()dans@ifdu modèle : mismatch d’hydratation → CLS.- Toucher à
window/localStorage/documentdans du code exécuté sur le serveur : crash SSR. - Séparer le schéma entre le HTML brut et le DOM rendu.
- Tester en développement local au lieu d’utiliser l’Inspection d’URL : vous reposez sur des suppositions, pas sur Googlebot.
Tester Angular pour le SEO
- L’Inspection d’URL (Search Console) est la source de vérité : la vue de la page explorée montre le HTML rendu — le DOM après l’exécution du JavaScript par Googlebot, c’est ce qui est indexé — avec les messages de console JS et les ressources bloquées. Lancez le test en direct pour un rendu à la demande.
curll’URL pour voir le HTML brut avant JavaScript — une coquille vide indique du CSR sans SSR.- Test des résultats enrichis pour valider les données structurées.
- Audit de site Ahrefs (rendu JS activé) et Screaming Frog (mode JS) pour comparer à grande échelle le DOM brut au DOM rendu.
- Lighthouse / PageSpeed Insights pour mesurer l’effet du choix de rendu sur les Core Web Vitals.
Angular n’est pas mauvais pour le SEO : il est simplement différent. Faites entrer du HTML réel dans la réponse, gérez vos balises d’en-tête, gardez les URL et les liens explorables et laissez les outils de Google déterminer ce qui est rendu. Ce sujet côtoie JavaScript SEO et les questions de rendu des CMS headless dans ce cluster ; la leçon reste la même : le mode de rendu décide presque tout.
Résumé IA
Voici une synthèse de la version avancée :
- Le défaut d’Angular est le rendu côté client (CSR) : une coquille HTML presque vide, donc une indexation retardée ou peu fiable, un LCP moins bon et des robots non Google (Bing, réseaux sociaux) qui ne voient rien.
- Googlebot est evergreen et rend le JavaScript, mais le rendu est mis en file (« deux vagues » : HTML brut d’abord, DOM rendu ensuite, sans calendrier fixe), sans état (pas de cookies ni de stockage), sans clic ni défilement, avec une mise en cache agressive. Le SSR et le pré-rendu évitent l’attente : le HTML est complet dès la première requête.
@angular/ssrest la solution moderne : SSR intégré au CLI Angular depuis v17, en remplacement du paquet externe Angular Universal (@nguniversal/express-engine). Configuration :ng new --ssroung add @angular/ssr.- Le pré-rendu (HTML statique au build) est le plus rapide et se déploie sur un CDN : idéal pour les pages marketing, articles et documentation statiques ; il dépend de données disponibles au build.
- Le rendu hybride choisit le mode par route dans
app.routes.server.ts:RenderMode.Prerender(statique),RenderMode.Server(dynamique),RenderMode.Client(pages internes non indexées). - L’hydratation (
provideClientHydration()) réutilise le HTML serveur sur une route déjà SSR ou pré-rendue : elle ne crée pas de HTML serveur pour le CSR. La relecture d’événements (v18+) capture les interactions prises en charge avant l’hydratation ; l’hydratation incrémentale (aperçu v19 / stable v20) dépend du SSR, de l’hydratation, des vues différables et de la relecture ensemble, avec des déclencheurs@defer(hydrate neverne bloque pas les chargements ultérieurs côté client). Aucune ne modifie l’indexation. ÉvitezisPlatformBrowser()dans@if: utilisezafterNextRender(). - Utilisez les services intégrés
TitleetMeta; le routeurTitleStrategydéfinit automatiquement les titres par route. - Utilisez le routage History HTML5, jamais les URL avec hash (
#) ; la navigation doit employer de vrais liens<a href>. Le JSON-LD peut être injecté via le jetonDOCUMENT. - Le rendu dynamique est un dépannage, pas une stratégie : Google recommande plutôt le SSR, le rendu statique ou l’hydratation.
- Testez avec l’Inspection d’URL (HTML rendu),
curl(HTML brut), le test des résultats enrichis et un crawler qui exécute JavaScript. AngularJS ≠ Angular : les anciens conseils AngularJS ne s’appliquent pas.
Documentation officielle
Documentation primaire de Google et d’Angular.
- Comprendre les bases du SEO JavaScript —
les phases exploration → rendu → indexation, les liens
<a href>explorables, les avertissements sur le routage par fragment, les soft 404s et les données structurées injectées en JavaScript. - Rendu dynamique (dépannage) — pourquoi il s’agit d’un dépannage, la nuance du cloaking et les solutions SSR/statique/hydratation.
- Rendering on the Web (web.dev — Addy Osmani et Jason Miller) — définitions de référence du SSR, du CSR, du rendu statique et de l’hydratation, ainsi que leurs compromis de performance.
- Outil d’inspection d’URL — comment voir le HTML rendu que Google indexe réellement et les messages de console JS.
Angular
- Angular — rendu côté serveur et hybride (SSR) —
guide officiel
@angular/ssr, routes serveur etRenderMode. - Angular — service
Title—setTitle()/getTitle(). - Angular — service
Meta—addTag(),updateTag()et sélecteurs. - Angular — référence du routeur —
PathLocationStrategycontre le routage par hash,TitleStrategy. - Présentation d’Angular v17 (blog de l’équipe Angular) — le SSR devenu une fonctionnalité de première classe du CLI.
- Angular Universal (mode maintenance) —
l’ancien paquet, désormais remplacé par
@angular/ssr.
Citations des sources
Déclarations enregistrées de Google et de mon propre travail. Chaque lien de moteur de recherche est un lien profond qui mène directement au passage cité.
Google — traitement des applications JavaScript
- “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.”
(traduction) *« Google traite les applications Web JavaScript en trois phases principales :
- exploration, 2. rendu, 3. indexation. »* — documentation Google Search Central. Aller à la citation
- “Google can only discover your links if they are <a> HTML elements with an href attribute.” (traduction) « Google ne peut découvrir vos liens que s’il s’agit d’éléments HTML <a> dotés d’un attribut href. » — documentation Google Search Central. Aller à la citation
Google — le rendu dynamique est un dépannage
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” (traduction) « Le rendu dynamique était un dépannage et non une solution à long terme pour les problèmes de contenu généré par JavaScript dans les moteurs de recherche. » — documentation Google Search Central. Aller à la citation
web.dev — préférer le SSR / rendu statique (Addy Osmani et Jason Miller)
- “Rendering an app on the server to send HTML, rather than JavaScript, to the client.” (traduction) « Rendre une application sur le serveur pour envoyer du HTML, plutôt que du JavaScript, au client. » — définition du rendu côté serveur. Aller à la citation
Patrick Stox (mon propre travail — JavaScript SEO : guide définitif)
- “JavaScript is not bad for SEO, and it’s not evil. It’s just different from what many SEOs are used to.” (traduction) « JavaScript n’est pas mauvais pour le SEO et n’est pas maléfique ; il est simplement différent de ce à quoi beaucoup de référenceurs sont habitués. »
- “Any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines.” (traduction) « Tout dispositif de SSR, de rendu statique ou de pré-rendu conviendra aux moteurs de recherche. »
Checklist SEO Angular
Vérification rapide pour confirmer qu’une application Angular est explorable et indexable :
- Le contenu public est servi sous forme de HTML réel avec
@angular/ssr(SSR) ou le pré-rendu, et non par CSR intégral. - Le mode de rendu est défini par route dans
app.routes.server.ts: pré-rendu pour les routes statiques, serveur pour les routes dynamiques, client uniquement pour les pages internes non indexées. - L’hydratation est activée (
provideClientHydration()) et aucun modèle n’utiliseisPlatformBrowser()dans@if(utilisezafterNextRender()). - Chaque page définit un titre unique (avec le service
TitleouTitleStrategydu routeur) et une description unique (avec le serviceMeta). - Les balises Open Graph / Twitter Card sont définies avec le service
Metapour les aperçus sociaux. - Le routage utilise l’API History HTML5 (par défaut) avec
<base href="/">— et nonHashLocationStrategy/useHash: true. - Toute la navigation utilise de vraies ancres
<a href>, y compris les liens vers les routes chargées paresseusement. -
robots.txtne bloque pas les ressources.jsou.css. - Les vues introuvables côté client renvoient un vrai
404ou portentnoindex(pas de soft 404s). - Aucun accès à
window/localStorage/documentdans le code exécuté sur le serveur (utilisez le jetonDOCUMENTou des garde-fous de plateforme). - Le JSON-LD est regroupé au même endroit et réussit le test des résultats enrichis.
- Vous avez vérifié le HTML rendu dans l’Inspection d’URL, et pas seulement le développement local.
Les modèles mentaux
1. Faites entrer du HTML réel dans la réponse. Presque tout problème de SEO Angular se résume à cette question : le robot reçoit-il du HTML terminé dès la première requête, ou une coquille qu’il doit rendre ? Le SSR et le pré-rendu répondent « oui ». Le CSR répond « un jour, peut-être ». Commencez chaque audit ici.
2. La règle de décision du rendu par route.
- Contenu statique (accueil, à propos, blog, documentation) →
RenderMode.Prerender. - Contenu dynamique qui doit rester frais (recherche, données en direct) →
RenderMode.Server. - Pages internes ou authentifiées que vous ne voulez pas indexer →
RenderMode.Clientconvient.
3. « Angular Universal » et « @angular/ssr » sont la même idée, à des époques
différentes.
Universal était le paquet externe ; v17 a intégré le SSR au CLI et l’a renommé. Avec Angular
moderne, utilisez @angular/ssr : le dépôt Universal est en maintenance.
4. Hydratez, ne restituez pas tout.
Le SSR naïf envoie du HTML puis le jette. provideClientHydration() le réutilise —
mais seulement sur une route déjà SSR ou pré-rendue ; il ne crée pas de HTML serveur pour une
route CSR. La relecture d’événements et l’hydratation incrémentale (@defer) réduisent
le JavaScript initial. Ne conditionnez jamais un modèle à isPlatformBrowser() :
c’est la voie vers un mismatch d’hydratation et un CLS dégradé.
5. Les balises d’en-tête relèvent de votre responsabilité, pas de celle d’Angular.
Il n’y a pas de Yoast ici. Définissez consciemment les titres et descriptions avec les services
Title/Meta (ou TitleStrategy) pour chaque page. « Toutes les
pages partagent un titre » est l’échec par défaut, pas de la malchance.
6. Concevez pour un robot sans état et des URL propres.
Routage History API, vrais liens <a href>, aucune dépendance aux cookies ou au stockage,
aucun contenu derrière un clic. Laissez ensuite l’Inspection d’URL — pas votre ordinateur —
vous dire ce qui a été rendu.
SEO Angular — fiche mémo
Modes de rendu
| Mode | Où le HTML est construit | SEO | Idéal pour | Configuration Angular |
|---|---|---|---|---|
| Pré-rendu (SSG) | Au build → fichiers statiques | ✅ Meilleur | Pages marketing/blog/documentation statiques | RenderMode.Prerender |
| SSR | Serveur, par requête | ✅ Excellent | Contenu dynamique qui doit rester frais | RenderMode.Server / @angular/ssr |
| Client (CSR) | Dans le navigateur | ⚠️ Risqué | Pages internes/authentifiées (non indexées) | RenderMode.Client |
| Rendu dynamique | Serveur séparé pour les robots | Dépannage seulement | Applications anciennes qui ne peuvent pas migrer | Puppeteer / Rendertron / prerender.io |
Commandes de configuration
| Objectif | Commande |
|---|---|
| Nouveau projet avec SSR | ng new my-app --ssr |
| Ajouter le SSR à une application existante | ng add @angular/ssr |
| Activer l’hydratation | provideClientHydration() dans app.config.ts |
Règles rapides pour les balises et le routage
- Titres/descriptions : services
TitleetMetad’Angular (aucune bibliothèque tierce nécessaire). - Titres automatiques par route :
TitleStrategydu routeur (v14+) via la propriététitlede la route. - Routage : API History HTML5 +
<base href="/">. JamaisuseHash: true. - Liens : de vraies ancres
<a href>, même vers les routes chargées paresseusement. - JSON-LD : injectez-le via le jeton
DOCUMENTet gardez-le au même endroit.
Noms
- Angular Universal = ancien paquet externe (
@nguniversal/express-engine), en maintenance. @angular/ssr= le même SSR, intégré au CLI depuis v17.- AngularJS (v1.x) ≠ Angular (v2+) : frameworks différents ; les anciens conseils AngularJS ne s’appliquent pas.
Pièges
isPlatformBrowser()dans@ifdu modèle → mismatch d’hydratation → CLS. UtilisezafterNextRender().window/localStorage/documentsur le serveur → crash SSR.- Bloquer
.js/.cssdans robots.txt → Google ne peut pas rendre.
Vérifier si une application Angular est réellement rendue côté serveur
La façon la plus rapide de savoir si une URL utilise le CSR ou le SSR/pré-rendu est de récupérer
le HTML brut (avant tout JavaScript) et d’y chercher le contenu réel. Une application Angular en
CSR renvoie un <app-root> presque vide ; une application SSR/pré-rendue renvoie un
balisage terminé.
macOS / Linux
# Raw HTML as the server sends it — this is the "first fetch", pre-JS
curl -sL -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://example.com/page/ -o raw.html
# Is your real headline in the raw HTML? Empty result = CSR with no SSR
grep -o "Your headline text" raw.html
# A near-empty <app-root> is the tell-tale CSR signature
grep -o "<app-root></app-root>" raw.htmlWindows (PowerShell)
$ua = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
Invoke-WebRequest -Uri "https://example.com/page/" -UserAgent $ua -OutFile raw.html
Select-String -Path raw.html -Pattern "Your headline text"
Select-String -Path raw.html -Pattern "<app-root></app-root>"Si le titre manque et que vous voyez un <app-root> nu, le contenu dépend du rendu :
ajoutez le SSR ou le pré-rendu. (Pour le DOM rendu, utilisez « View Crawled Page → rendered
HTML » dans l’Inspection d’URL ; un curl simple ne peut pas exécuter JavaScript.)
Confirmer que le JavaScript/CSS d’Angular n’est pas bloqué dans robots.txt
macOS / Linux
curl -sL https://example.com/robots.txt | grep -iE "disallow.*\.(js|css)|Disallow:\s*/(assets|dist|main)"Une directive Disallow qui correspond à votre bundle signifie que Google ne peut pas
rendre correctement la page : c’est presque toujours une erreur.
Outils pour déboguer le SEO Angular
- Inspection d’URL (Google Search Console) — la source de vérité. Lancez un test en direct, puis lisez le HTML rendu (le DOM après exécution du JavaScript Angular par Googlebot), la capture d’écran, les ressources de page (chargées ou bloquées) et les messages de la console JavaScript.
- Test des résultats enrichis — confirmez que le JSON-LD est présent dans la sortie rendue après chaque changement de rendu.
curl— récupérez le HTML brut avant JavaScript pour distinguer le CSR (<app-root>vide) du SSR/pré-rendu.- Audit de site Ahrefs (rendu JS activé) — explore avec Chrome sans interface et compare le DOM brut au DOM rendu, en faisant ressortir les métadonnées manquantes, les canoniques cassées et les problèmes d’indexabilité à grande échelle.
- Screaming Frog SEO Spider (mode rendu JS) — compare le contenu brut au contenu rendu pour chaque URL.
- Lighthouse / PageSpeed Insights — mesure l’effet du choix de rendu (CSR contre SSR/pré-rendu) sur les Core Web Vitals.
- Angular CLI / DevTools — confirmez que
outputMode, les routes serveur et l’hydratation sont configurés comme prévu.
Ressources utiles
Mes écrits connexes
- SEO JavaScript : guide définitif — mon guide complet sur le rendu, la parité du DOM, la règle de la directive la plus restrictive et les configurations de rendu sûres. Le SEO Angular est une application particulière de ces principes.
- Guide débutant du SEO technique — la place du rendu et de l’exploration dans une vision plus large.
Mes interventions
- SEO JavaScript — Ungagged 2019 (SlideShare) — comportement de rendu sans état de Googlebot, fenêtre d’affichage et mise en cache, ainsi que les approches de rendu de l’époque. (Réserve : la recommandation de rendu dynamique de cette présentation est désormais obsolète ; Google l’a depuis qualifiée de dépannage.)
Dans le secteur
- Rendering on the Web (web.dev) — l’article de référence d’Addy Osmani et Jason Miller sur le SSR, le CSR, le rendu statique et les compromis de l’hydratation.
- Rendu côté serveur et hybride (SSR) (angular.dev) — le guide officiel
@angular/ssr: routes serveur,RenderMode, pré-rendu et hydratation. - Présentation d’Angular v17 (blog de l’équipe Angular) — la version qui a fait du SSR une fonctionnalité de première classe du CLI et introduit le paquet
@angular/ssr. - Angular Universal (mode maintenance) (GitHub) — l’ancien paquet SSR remplacé par
@angular/ssr, utile pour comprendre le changement de nom. - Guide SEO Angular (Search Engine Journal, Jamie Indigo) — le parcours classique de l’indexation en deux vagues ; solide sur les fondamentaux, mais antérieur au renommage de v17.
- Guide du SSR Angular (Angular Architects, Alexander Thalhammer, mars 2025) — guide de configuration SSR riche en code ; vérifiez les exemples contre la documentation officielle
@angular/ssrpour les changements d’API. - r/TechSEO — la communauté consacrée au débogage du rendu et de l’indexation.
Anti-patterns SEO Angular
Erreurs concrètes que je vois régulièrement dans les applications Angular : chacune mérite une vérification directe, et pas seulement une discussion théorique.
Livrer un build uniquement CSR et le déclarer terminé
La sortie par défaut de ng new n’a ni SSR ni pré-rendu. C’est la façon la plus rapide
de commencer un projet et la plus simple de finir avec un <app-root> vide lors de la
première requête. Pourquoi c’est incorrect : le HTML brut vu par un robot ne contient aucun
contenu, l’indexation dépend donc entièrement du rendu différé de Google — et les autres robots
n’ont aucune seconde chance. À faire : ajoutez @angular/ssr au début du projet
(ng new my-app --ssr) ou exécutez ng add @angular/ssr sur un projet
existant avant de publier ce que vous voulez rendre trouvable.
Utiliser HashLocationStrategy pour les routes publiques
Le routage par hash (useHash: true, URL comme /#/products/shoes) reste la
valeur par défaut dans d’anciens tutoriels et modèles Angular. Pourquoi c’est incorrect :
tout ce qui suit # est retiré côté client avant même que la requête atteigne le serveur :
le serveur — et Googlebot — ne voit donc qu’une seule URL pour toute l’application.
À faire : utilisez le routage History HTML5 par défaut (PathLocationStrategy)
avec <base href="/"> dans index.html.
Conditionner un modèle à isPlatformBrowser()
Envelopper le contenu dans @if (isPlatformBrowser(platformId)) semble être le moyen
évident de protéger du code réservé au navigateur. Pourquoi c’est incorrect : le serveur
rend une branche et le client l’autre pendant l’hydratation ; cela crée un mismatch
d’hydratation. Angular doit réconcilier la différence et le résultat visible est un décalage de
mise en page qui apparaît comme CLS. À faire : utilisez afterNextRender() pour le
travail réservé au navigateur afin que le modèle lui-même soit rendu de façon identique côté
serveur et côté client.
Définir document.title directement au lieu du service Title
Cela fonctionne en développement local, donc le raccourci est tentant. Pourquoi c’est
incorrect : l’accès direct au DOM, comme document.title = '...', s’accorde mal avec
le SSR : le serveur n’a pas de global document au même sens que le navigateur et vous
perdez les bénéfices de l’intégration du routeur avec la gestion de titres d’Angular.
À faire : injectez le service Title d’Angular (setTitle()) ou
configurez les titres par route avec TitleStrategy.
Toucher à window, localStorage ou document dans du code SSR
Un composant ou un service qui lit localStorage ou vérifie window.innerWidth
au moment de sa construction fonctionne dans le navigateur et fait tomber le rendu serveur.
Pourquoi c’est incorrect : aucun de ces globaux n’existe dans le processus serveur Node qui
exécute le build SSR ; le rendu échoue et la requête renvoie soit une erreur 500s, soit
silencieusement une réponse vide. À faire : protégez ce code avec afterNextRender()
ou injectez le jeton DOCUMENT plutôt que le global, et testez le build SSR localement
(ng build puis servez la sortie SSR), pas seulement avec ng serve.
Traiter le rendu dynamique comme une solution permanente
Mettre en place Puppeteer ou un service comme Rendertron pour servir une copie pré-rendue aux
robots résout le symptôme immédiat. Pourquoi c’est incorrect : c’est un système
supplémentaire à maintenir, il peut diverger de ce que voient les utilisateurs et Google a
indiqué directement qu’il s’agissait d’un dépannage plutôt que d’une solution à long terme.
À faire : migrez vers @angular/ssr ou le pré-rendu pour que chaque demande —
robot ou humain — reçoive le même HTML réel depuis le même pipeline.
Quel mode de rendu cette route doit-elle utiliser ?
Angular v17+ permet de définir le mode de rendu par route dans
app.routes.server.ts. La question n’est pas « SSR ou pré-rendu pour toute
l’application ? », mais celle-ci, posée pour chaque route.
Choosing a rendering mode for an Angular route
Prompts pour le SEO Angular
Prompts prêts à copier pour les tâches SEO Angular de cet article. Collez l’entrée décrite et vérifiez la sortie selon votre propre jugement : ils font gagner du temps sur les tâches mécaniques, mais ne remplacent pas un test avec l’Inspection d’URL.
1. Comparer le HTML brut au HTML rendu pour une route
Collez la sortie de curl -sL <url> (HTML brut) et le panneau « HTML rendu » d’un test
en direct de l’Inspection d’URL (ou d’une exploration JS d’Ahrefs/Screaming Frog) pour la même URL.
Here is the raw HTML for [URL] (fetched with curl, before JavaScript runs):
[paste raw HTML]
Here is the rendered HTML for the same URL (from Google Search Console URL
Inspection's Live Test, or a JS-rendering crawler):
[paste rendered HTML]
Compare the two. List: (1) content present in rendered but missing from raw —
this is what depends on client-side rendering, (2) any <title>, meta description,
or JSON-LD that differs between the two versions, (3) whether the raw HTML shows
a near-empty <app-root> (a sign of CSR with no SSR/prerendering).Attendez une courte liste de ce qui dépend du CSR et des divergences de titre/meta/schéma entre le brut et le rendu — les deux points à corriger en premier.
**2. Examiner l’implémentation d’un service Title/Meta
Collez votre SeoService Angular (ou équivalent), qui appelle les services
Title et Meta.
Here is an Angular service that sets page titles and meta tags:
[paste the service's TypeScript code]
Check it against these rules: (1) titles are set via the Title service's
setTitle(), never document.title directly, (2) description is set with
meta.updateTag({ name: 'description', ... }) not addTag() (which can duplicate
the tag on repeat calls), (3) Open Graph tags use the property selector, not
name, (4) nothing in this code reads window/localStorage/document directly in a
way that would break during SSR. Flag any line that violates one of these and
suggest the fix.Attendez une vérification ligne par ligne des quatre règles, avec un extrait corrigé pour chaque problème signalé.
3. Auditer app.routes.server.ts pour les erreurs de mode de rendu
Collez votre fichier de configuration des routes serveur.
Here is my Angular app.routes.server.ts, which sets RenderMode per route:
[paste the file]
For each route, tell me: is RenderMode.Prerender used on anything that depends
on per-request or per-user data (a mistake — it would bake stale/wrong data into
the static build)? Is RenderMode.Client used on anything that looks like public,
indexable content (a missed-SEO-opportunity)? Is RenderMode.Server used on fully
static content where Prerender would be faster and cheaper? List each route with
its current mode and whether it matches the decision rule: static data →
Prerender, must-be-fresh → Server, non-indexed internal → Client.Attendez un verdict par route signalant tout mode (RenderMode) qui ne correspond pas aux besoins de la route :
données statiques → pré-rendu, données toujours fraîches → serveur, contenu interne non indexé →
client.
Testez vos connaissances : SEO Angular
Cinq questions rapides sur le rendu d’applications Angular pour les rendre explorables et indexables. Choisissez une réponse à chaque fois, puis vérifiez.
Journal des modifications
Mis à jour le 8 août 2026.
Résumé éditorial et détails enregistrés des changements.Détails des changements
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
Comparaison complète indisponible — aucun instantané antérieur n’a été archivé pour cette révision.
Mis à jour le 17 juil. 2026.
Résumé éditorial et détails enregistrés des changements.Détails des changements
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
Comparaison complète indisponible — aucun instantané antérieur n’a été archivé pour cette révision.