ReactのSEO

Reactはデフォルトでクライアントサイドレンダリングを行うため、クローラーはJavaScriptが実行されるまで空のシェルしか見ることができません。ここでは、Googleが実際にReactアプリをどのように処理するか、どのレンダリング戦略を選ぶべきか、そしてルーティング、メタデータ、レンダリングタイムアウトによる重複コンテンツの罠を修正する方法を説明します。

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

React自体はSEOに悪いわけではありませんが、デフォルトのクライアントサイドレンダリングは問題です。標準の構成(CRA、Vite + React)では、サーバーは空のシェルを送信し、ブラウザがページを構築するため、クローラーはJavaScriptが実行されるまで何も見ることができません。GoogleはWeb Rendering Serviceを通じてReactをレンダリングできますが、レンダリングはキューに入れられ、遅延し、タイムアウトする可能性があります。Gary Illyes氏は、レンダリングのタイムアウトにより、ボイラープレートのみのページが残り、重複としてマークされることを示しています。AIクローラーのレンダリング契約はプロバイダーによって異なるため、CSRのみのコンテンツはカバレッジリスクを追加します。修正方法はレンダリング戦略です。SSRまたはSSG(最も簡単なのはNext.jsまたはRemix)を使用すると、コンテンツが初期HTMLに含まれ、hydrateRoot(createRootではなく)でハイドレーションされるため、サーバーとクライアントの出力が完全に一致します。次に、History APIルーティング、実際の<a href>リンク、正しいステータスコード、バージョンに適したメタデータを使用します。React 19では<title>/<meta>/<link>がネイティブにホイストされますが、それ以外の場合はreact-helmet-async(メンテナンスされていない元のreact-helmetは使用しない)を使用します。

TL;DR — ReactのSEO問題はReact自体ではなく、デフォルトのクライアントサイドレンダリングにあります。 CRAやVite + Reactは空のシェルを配信し、ブラウザでDOMを構築するため、 クローラーが取得する生のHTMLにはコンテンツがありません。GoogleはWebレンダリングサービス(常緑のChromium)経由でレンダリングできますが、レンダリングは別途キューに入れられ、遅延する可能性があり、タイムアウトする可能性があります — Gary Illyesは、ボイラープレートのみのページが残り、重複としてフラグ付けされるレンダリングタイムアウトを文書化しています。BingはJSのレンダリングがそれほど確実ではありません。AIクローラーのレンダリングはプロバイダーによって異なります。修正方法はレンダリング戦略です。SSRまたはSSG(最も簡単なのはNext.jsまたはRemix)により、コンテンツが初期HTMLに含まれます。サーバーレンダリングされたマークアップをハイドレーションする場合は、hydrateRootcreateRootではなく)を使用し、サーバー/クライアントの不一致は抑制する警告ではなくバグとして扱います。次に、History APIルーティング(ハッシュURLではなく)と実際の<a href>リンクを使用します。<head>メタデータについては、React 19は<title>/<meta>/<link>をネイティブにホイストします。React 18または高度なニーズには、react-helmet-asyncを使用します(メンテナンスされていない元のreact-helmetは使用しないでください)。正しいHTTPステータスコードを設定します。SSRにランキングボーナスはありません — コンテンツを確実にインデックス可能にするだけです。一般的なレンダリングの仕組みについては、JavaScript SEOおよびヘッドレスCMSのトピックを参照してください。

ReactがSEOにとって難しい本当の理由

ReactはコンポーネントベースのJavaScriptライブラリであり、標準のまま(Create React App、Vite + React)ではクライアントサイドで実行されます。サーバーはほぼ空のドキュメント(有名なのは<div id="root"></div>だけ)とJavaScriptのバンドルを返し、ブラウザがそのJavaScriptを実行してDOMを構築します。これに対し、サーバーレンダリングされたページ(WordPress、Railsアプリ)では、完全なHTML — コンテンツ、見出し、リンク — が最初のレスポンスで届きます。

したがって、すべてを決定する質問は次のとおりです。JavaScriptが実行される前の生のHTMLには何が含まれているか? デフォルトのReactアプリの場合、答えは「ほとんど何もない」です。CRAアプリで右クリック → ソースの表示をすると、シェルは見えますが、コンテンツは見えません。これがまさにクローラーが最初のフェッチで取得するものです。

