Angular SEO: pick a render mode per route, put titles and meta in the server HTML, and return real status codes

How to make an Angular app readable to search engines with @angular/ssr, route-level render modes, the Title and Meta services, status codes and hydration, from the Angular and Google docs.

Published by AI Knows Us · Updated 21 October 2026

Angular SEO comes down to one decision and four follow-ups. The decision: stop serving search engines an empty shell. Angular ships every app as client-side rendered by default, so add server-side rendering with ng add @angular/ssr and choose, route by route, whether each page is prerendered at build time, rendered on the server per request, or left to the browser. The follow-ups: give every route its own title and meta description, return real HTTP status codes, use real links Google can follow, and turn on hydration so the server HTML is reused instead of thrown away. Everything below comes from Angular's own documentation at angular.dev and Google Search Central, both read on 21 October 2026.

Why a default Angular app is hard for search

Angular's server rendering guide says it plainly: "Angular ships all applications as client-side rendered (CSR) by default." The server sends a small HTML file and a bundle of JavaScript, and the browser builds the page. The same guide warns that client-side rendering "may negatively affect search engine optimization (SEO), as search crawlers have limits to how much JavaScript they execute when indexing a page."

Google processes JavaScript pages in three phases: crawling, rendering and indexing. A page waits in a queue for rendering, and Google's JavaScript SEO guide notes that "it is not immediately obvious when a page is waiting for crawling and when it is waiting for rendering." Google still recommends server-side or pre-rendering, "because it makes your website faster for users and crawlers, and not all bots can run JavaScript."

Step 1: add server rendering and pick a mode per route

For a new project, run ng new --ssr. For an existing one, run ng add @angular/ssr. Angular's docs note that by default it then prerenders the entire application and generates a server file. You control the rest in a server routes file, usually app.routes.server.ts, where each route gets one of three render modes.

Render modeWhat the crawler receivesUse it for
RenderMode.Prerender (SSG)A static HTML file built at deploy timeHome, about, pricing, docs, blog posts: pages that are the same for every visitor
RenderMode.Server (SSR)Fully rendered HTML built for each requestProduct and listing pages whose data changes often
RenderMode.Client (CSR)The shell, with content built in the browserLogged-in dashboards and account pages you do not want indexed anyway

Angular's docs say both server rendering and prerendering "generally" have "excellent search engine optimization (SEO), as search crawlers receive a fully rendered HTML document." A typical config looks like this:

import { RenderMode, ServerRoute } from '@angular/ssr'; export const serverRoutes: ServerRoute[] = [ { path: '', renderMode: RenderMode.Prerender }, { path: 'pricing', renderMode: RenderMode.Prerender }, { path: 'products/:id', renderMode: RenderMode.Server }, { path: 'account/**', renderMode: RenderMode.Client }, { path: '**', renderMode: RenderMode.Server },
];

For prerendered routes with parameters, such as post/:id, add a getPrerenderParams function that returns the list of IDs to build. It runs at build time only. If a visitor requests an ID that was not built, the fallback option decides what happens, for example falling back to client rendering. Every ID you want indexed belongs in that list.

Step 2: give every route its own title and description

Google's guide asks for "unique, descriptive <title> elements and meta descriptions." Angular gives you three tools.

  • Route titles. Add a title to each route and Angular updates the page title when the route activates. The title can also come from a resolver function, which suits product pages that need data first.
  • TitleStrategy. If you want a house pattern, such as "Product name | Brand", extend TitleStrategy once instead of repeating the suffix in every route.
  • The Meta service. Angular's Meta service from @angular/platform-browser adds, updates and removes <meta> tags. Its own description lists Search Engine Optimization among the uses.
import { Component, inject } from '@angular/core';
import { Meta } from '@angular/platform-browser'; @Component({ selector: 'app-pricing', template: '...' })
export class Pricing { private meta = inject(Meta); constructor() { this.meta.updateTag({ name: 'description', content: 'Plans, limits and what each tier includes.' }); }
}

Because the page is now rendered on the server, these tags are in the HTML the crawler receives, not added later in the browser. For the canonical link, Angular's guide shows a service that injects the DOCUMENT token and appends a <link rel="canonical"> during server rendering. Use DOCUMENT rather than the browser's global document, which does not exist on the server.

Step 3: return real status codes, and know how redirects behave

A single-page app that shows "Product not found" with a 200 status is a soft 404 in Google's eyes. Google notes that pages with a non-200 status, such as 404, may skip rendering entirely, which is what you want for a missing page.

  • Fixed codes per route. A ServerRoute accepts status and headers properties, so your not-found route can always return 404.
  • Codes decided at runtime. The RESPONSE_INIT token from @angular/core lets a component set the status code during server rendering, for example after an API says the product does not exist.
  • Redirects. Angular's docs say redirectTo becomes a standard HTTP redirect (301 or 302) under server rendering, but a "soft redirect" using <meta http-equiv="refresh"> in prerendered HTML. If a prerendered URL has moved for good, set the permanent redirect at your server or CDN as well.

