AngularのSEO

Angularアプリをクロール可能かつインデックス可能にする方法を解説します。@angular/ssrとプリレンダリング、ハイブリッドレンダリング、ハイドレーション、Title/Metaサービス、History APIルーティング、Googlebotが実際にレンダリングするもののテストを扱います。

初回公開:2026年6月26日 · 最終更新:2026年8月22日 · Advanced
言語

Angular SEOの本質は、クライアントレンダリングのシェルではなく、本物のHTMLを提供するという1つの判断です。最新のAngular(v17以降)は@angular/ssrをCLIに組み込み、静的ルートをプリレンダリングし、動的ルートをサーバーでレンダリングし、HTMLを破棄しないようハイドレーションします。さらに、AngularのTitle/Metaサービスで固有のtitleとdescriptionを設定し、HTML5 Historyルーティング(ハッシュURLは使わない)、本物の<a href>リンクを使い、URL検査で確認します。動的レンダリングは回避策であり戦略ではありません。AngularJSは別のフレームワークです。

TL;DR — Angular SEOは、多くの役割を持つ1つのアーキテクチャ上の判断です。クライアントレンダリングのシェルではなく、本物のHTMLをレスポンスに入れます。最新のAngular(v17以降)は、SSRを@angular/ssrとしてCLIに組み込みました(改称され、統合されたAngular Universalの後継です)。静的ルートをプリレンダリングし、動的ルートをサーバーでレンダリングし、ハイブリッドレンダリングで組み合わせ、サーバーHTMLを再利用して再構築しないようハイドレーションします。さらに、TitleMetaサービス(またはルーターのTitleStrategy)で固有のtitle/descriptionを設定し、HTML5 Historyルーティング(HashLocationStrategyは使わない)、本物の<a href>リンク、安全に注入したJSON-LD、URL検査による検証を行います。動的レンダリングはGoogleが認める回避策であり、戦略ではありません。

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

問題はデフォルト:クライアントサイドレンダリング

標準のAngularビルドは、本文が実質的に<app-root></app-root>で、スクリプトタグが付いたindex.htmlを出荷します。JavaScriptを実行しなければ、クローラーには見出し、本文、リンクがありません。バンドルの読み込み後にブラウザーでコンテンツが組み立てられるからです。これはJavaScript SEO で説明しているのと同じ中核問題です。ウェブは単純なHTMLから移行し、CSRはそのスペクトルの中でもリスクが高い端です。

(このガイドの実装詳細(RenderMode API、ハイドレーションのトリガー、イベントリプレイ)はAngular v22を反映しています。以下のバージョン固有の機能には、v17のSSR改称、v18のイベントリプレイ、v19〜v20のインクリメンタルハイドレーションという日付があります。)

CSRは、SEOに関する3つの異なる問題を生みます。

  1. インデックス登録の遅延と不確実性。 GoogleはJSアプリを3段階(「Crawling, Rendering, and Indexing」 (翻訳)「クロール、レンダリング、インデックス登録」)で処理し、レンダリングをキューへ遅延させます。レンダリングが実行されるまで、コンテンツはインデックス登録の対象になりません。
  2. Core Web Vitalsの悪化。 意味のあるコンテンツを描画する前にブラウザーがバンドルをダウンロードして実行するため、LCPが悪化します。
  3. Google以外のクローラーにはシェルしか見えない。 BingbotはJSレンダリングの一貫性が低く、ソーシャル/リンクプレビューのボットは通常レンダリングしません。そのため、クライアント側で注入したOpen Graphタグやコンテンツは届きません。

GooglebotがAngularアプリを実際に処理する方法

Googlebotはevergreenです。現在のChromeのV8エンジンでレンダリングし、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 したがってAngularを実行できます。ただし、設計時に考慮すべき明確な境界があります。

  • レンダリングは即時ではなくキューに入る。 Googleはクロール、レンダリング、インデックス登録を別々の段階として文書化していますが、レンダリングがクロールに追いつくまでの固定時間は公開していません。業界でいう「2つの波」は、まずCSR Angularの空のシェルである生HTMLがインデックスされ、その後、レンダリングされたDOMが、レンダリングが実行された時点でインデックスされることです。SSR/プリレンダリングなら最初の取得でHTMLが完成しているため、そのコンテンツが別のレンダリングを待つ必要はありません。
  • レンダラーはステートレス。 読み込み間でCookie、localStoragesessionStorageを持ち越さず、権限プロンプトを拒否します。クライアント状態でコンテンツを制御しないでください。
  • クリックもスクロールもしない。 とても高いビューポートでレンダリングします。操作の背後にあるコンテンツは見られません。
  • リソースは積極的にキャッシュされる。 更新されたバンドルが古いまま配信されないよう、コンテンツフィンガープリント付きファイル名(Angularの標準main.<hash>.js)を使います。

@angular/ssrとは:名称の歴史