責任が実際にどこにあるかを正確に言うと、Reactライブラリ自体はCSR専用ではありません。React DOMには、クライアントレンダリング(createRoot)、サーバーレンダリング(ストリーミングおよび静的API)、ハイドレーションAPIが含まれており、ライブラリはこれらすべてをサポートしています。空のシェルの問題は、デフォルトのツールチェーン(Create React App、サーバーなしのVite + React)の特性であり、クライアントAPIのみを配線し、サーバーでHTMLをレンダリングするものは何もありません。ツールチェーンをNext.js、Remix、またはReact独自のサーバーレンダリングAPIに切り替えると、同じライブラリが最初のレスポンスで完全なHTMLを配信します。

これは、より広範なJavaScript SEO問題へのReact固有の適用です。一般的な障害モード(パリティ、インタラクション、状態、タイミング)については、そちらを参照してください。ここでは、Reactに固有の点とその修正方法に焦点を当てます。

Googleが実際にReactアプリを処理する方法

GoogleはJavaScriptを3つのフェーズで処理します:クロール → レンダリング → インデックス。GooglebotがURLをフェッチし、レンダリングされたDOMは後でWebレンダリングサービス(WRS) — Chromeと同じエンジンである常緑のChromium — によって構築され、その後、レンダリングされた出力がインデックスされ、そのリンクが抽出されます。 Evidence for this claim Google processes JavaScript pages through crawling, rendering, and indexing using its Web Rendering Service. Scope: Google Search rendering behavior. Confidence: high · Verified: Google: JavaScript SEO basics

重要なニュアンスは、レンダリングがいつ行われるかです。レンダリングはリソースを大量に消費するため、初期クロールとは別にキューに入れられます。Martin Splittはこの流れを明確に説明しています:「HTTPリクエストを行い、何かが返ってきます… いくつかの骨組みだけのHTMLで、それが行うのはJavaScriptをロードして実行することだけです。その後、このHTMLは… レンダリングに入ります。レンダリングはJavaScriptを実行します — ブーム!以前は存在しなかった多くのコンテンツが発生します。」 CSR Reactページの場合、その「ブーム」がページ全体です — そのレンダリングステップが実行されるまで、そのどれも存在しません。

持ち運ぶ価値のある注意点: 古い「2つのウェーブのインデックスモデル」に過度に依存しないこと。 Splitt自身もそれを撤回し、そのウェーブを*「過度な単純化」*と呼んだ。実用的な takeawaysは「正式なWave 2が定義されたタイミングで存在する」ということではなく、レンダリングが 明確で、延期可能で、失敗しうるステップであり、CSRはコンテンツの100%をその間違った側に置くということだ。

Reactアプリに特に影響するレンダラーの事実がさらに2つある:

  • ステートレスである。 Googlebotはページ読み込み間でlocalStoragesessionStorage、または クッキーを保持しない。クライアント側の状態に依存するコンテンツやルーティングは クローラーには見えない。
  • 諦めることがある。 レンダラーはタイムアウトを強制する。メインコンテンツの読み込みが遅い場合 — 大きなバンドル、APIコールのウォーターフォール — レンダリングはコンテンツが到着する前に完了し、 Googleは不完全なページをインデックスする。

レンダリングタイムアウトの罠(そしてなぜ重複を生むのか)

この失敗モードはほとんど明確に説明されておらず、Reactアプリにとって最も有害なものです。 Gary Illyesはそれを直接説明しました: 「私の受信箱には、中心となるコンテンツの読み込みに 永遠に時間がかかり、レンダリングがタイムアウトしたというメールがたくさんあります…そして 私たちはボイラープレートだけのページを大量に残されました。ボイラープレートだけでは、 それらのページは重複です。」

それがCSR Reactアプリにとって何を意味するかを考えてみましょう。ヘッダー、ナビ、フッターは 速く読み込まれるボイラープレートです。実際のページコンテンツ — 各URLをユニークにする部分 — は JavaScriptによって取得・レンダリングされ、読み込みが遅いです。レンダリングがタイムアウトします。 GoogleはすべてのURLでヘッダー+ナビ+フッターだけを残されます。今やすべてのページが 同一に見え、GoogleはそれらをSearch Consoleで互いの重複としてマークします。

