Domain 19 / 225
JavaScript SEO はクロール → レンダリング → インデックスの 3 段階で動く
JavaScript SEO の要点
Google は JavaScript を 3 段階(クロール → レンダリング → インデックス)で処理する。レンダリングまで数秒〜数日待つことがあり、CSR で初期 HTML が空のページはインデックス遅延の原因。canonical / title は HTML に書くのが最も確実、SSR が推奨
なぜこれを学ぶか
JavaScript SEO は SPA / 大規模 React アプリで「インデックスされない」事故が最も多い領域。 Googlebot は JS を実行するが、レンダリング段階で待たされたり失敗したりすると、せっかくのコンテンツが SEO 評価対象にならない。
Next.js / Remix / Nuxt / SvelteKit など現代フレームワークの SEO 設計では必須知識。
学ばないと起きること
| よくある事故 | 被害 |
|---|---|
| 完全 CSR の SPA で初期 HTML が空 | レンダリング遅延でインデックスが数日〜数ヶ月遅れる |
| クライアント側で canonical を後から書き換える | 元 HTML の canonical と矛盾、Google が正規 URL を判定不能 |
| meta description / title を JS で動的設定して初期 HTML に書かない | レンダリング失敗時にスニペットが取れない |
<a routerLink> のような独自属性で内部リンクを書く | Googlebot が認識せず、クロール経路が途絶える |
JavaScript リダイレクト(window.location)でルーティング | レンダリング失敗で Google が認識できないことがある |
| ユーザー操作(クリック)で初めて読み込まれるコンテンツ | Googlebot は操作しないので評価対象外 |
動的に挿入する内部リンクが <a href> 形式でない | リンクが認識されず、サイト内のクロール経路が壊れる |
学ぶメリット
- React / Next.js / Vue などの SPA / SSR 設計で SEO 観点を組み込める
- インデックスされない問題を「クロール / レンダリング / インデックス」のどこで止まっているか切り分けられる
- 商談で「JS SEO の 3 段階」を即答できる
- URL 検査ツールで Googlebot レンダリング結果を確認できる
仕組み
Google の JavaScript 処理 3 段階
Google が JS ページを処理するパイプライン:
| 段階 | 処理内容 |
|---|---|
| 1. クロール | URL のキューから Googlebot が HTTP リクエスト、HTML を取得 |
| 2. レンダリング | 取得した HTML を Headless Chromium で JS 実行、最終 DOM を生成 |
| 3. インデックス | レンダリング後の HTML から内容を解析、インデックスに格納 |
公式: 「すべての 200 OK ページがレンダリングキューに入る」(noindex を除く)
レンダリング待ちは数秒〜数日
Google のレンダリングリソースには制約があり、ページがキューに入ってから処理されるまで 数秒〜数日かかることがある(公式表現)。 完全 CSR で初期 HTML に主要コンテンツがないと、この遅延の影響を直接受ける。
Googlebot は最新 Chromium
公式: Googlebot は evergreen 版の Chromiumを使用。 最新の Web 技術はほぼ動作するが、実行できない / してくれない API もある。
不可:
- 自動的に許可を求めるブラウザ API(位置情報 / カメラ / 通知)
- 永続化(localStorage / sessionStorage はリクエストごとに初期化)
- WebSocket / WebRTC / Service Worker(リクエスト間で状態保持しない)
可能だが注意:
- 大量の JS 実行でレンダリングが遅延
- 巨大なバンドルサイズはレンダリングキューで待たされる
クロール / リンク発見
公式: 「JavaScript で動的にリンクを挿入しても OK、ただし <a href> 形式であること」
<!-- Googlebot が認識する -->
<a href="/products/dress">商品ページ</a>
<!-- Googlebot が認識しない -->
<a routerLink="/products/dress">商品ページ</a>
<span onclick="goto('/products/dress')">商品ページ</span>
<button onclick="navigate('/products/dress')">商品ページ</button>
JS で挿入するリンクも、最終的に <a href> の形式であれば認識される。
キー概念
canonical を JS で設定する時の注意
公式: HTML で canonical を書くのが最も確実。JS で書く場合の注意:
- JS で canonical を変える場合、元 HTML と同じ URL を指定する
- 元 HTML の canonical を JS で別 URL に書き換えるのは避ける
- HTML に canonical を書けないなら、JS のみで設定する(HTML には書かない)
矛盾を避けるのが原則。
title / meta description も同様
JS で動的設定は可能だが、初期 HTML に書くのが安全。 SPA で URL ごとに違う title を設定する場合、SSR または事前レンダリングが推奨。
lazy-loading の正しい使い方
OK パターン:
<!-- スクロール連動 lazy-load: Googlebot が処理する -->
<img src="article.jpg" loading="lazy" alt="...">
NG パターン:
<!-- ユーザー操作(クリック)を要求: Googlebot は操作しないので無視 -->
<button onclick="loadContent()">続きを読む</button>
ユーザーアクションを必要とする lazy-load の主要コンテンツは SEO 評価対象外。 intersection observer を使ったスクロール連動 lazy-load なら OK。
Web Components(Shadow DOM)
カスタム要素を使う場合:
- ライト DOM の中身は通常通りインデックスされる
- Shadow DOM の中身も Google は基本的に認識する
- スロット(
<slot>)使用時は内容が正しく結合されるかテスト
URL 検査ツールでレンダリング結果を確認するのが確実。
互換性のあるコードを書く
Google は polyfill を要求しない。差分配信(differential serving)と機能検出を組み合わせるのが推奨。
if ('IntersectionObserver' in window) {
// モダン実装
} else {
// フォールバック
}
ポリフィルできない API もあるので、ドキュメントを確認する。
よくある誤解
| よくある誤解 | 実際のところ | 出典 |
|---|---|---|
| Googlebot は JavaScript を実行できない | 最新 Chromium で実行する。ただしレンダリング遅延に注意 | JavaScript SEO の基本 |
| 完全 CSR でも問題なくインデックスされる | 初期 HTML が空だとレンダリング待ちでインデックス遅延 | 同上 |
| canonical / title は JS で動的設定が一番柔軟 | HTML で書くのが最も確実、JS で書き換えるのは推奨されない | 同上 |
<a routerLink> でも Google は内部リンクとして処理 | しない。<a href> 形式が必要 | リンクのベスト プラクティス |
| JavaScript リダイレクト(window.location)も 301 と同じ評価 | レンダリング失敗で Google が認識できないリスク、サーバーサイドリダイレクトが推奨 | リダイレクト |
| クリックで読み込む lazy-load も Google が拾う | 拾わない。ユーザーアクション要求の lazy-load は対象外 | lazy-loading |
| Googlebot は localStorage / Cookie を持続できる | 持続しない。リクエストごとに初期化される | JavaScript SEO の基本 |
URL フラグメント(#/path)で SPA ルーティングして OK | NG。Google はフラグメントを基本サポートしない、History API を使う | 同上 |
実務での適用
Next.js / Remix / Nuxt の SEO 設計
公式推奨は SSR(サーバーサイドレンダリング)または静的生成(SSG)。
| レンダリング方式 | SEO 評価 |
|---|---|
| SSR(サーバーサイドレンダリング) | 推奨。初期 HTML に主要コンテンツが入る |
| SSG(静的生成) | 推奨。ビルド時に HTML 生成 |
| ISR(インクリメンタル静的再生成) | OK。SSG の動的更新版 |
| CSR(クライアントサイドのみ) | 非推奨。レンダリング待ちでインデックス遅延 |
canonical の正しい設定例(Next.js)
// HTML(Server Component)で書く
export const generateMetadata = ({ params }): Metadata => ({
alternates: {
canonical: `https://example.com/products/${params.slug}`,
},
});
JS で動的に書き換えるのは避ける。
内部リンクは必ず <a href> で
// OK(Next.js Link コンポーネント)
import Link from "next/link";
<Link href="/products/dress">商品ページ</Link>
// 内部実装が <a href> なので Google が認識する
// NG(onClick だけのナビゲーション)
<button onClick={() => router.push("/products/dress")}>商品ページ</button>
URL 検査ツールでレンダリング確認
Search Console の URL 検査で:
- URL を入力 → ライブテスト
- 「レンダリング済みの HTML」を確認
- 主要コンテンツが入っているか確認
- 内部リンクが
<a href>で出力されているか確認
これで Googlebot が見ている内容を確認できる。
トラブル別の対処
| 症状 | 確認すべきこと |
|---|---|
| 公開したページがいつまでもインデックスされない | URL 検査でレンダリング結果確認、初期 HTML が空でないか |
| canonical が正しく認識されていない | HTML と JS で矛盾していないか、URL 検査で実際の認識結果確認 |
| 内部リンクが Google に発見されない | <a routerLink> などカスタム属性を使っていないか |
| SPA のページが部分的にしかインデックスされない | History API でルーティングしているか、各ルートで個別 URL になっているか |
公式ソース
- JavaScript SEO の基本
- Search の JavaScript 問題のトラブルシューティング
- 動的レンダリング
- lazy-loading コンテンツのベスト プラクティス
- リンクのベスト プラクティス
自己テスト
Q1. Googlebot は JavaScript を実行できるか?
実行できる。最新 Chromium(evergreen)を使用。 ただしレンダリングまで数秒〜数日待つことがあるので、完全 CSR は SEO 上不利
Q2. Google の JavaScript ページ処理 3 段階は?
クロール → レンダリング → インデックス。 クロールで HTML 取得、レンダリングで JS 実行、インデックスで内容解析・格納
Q3. canonical を JS で設定するのは推奨されるか?
HTML で書くのが最も確実。 JS で書き換える場合は元 HTML と矛盾しないこと。HTML に書けないなら JS のみで設定(HTML には書かない)
Q4. a routerLink= の独自属性を Google は内部リンクとして認識するか?
しない。<a href> 形式である必要がある。
JS で動的に挿入する場合も最終的に <a href> の形になっていれば OK
Q5. クリックで初めて読み込まれる lazy-load コンテンツは Google に拾われるか?
拾われない。ユーザーアクション(クリック / タップ / スワイプ)を必要とする lazy-load は SEO 評価対象外。 スクロール連動 lazy-load なら OK
Q6. SPA で URL フラグメント(`#/path`)でルーティングしてよいか?
NG。Google は基本的にフラグメントをサポートしない。 History API を使ったクリーン URL ルーティングが必須
Q7. JavaScript リダイレクト(window.location)の SEO 評価は?
Google は実行して認識するが、レンダリング失敗で気づかれないリスクがある。 サーバーサイドリダイレクト(301)が推奨
Q8. SPA で SEO に強い構成は?
SSR(サーバーサイドレンダリング)または SSG(静的生成)。 初期 HTML に主要コンテンツが入る形が SEO 上有利。 完全 CSR はレンダリング遅延の影響を直接受ける
これらの内容を採点付きで挑戦したい場合は、本ドメインのプロ試験で 5 問形式で確認できる。