For routes that stay client rendered, Google suggests two options: redirect with JavaScript to a URL the server answers with 404, or add a noindex robots meta tag to the error view.

Step 4: make links that Google can follow

Google "can only discover your links if they are <a> HTML elements with an href attribute." Put Angular's router links on anchor elements, not on buttons or divs with click handlers. Google also says not to use URL fragments, such as /#/products, to load different content, and to use the History API instead. Moving an older app off hash URLs is a high-value fix.

Step 5: turn on hydration

Hydration lets the browser reuse the server-rendered DOM instead of rebuilding it. Angular's hydration guide warns that without it, server-rendered apps "will destroy and re-render the application's DOM, which may result in a visible UI flicker," which can hurt Largest Contentful Paint and cause layout shift. Projects set up with the CLI usually have it already. In a custom setup, add provideClientHydration() to the bootstrap providers.

One trap the guide calls out: do not use isPlatformBrowser inside templates to show different content on server and client. It causes hydration mismatches and layout shifts. Run browser-only code in afterNextRender instead, and keep the rendered content the same on both sides.

What about dynamic rendering and prerender services?

Google describes dynamic rendering as "a workaround and not a recommended solution, because it creates additional complexities and resource requirements." Angular's built-in hybrid rendering removes the need for it. For the wider picture of how Google renders JavaScript frameworks, see our guide to JavaScript SEO.

How to check the work

  1. View the page source (not the inspector) on a key route. The main heading, body text, title and meta description should be in the raw HTML.
  2. Run the URL in Google's URL Inspection tool or the Rich Results Test and read the rendered HTML, as Google's guide suggests.
  3. Request a URL that should not exist and confirm the response code is 404, not 200.
  4. Check the version. Angular's release page lists v22 as active since 3 June 2026 and says versions 2 to 19 are no longer supported, so very old apps may need an upgrade before the newer server routing APIs are available.

Questions about Angular SEO

Is Angular bad for SEO?

Not when it is set up for it. A default client-rendered Angular app makes crawlers do the rendering. With server rendering or prerendering, crawlers get complete HTML, and Angular's own docs describe that as excellent for SEO.

Should I use prerendering or server-side rendering?

Prerender pages that look the same for everyone and change only when you deploy. Use server rendering for pages whose data changes between deploys, such as stock or prices. You can mix both in one app, route by route.

How do I set the page title in Angular?

Add a title property to each route, or a resolver when the title depends on data. For a site-wide pattern, provide a custom TitleStrategy. Use the Meta service for descriptions and social tags.

Do I still need Angular Universal?

Server rendering now lives in the @angular/ssr package, added with ng add @angular/ssr. Follow the current server and hybrid rendering guide on angular.dev rather than older Universal tutorials.

Why does Google index my Angular page with no content?

Usually Google indexed the client-rendered shell, or an API call failed during rendering. Check the rendered HTML in URL Inspection, then move the route to prerender or server mode.

The same HTML now answers assistants too

Google's own guide says not all bots can run JavaScript, and the crawlers that feed AI assistants are bots too. A product team that moves its Angular marketing pages to server rendering hands every reader, human or machine, the same complete page. What an assistant then says when a buyer asks it to compare products in your category is a separate result you can measure, and AI Knows Us was built to read exactly that.

Read next

Simon-Kucher pricing strategy, what the firm publishes about its own method and what a Singapore buyer should ask before briefing itThe firm publishes its approach, its scale and four named service lines, and publishes no fee, so the useful work before any call is reading what it claims and deciding which decision you are buying.International pricing strategies for a Singapore company, and the corridor that stops one market undercutting anotherA converted home price is the one answer that is almost always wrong, so set a price per market and keep the gaps narrower than the cost of moving a unit between them.Premium pricing strategy for a Singapore business, and the fence that makes the higher number holdCharging permanently more than the credible alternatives works when the buyer can name what the extra money buys, and the published Singapore writing ladder shows exactly how that is built.Red Antler publishes no price, so here is what its own site does publish and how to cost the same scope from SingaporeRead on 29 October 2026, three pages of redantler.com carry a complete deliverable list, three business stages and not one figure about what any of it costs.Hiring a full service content agency, the five stages a retainer has to cover and the two handoffs where the money leaksMost content retainers buy production and quietly leave strategy and distribution with you, so price the stages rather than the word count.Hiring a branding agency for a Singapore financial services firm, and the three registers to search before you fall in love with a nameIdentity work for a licensed firm starts with a clearance search rather than a mood board, and two of the three registers are free to read in a browser today.

Or browse the whole archive.

See what AI says about you.

The first scan is free, it needs no account, and it asks the questions your buyers ask.

Free. No card. We ask 5 real buyer questions on 2 AI apps.

Already sure you want this? Start free. No card needed, and the free plan stays free. Pay only when you want the work done. Or talk to a person if you have a question first. Or read how we fix what it finds.