Illyes自身の修正は実用的な部分です: 「コンテンツ(わずかなボイラープレートを含む)が最初に 読み込まれるようにjs呼び出しを再構築してみて、それが役立つかどうか確認してください。」 しかし、より 耐久性のある答えは、メインコンテンツをレンダリングステップに依存しないことです — つまり SSRまたはSSGです。

Reactのレンダリング戦略

これは最も影響力のある単一の決定です。SEOにとって、おおよそ最悪から最良へのオプション:

  • CSR(デフォルトのReact)。 サーバーはシェルを送信し、ブラウザがすべてを構築します。コンテンツは レンダリングキューによって遅延され、タイムアウトにさらされます。SEOには最悪。 インデックスされたくない認証済みダッシュボードには問題ありません。 Evidence for this claim Client-only React rendering constructs UI in the browser; server rendering APIs produce HTML before browser hydration. Scope: React rendering mechanics; SEO impact depends on what the initial response contains. Confidence: high · Verified: React: hydrateRoot React: Server APIs
  • プリレンダリング。 完全なSSRフレームワークなしのビルド時レンダリング — react-snapや プリレンダーサービスなどのツールがアプリをクロールし、静的HTMLを保存します。軽量で、 よりシンプルでほぼ静的なサイトに適しています。
  • SSG(静的サイト生成)。 デプロイ時に一度HTMLを構築し、静的ファイルとして提供します。 最速で、コンテンツは常に生のHTMLに存在します。高度に動的またはユーザーごとのコンテンツには 制限があり、大規模サイトではビルドが遅くなります。
  • SSR(サーバーサイドレンダリング)。 サーバーがリクエストごとにReactを実行し、完全なHTMLを送信します。 コンテンツはクローラーに即座に利用可能で、常に新鮮です。Node.jsサーバーとわずかに高いTTFBが必要です。
  • ハイブリッド/ISR(インクリメンタル静的再生成)。 静的ページをバックグラウンドで再生成するNext.jsの機能 — 静的な速度と定期的な新鮮さを兼ね備えています。
戦略初期HTMLにコンテンツがあるか?SEOリスク最適な用途
CSR(生のReact)いいえ最高ログイン済みダッシュボード、インデックスされないアプリ
プリレンダリングはい(ビルド時)小規模でほぼ静的なサイト
SSGはい(ビルド時)最低ブログ、ドキュメント、マーケティング
SSRはい(リクエストごと)新鮮で動的なコンテンツ
ISR/ハイブリッドはい毎時/毎日変わるコンテンツ

そして、新しいビルドで避けるべき戦略の1つが動的レンダリングです。クローラーのユーザーエージェントを検出し、ユーザーにはCSRを提供しながら、クローラーには事前レンダリングされたバージョンを提供します。Googleは現在これを*“a workaround and not a long-term solution”(回避策であり、長期的な解決策ではない)と呼び、“creates additional complexities and resource requirements”*(追加の複雑さとリソース要件を生み出す)と述べ、代わりにサーバーサイドレンダリング、静的レンダリング、またはハイドレーションを推奨しています。(Bingは2018年に動的レンダリングを推奨していましたが、そのガイダンスは古くなっています。2019年以降、BingbotはMicrosoft Edge / Chromiumを介してレンダリングするため、SSR/SSGがそこでも正しい選択です。)

ここで否定すべき迷信があります。SSRはランキング向上にはなりません。John Mueller氏が述べたように、“there are no SEO ranking bonuses for implementing it one way or another”(どちらの方法で実装してもSEOランキングのボーナスはありません)— 異なるレンダリング方法は*“just different ways of making the content indexable”*(コンテンツをインデックス可能にするための単なる異なる方法)にすぎません。SSRの価値は、信頼性の高いインデックス可能性(そして多くの場合、より速いFirst Contentful Paintによるより良いCore Web Vitals)であり、魔法のようなランキングのレバーではありません。

ハイドレーションは完全に一致する必要があります — それはSEOテクニックではなく、バグの境界です

SSRとSSGはどちらも、ブラウザにすでにコンテンツが含まれるHTMLを渡します。Reactはその後、クライアント側でそのマークアップにアタッチする必要がありますが、これはプレーンなクライアントレンダリングとは異なるAPIです:

  • createRoot は、既存のマークアップを期待せずに、ゼロからDOMノードにReactをレンダリングします。CSRのみのアプリに使用します。
  • hydrateRoot は、react-dom/server がすでに生成したHTMLにReactをアタッチし、クライアントの最初のレンダリングがサーバーが送信したものと同一の出力を生成することを期待します。SSR/SSGを使用している場合は、createRoot ではなく hydrateRoot が必要です。サーバーレンダリングされたマークアップで createRoot を呼び出すと、Reactはそれを破棄してゼロから再レンダリングし、SSR/SSGを設定して得たまさにそのSEOの利点を捨ててしまいます。