サーバーサイドレンダリングは、リクエストごとにNodeサーバー上でAngularを実行し、完全にレンダリングしたHTMLを返します。ブラウザーは既存のDOMにイベントリスナーを取り付けてハイドレーションします。すべてのクローラー(Googlebot、Bingbot、ソーシャルボット)が最初のリクエストで完全なHTMLを受け取り、2つ目の波を待つ必要がありません。

名称が混乱を招くため、正確に説明します。**「Angular Universal」**は歴史的なSSRソリューションで、外部パッケージ(@nguniversal/express-engine)として提供されていました。**Angular v17(2023年11月)でSSRはAngular CLIとApplication Builderに直接統合され、@angular/ssr**へ改称されました。Angular Universalリポジトリは現在メンテナンスモードです。 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 現在の設定は1行です。

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

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

これは古いng add @nguniversal/express-engineを置き換えます。同じ考え方ですが、正式に統合されたツールです。

プリレンダリング(静的生成/SSG)

プリレンダリングはビルド時にルートの静的HTMLを生成するため、リクエスト時にサーバーを実行せず、CDNへデプロイできます。TTFB/FCP/LCPが最も速く、運用コストも最小です。v17以降は、サーバールートファイル(app.routes.server.ts)でRenderMode.Prerenderを使い、ルートごとに設定します。outputMode: 'static'なら完全に静的なアプリになります。

制約は、データがビルド時に利用できなければならず、ユーザーごとのコンテンツがなく、大規模サイトではビルドが遅くなることです。マーケティングページ、ドキュメント、ブログ記事に最適です。検索でランク付けされ、引用される必要が最も高いコンテンツそのものです。

ハイブリッドレンダリング — ルートごとにモードを選ぶ

v17以降の大きな進歩は、app.routes.server.tsでレンダリングモードをルートごとに設定できることです。

  • RenderMode.Prerender — 静的ルート(ホーム、About、ブログ記事)。
  • RenderMode.Server — 動的でリクエストごとに変わるルート(検索結果、最新データのダッシュボード)。
  • RenderMode.Client — そもそもインデックスさせない内部専用ルート(管理画面、認証限定画面)。ここではCSRで問題ありません。

実務での判断ルールはこれです。静的なものはプリレンダリングし、最新性が必要なものはサーバーでレンダリングし、インデックスに入れるべきでないものだけクライアントレンダリングへ戻します。

ハイドレーション — CLSを壊す落とし穴

素朴なSSRには欠点があります。サーバーがHTMLを送り、ブラウザーがそれを破棄して最初から再レンダリングするため、ちらつきと無駄な処理が発生します。ハイドレーションはこれを解決します。ブラウザーがサーバーでレンダリングしたアプリを復元し、対応するDOMを破棄・再作成せず再利用して、インタラクティブ性だけを接続します。これはapp.config.tsで有効にします。

provideClientHydration()

前提: ハイドレーションはSSRに付随するクライアント側の機能で、単独のスイッチではありません。provideClientHydration()が動くのは、すでにサーバーでレンダリング(またはプリレンダリング)されたルートだけです。RenderMode.ClientルートのシェルをサーバーHTMLに変えることはできません。まずそのルートでSSR/プリレンダリングを有効にします。

SEOに隣接するUXで重要な新機能が2つあります。ただし、どちらも検索のインデックス登録自体を変えません。

  • イベントリプレイ(v18以降): ハイドレーション完了前に起きた、対応対象のユーザー操作を取得し、完了後に再生します。対応する操作で失われるクリックを減らします。UX/インタラクティブ性の機能でありSEOの機能ではなく、Googleがインデックスする内容にも影響しません。
  • インクリメンタルハイドレーション(v19開発者プレビュー、v20で安定版): SSR、ハイドレーション、遅延可能ビュー、イベントリプレイを組み合わせて使い、単独機能ではありません。@deferブロックのhydrateトリガーで、初期レンダリングでどの境界を脱水状態に保つかを制御します。hydrate never境界は初回読み込みで脱水状態のままですが、後のクライアントレンダリング(ルート変更後など)で依存関係の読み込みまで必ず阻止するわけではありません。SEOへの影響は間接的です。最初にハイドレーションするJavaScriptを減らすとLCPに役立つことがありますが、トリガー設定はレンダリングの詳細であって、クローラーのタイミングを制御する仕組みではありません。

重大な落とし穴: テンプレート内に@if (isPlatformBrowser(...))を直接置くと、サーバーとクライアントが異なるマークアップをレンダリングし、ハイドレーション不一致になります。レイアウトシフトが発生してCLSを悪化させるため、テンプレートをプラットフォームで分岐せず、ブラウザー専用処理にはafterNextRender()を使います。

titleとmetaタグ — Angular組み込みサービス

Angularは<title>要素のテキストへ直接バインドできないため、@angular/platform-browserの2つのサービスでheadタグを管理します。

  • TitlesetTitle()getTitle()
  • MetaaddTag()addTags()updateTag()getTag()removeTag()。たとえばname='description'property='og:title'のようなセレクターを使います。

