React サイトが Google にインデックスされないのはなぜか
ほぼ確実に、クローラーが受け取るページとあなたが見ているページが別物だからです。ブラウザ側で描画する React アプリは、ほぼ空の HTML の枠だけを返し、中身は JavaScript で埋めます。Google はその JavaScript を実行しますが、クロール時ではなく後続のパスで実行します。最初のパスで決まること — そのページが重複か、正規 URL はどれか、どの言語版が対応するか — は、すべてその空の枠の上で決まります。ですから何かを直す前に、ブラウザが描画した画面ではなく、サーバーが実際に返している生の HTML を読んでください。
クローラーが受け取るページは、あなたが見ているページではない
本番サイトを開き、検証ではなくソースを表示を選んでください。検証は JavaScript が動いたあとの DOM を見せますが、ソース表示はサーバーが実際に送ったバイト列を見せます。クライアント描画の React アプリでは、それはたいていタイトル、いくつかの link タグ、空のコンテナ要素、そしてスクリプトのバンドルだけです。クローラーが最初に読むのはこの文書であり、公開して間もないサイトでは、しばらくの間これが唯一読まれる版になることもあります。
Google は JavaScript を段階に分けて扱うと明言しています。URL をクロールし、描画待ちの列にページを入れ、返ってきたものをインデックスする — そして描画は即時ではなく先送りされます。ここから二つの帰結が出ます。ひとつは分かりやすいほうで、バンドルが動いて初めて存在する内容はインデックスが遅れ、そもそも入らないこともある、というものです。もうひとつは自然に解消しないぶん厄介です。最初の応答からしか読まれない信号がいくつかあり、あとから描画してもそれらは救われません。
いちばん分かりやすいのが正規化タグです。Google 自身の案内では、正規リンク要素は文書のヘッド内に置くものとされ、言語版どうしを結ぶ hreflang の注釈も同じです。フレームワークがあとから — 本文側に、あるいはヘッドを送り終えたあとに — 挿入するタグは、判断が下された時点では存在しなかったタグです。ブラウザはそれでも適用するので、画面上は正しく見えます。ただ、あなたが考えを変えたかった唯一の読み手には間に合っていないのです。
Google が実際に受け取ったものを確かめる
所要は二十分ほどで、書き直しに手をつける前に決着がつきます。プレビューではなく本番 URL に対して行ってください。
- 生の応答を読む。 curl で取得するか、ソースを表示します。返ってきたものに二つ問いを立ててください。狙っている語句を含む本文がこのテキストの中にあるか。正規化タグは文書の下のほうではなく head 要素の中にあるか。どちらかが「いいえ」なら、原因はもう見つかっています。
- Search Console では、ライブテストではなくクロール済みページを読む。 URL 検査は両方を見せます。ライブテストはその場で取り直した新しい取得結果で、クロール済み HTML は前回実際に保存されたものです。両者が食い違うときはクロール済みのほうを信じてください。その食い違い自体が発見です。
- 下層ページの URL を直接叩く。 クライアント側のルーターは、サーバーが返せない経路を作ってしまうことがあります。下層ページを新しいタブで開くか curl で取得し、トップページへリダイレクトしたり、何も見つからないと言いながら成功を返したりせず、そのページ自身の内容を返すことを確認します。
- 配信しているホストが三つではなく一つであることを確かめる。 www あり、www なし、そして暗号化なしの形式をそれぞれ取得します。三つのうち二つは残りの一つへリダイレクトするはずです。複数がサイト全体を返すなら、同じサイトを二つの住所で公開して、どちらを選ぶかを Google に委ねていることになります。
自社のテストから隠れていた不具合
私たちは AgentCeres — AI Growth Officer を agentceres.com で React のフレームワーク上に公開しており、この問題の一種で数か月分のインデックスを失いました。行ったどの点検も「健全」と答えていたからです。全部を書く価値があります。どの段階も、成功に見える形で失敗していました。
Search Console は、当社のかなりの数のページを「ユーザー指定の正規 URL がない重複」と報告しました。つまり信頼できる正規化タグが見つからず、自分で選んだということです。タグ自体はありました。応答のおよそ四十キロバイト地点にあったのです。フレームワークが動的に描画するページではメタデータをストリーミングで送るのに対し、head 要素は先頭からおよそ一・五キロバイトの地点で閉じていました。ブラウザはすべて適用していました。最初のクロールだけが見ていなかったのです。
そもそもそれらのページが動的だった理由が、二つ目の不具合でした。ビルド時に事前生成されているはずの十数本の経路が、黙って対象から外れていたのです。共有のヘッダーコンポーネントがリクエストヘッダーを読む翻訳ヘルパーを呼んでおり、リクエストヘッダーを読むだけでページは動的になります。ビルド自身の経路一覧は、それらを静的として表示し続けていました。生成された HTML ファイルの一覧には、どれも入っていませんでした。要約と成果物が食い違っており、私たちは要約のほうを読んでいたわけです。
三つ目こそ持ち帰る価値があります。メタデータをストリーミングするフレームワークは、従来どおり待って返すクローラーの一覧を持っていることが多く、当社のものも既定でその一覧を備えていました。Googlebot はそこに入っていませんでした。ライブテストのボタンの裏で動く Google の検査ツールのほうは入っていました。つまり、作業を確認するために押していたボタンは毎回よい版を取得し、通常のクロールは壊れた版を受け取り続けていたのです。検証の道具が自社のスタック内で特別扱いされているなら、それは検証ではありません。
安く済む補足を二つ。当社の www ホストはリダイレクトせずサイト全体を返しており、Google はそれを二つ目の複製としてインデックスし、サイトマップに載せた住所のほうを格下げしていました。ミドルウェアの二行で解決しました。もうひとつ、クローラーごとの設定に手を伸ばしたくなったら、オリジンの前段にある CDN は誰が要求したかを見ずにキャッシュするのが普通だ、と思い出してください。キャッシュに載った版が次のクローラーに渡ります。CDN の背後では、特定のクローラーだけを別扱いする規則は当てにできません。
効く順に、何を変えるか
- 見つけてほしいページは事前生成する。 マーケティングページ、ドキュメント、見知らぬ人が検索しうるものは、ビルド時に HTML を生成します。静的な出力は問題そのものを回避します。最初のパスに本文もタグも揃っているからです。
- 本当に動的でなければならないものはサーバー側で描画する。 リクエストに依存するページでも完全な HTML は返せます。重要なのは事前に計算されたかどうかではなく、最初の応答が完成しているかどうかです。
- タイトル・説明・正規化・言語のタグは、その最初の応答のヘッドに置く。 フレームワークがそれらを先送りできるなら、止める設定を探し、描画後の DOM ではなく生の HTML を読んで直ったことを確かめます。ここは「もうやった」と思い込まれやすい工程です。
- 各ページに本物の URL と、そこへの本物のリンクを与える。 フラグメントやクリックハンドラーの裏にある経路はクロールできません。クローラーは href を持つアンカー要素をたどるので、ボタンで組んだナビゲーションは Google が歩けないナビゲーションです。
- ホストを一つ選び、残りはリダイレクトする。 そのうえで、選んだ形式だけを載せたサイトマップを送信し、自分の宣言どうしが矛盾しないようにします。
これは順位を上げる戦略ではありません。戦略の前提条件であり、二度と考えなくて済むように半日で片づける価値があります。ページが本当に読まれるようになったあと、成果を左右する問いは まともなページなのに流入がない理由 と 最初の訪問者が実際どこから来るか です。そもそもこの配信経路を自分で持ちたくないなら、静的サイトジェネレーターと Git ベースのエディター の組み合わせが構造的に描画問題を回避します。公開されるものが最初から完成した HTML だからです。
FAQ
- Google は JavaScript のサイトをそもそもインデックスするのか
- します。Googlebot は JavaScript を実行し、ページが最終的になった姿をインデックスします。ただしそれはクロール時ではなく先送りされたパスで行われるため、バンドルが動いて初めて存在する内容は、最初から HTML にある内容より遅く、確実性も低くインデックスされます。最初の応答からしか読まれない部分 — 正規化タグや hreflang の注釈など — は描画では救われません。クライアント描画は絶対的な障害ではなく、遅延とリスクを伴うもの、と捉えてください。
- 直すにはサーバーサイドレンダリングが必要か
- たいていは不要です。見知らぬ人が検索しうるページには静的な事前生成で十分ですし、サーバー描画より運用が簡単で安く済みます。サーバー描画は、内容が本当に「誰が見に来たか」に依存するページのために取っておいてください。効いてくる基準は手法の選択ではなく、最初の応答がすでに完成しているかどうかです。事前生成もサーバー描画もそれを満たし、クライアント描画は満たしません。
- Search Console のライブテストは問題なさそうなのに、なぜインデックスされないのか
- ライブテストはその場で行う取得と描画であり、あなたのスタックが通常のクロールとは別の応答をそこに返している場合があるからです。当社がまさにそうで、待って返すメタデータを受け取るクローラーの既定一覧に Google の検査ツールは入っていた一方、Googlebot は入っていませんでした。同じレポート内に保存されているクロール済み HTML のほうを読んでください。両者が食い違うとき、インデックスされているのはクロール済みの版であり、ライブテストは他の誰にも配信されていないページの話をしています。
Want this done for you?
AgentCeres is a managed AI marketing team — specialists draft the work, you approve what ships. 14-day free trial, from $39/month.