Evidence for this claim hydrateRoot attaches React to HTML previously generated by React on the server; the initial client output should match the server output. Scope: hydration Confidence: high · Verified: hydrateRoot

サーバーとクライアントの出力の不一致は、SEO修正を行うReactアプリでは現実的なリスクです。タイトル内の Date.now()、ロケール依存の形式、if (typeof window !== 'undefined') ブランチなどです。React自身のドキュメントは、そのときに何が起こるかについて率直です。開発中は不一致について警告しますが、“there are no guarantees that attribute differences will be patched up in case of mismatches”(不一致の場合に属性の違いが修正されるという保証はありません)。ガイダンスは、不一致をバグとして扱い、修正することです。警告を抑制してコンテンツの同等性を想定することではありません。SEOに特化して言えば、ページがブラウザで正しく見えるからといって、レンダリングされたコンテンツとメタデータがサーバーが送信したものと一致するとは想定しないでください。クリーンなコンソールを信頼するのではなく、サーバーのHTMLをハイドレーション後のDOMと直接差分比較してください(以下のテストセクションのView SourceとInspect Elementのチェックは、これを高速に行う方法です)。

React RouterとURL構造

React Routerは、サーバーへの往復なしでブラウザ内のナビゲーションを処理します。これは、正しく設定されていればSEOに問題ありません:

  • History APIを使用し、ハッシュルーティングは使用しないでください。 BrowserRouterpushState を使用し、クリーンでクロール可能なURL(/products)を生成します。HashRouter/#/products を生成し、GoogleはハッシュベースのURLを確実に解決できません。それらを機能させていた古いAJAXクローリングスキームは非推奨です。History APIを使用してください。
  • サーバーもそれらのURLを処理する必要があります。 History APIルーティングでは、すべての「ページ」にサーバーが応答できる実際のURLが必要です。これはSSRにとって重要であり、/products への直接アクセスやリフレッシュが404にならないようにするために必要です。
  • <Link> は実際のアンカーをレンダリングします。 React Routerの <Link> コンポーネントは <a href> を出力し、これはクロール可能です。アンカーなしの onClick ハンドラーに基づくナビゲーションはクロールできません。Googleは実際の <a href> リンクのみをフォローします。

メタデータの管理:react-helmet、react-helmet-async、React 19のネイティブタグ

React 18までは、Reactはルート変更時にネイティブにドキュメントの<head>を更新することはありませんでした。各ルートの<title>、メタディスクリプション、canonical、Open Graph / Twitterタグはすべてライブラリで設定する必要がありました。React 19でそれが変わりました: コンポーネントは<title><meta><link>タグを直接レンダリングでき、Reactがそれらを<head>に自動的に引き上げます。クライアント専用アプリ、ストリーミングSSR、Server Componentsのいずれでも機能します。React 19.2は2026年半ば時点での現在の安定版リリースであり、これは現在のReactバージョンのあらゆるアプリに適用されます。

つまり、正しい答えはReactのバージョンと実際に必要なものによって異なります:

  • React 19、スタンドアロンアプリ、基本的なタグのみ必要な場合。 コンポーネント内で<title>/<meta>/<link>を直接レンダリングします。ライブラリは不要です。
  • React 19だが、htmlAttributes/bodyAttributes、SSRのcontextシリアライゼーション、onChangeClientStateprioritizeSeoTags、またはtitleTemplateが必要な場合。 ネイティブの引き上げではこれらをカバーできません。react-helmet-asyncを使用してください。その公式ドキュメントもこれを直接指摘しています: これらの特定のニーズがなければ、React 19ではパッケージがまったく不要な場合があります。
  • React 18以前、スタンドアロンアプリの場合。 ネイティブの引き上げはまだ存在しません。react-helmet-asyncを使用してください。これは積極的にメンテナンスされており(メジャーバージョン3、実行時にReactバージョンを検出)、SSRをサポートしています。
  • 元のreact-helmet どのReactバージョンでも使用しないでください。メンテナンスされておらず(2020年以降リリースなし)、React 18の並行レンダリング下で既知のバグがあります。
  • Next.jsアプリの場合。 Reactのバージョンに関係なく、Next独自のMetadata API(App Routerのmetadataエクスポート/generateMetadata)を使用してください。Helmetを追加したり、ネイティブのReactタグ引き上げに依存したりしないでください。Next.jsアプリではフレームワークがドキュメントを所有します。