基本機能にサードパーティーライブラリは不要です。共有SEOサービスがきれいなパターンです。

@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 });
  }
}

特にtitleについては、ルーターの**TitleStrategy**(Angular v14以降)を使うと、ルート設定でtitleを直接設定でき、ナビゲーション時にページtitleが自動更新されます。コンポーネントごとのコードは不要です。document.title = ...を手で設定せず、SSRでも正しく動くようTitleサービスを使います。

URL構造

  • 標準のHTML5 History APIルーティング(PathLocationStrategy)を使う。 /products/shoesのようなきれいなURLになります。index.html<base href="/">が必要です。
  • 公開コンテンツでHashLocationStrategyuseHash: trueを決して使わない。 #の後のフラグメント識別子はHTTPリクエスト前に取り除かれるため、サーバーには見えず、Googlebotも#/productsを確実に解決できません。サイト全体が1つのURLに崩れる可能性があります。
  • ナビゲーションには本物の<a href>リンクを使う。 遅延読み込みルートへのリンクも同じです。遅延読み込みはパフォーマンス上問題ありませんが、ルートへのリンクはクリックハンドラーではなくクロール可能なアンカーでなければなりません。

構造化データ(JSON-LD)

GoogleはJavaScriptによるJSON-LDの注入をサポートしています。堅牢なAngularパターンは、documentをグローバルに触ってサーバーを壊すのではなく、AngularのDOCUMENT注入トークンで<script type="application/ld+json">を作り、document.headへ追加するサービスです。すべてのスキーマを1か所に置き、静的HTMLとレンダリングされたDOMに分割しないでください。リッチリザルトテストとURL検査で検証します。

動的レンダリング — 旧式の回避策であり、計画ではない

動的レンダリングは、ボットにPuppeteer、Rendertron、prerender.ioなどでプリレンダリングした版を、ユーザーに完全なSPAを提供します。Googleは*“dynamic rendering is a workaround and not a long-term solution,”* (翻訳)「動的レンダリングは回避策であり、長期的な解決策ではない」、そして*“better solutions than dynamic rendering”* (翻訳)「動的レンダリングより優れた解決策」があると明確に述べています。つまり、サーバーサイドレンダリング、静的レンダリング、ハイドレーションです。実質的に同じコンテンツを提供する限り自動的にクローキングになるわけではありませんが、追加のレンダリングサーバー、コンテンツのずれのリスクを生み、実ユーザーのCore Web Vitalsには何もしません。新しいAngularビルドでは、代わりに@angular/ssrまたはプリレンダリングを使います。

Angular SEOでよくある間違い

  1. ハッシュルーティング(# URL) — サイト全体が1つのURLに見える。
  2. TitleMetaの呼び出しがない — すべてのページが同じtitleとdescriptionを共有する。
  3. SSR/プリレンダリングがない — コンテンツが遅延レンダリングの波の後でしか存在しない。
  4. robots.txt.js.cssをブロックする — Googleがレンダリングできず、空のシェルをインデックスする。
  5. 見つからない画面で200を返す — ソフト404。本物の404を返すかnoindexを追加する。
  6. Titleサービスではなくdocument.title = ...を使う。
  7. テンプレートの@if内でisPlatformBrowser()を使う — ハイドレーション不一致 → CLS。
  8. サーバーで実行されるコードからwindowlocalStoragedocumentに触る — SSRがクラッシュする。
  9. 生HTMLとレンダリングされたDOMでスキーマを分割する。
  10. URL検査ではなくローカル開発環境でテストする — Googlebotではなく思い込みに頼る。

AngularをSEO向けにテストする

  • URL検査(Search Console)が真実の基準です。クロール済みページ表示には、GooglebotがJavaScriptを実行した後のDOMであるレンダリングHTML、インデックスされる内容、JSコンソールメッセージ、ブロックされたリソースが表示されます。オンデマンドレンダリングにはライブテストを実行します。
  • URLをcurlすると、生のJavaScript実行前HTMLが分かります。空のシェルならSSRのないCSRです。
  • リッチリザルトテストで構造化データを検証します。
  • Ahrefs Site Audit(JSレンダリングを有効化)とScreaming Frog(JSモード)で、生DOMとレンダリングDOMを大規模に比較します。
  • Lighthouse/PageSpeed Insightsで、レンダリング方式がCore Web Vitalsに与える影響を確認します。

AngularはSEOに悪いのではなく、違うだけです。レスポンスに本物のHTMLを入れ、headタグを管理し、URLとリンクをクロール可能にし、何がレンダリングされたかをGoogle自身のツールで判断させます。このトピックはJavaScript SEO と、同じクラスターのヘッドレスCMSレンダリングの問題に並びます。根底の教訓は共通です。レンダリングモードがほぼすべてを決めます。

Add an expert note

Pin an expert quote

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