JavaScript SEO全般から引き継がれる信頼性のルールが1つあり、上記のどれを使用する場合でも適用されます: HTMLレベルのメタデータはJSで注入されたメタデータよりも優れています。クライアントサイドのJavaScriptで注入されたcanonicalタグは、サーバーレンダリングされたHTMLに存在するものよりもはるかに信頼性が低くなります。これもSSR/SSGを支持するもう一つの論拠です。

AIクローラーがこれを緊急にしている

2026年の複雑な点: GPTBot(OpenAI)、ClaudeBot(Anthropic)、PerplexityBot、その他のエージェントのレンダリング動作は、プロバイダーとバージョンに固有です。CSR Reactアプリは、最初のGooglebotフェッチが見るのと同じ空のシェルをすべてのクローラーに送信します。現在のプロバイダードキュメントでは、それを埋める共有レンダリングステップは確立されていません。生成エンジンがより大きな発見サーフェスになるにつれて、SSR/SSGはGoogleだけの関心事ではなくなります: 生のHTMLは、普遍的なクローラーの制限を想定せずにカバレッジを最大化します。(ヘッドレスCMSのトピックでは、このAIクローラーの現実についてより詳しく説明しています。)

Googleが実際に見ているものをテストする

ブラウザを信頼しないでください。DevToolsインスペクタはレンダリングされたDOM(JavaScript実行後)を表示します。これは、JSなしのクローラーが見ないものとまったく同じです。適切なツールを使用してください:

  • ソースの表示と要素の検査。 ソースの表示は生のHTML(JSの前にクローラーが取得するもの)です。要素の検査はレンダリングされたDOMです。コンテンツが要素の検査にはあるがソースの表示にはない場合、それはJavaScript依存です。
  • URL検査ツール(Search Console) — 最も権威のあるチェックです。ライブテストを実行し、レンダリングされたHTMLスクリーンショットページリソース/コンソールメッセージを確認して、Googleが実際にレンダリングしたものと読み込みに失敗したものを確認します。
  • リッチリザルトテスト — サイトを検証せずにレンダリングされたHTMLをすばやくチェックします。
  • DevToolsでJavaScriptを無効化して再読み込みします。JSを実行しないクローラーの高速シミュレーションです(そしてAIクローラーが見るものの適切なプロキシでもあります)。
  • Search Consoleのカバレッジレポート — 「検出済み、現在インデックス未登録」はレンダリングキューのバックログを示す可能性があります。重複ページのクラスターは、レンダリングタイムアウトのボイラープレートトラップを示す可能性があります。
  • JSレンダリングクローラー — Ahrefs Site AuditとScreaming Frog(JSレンダリングモード)はページを大規模にレンダリングするため、サイト全体で生のHTMLとレンダリング後のHTMLを比較できます。

Next.js と Remix(実践的な答え)

SEO が重要で、生の CSR React を使っているなら、サーバーでレンダリングするフレームワークへの移行が通常は正しい選択です。Next.js はこのために作られています — SSR と SSG が標準で、ISR、App Router、組み込みの Metadata API、自動コード分割、画像最適化を備えています。Remix はウェブ標準の代替で、fetch/Request/Response を基盤とし、SSR がデフォルトで、プログレッシブエンハンスメントに強いという特徴があります。Next.js は別途詳しく説明します — ここでは意図的に簡潔にしています。React SEO の要点はもっと狭い範囲です:フレームワークは、コンテンツをブラウザのみのレンダリングステップから初期 HTML に移すために存在します。

React は、レンダリングを後付けではなくアーキテクチャ上の決定として扱う場合、SEO に適しています。ランキングが必要なものには SSR または SSG を選び、リンクとルーティングを正直に保ち、ルートごとにメタデータを管理し、ブラウザではなく Google 自身のツールに、実際にレンダリングされたものを確認させましょう。

Add an expert note

Pin an expert quote

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