JavaScriptのSEO
検索エンジンがJavaScriptに依存するコンテンツをクロール、レンダリング、インデックス登録できるようにする方法を説明します。実際のリンク、パリティ、遅延読み込み、無限スクロール、soft-404s、テストを扱います。
言語
このページには証拠シグナルが1件あります
- 関連するライブツールRaw vs. Rendered HTML Checker
JavaScript SEOは、JavaScriptに依存するコンテンツを検索エンジンがクロール、レンダリング、インデックス登録できるかを扱います。GoogleはJSを実行できます。失敗モードはより具体的で、生とレンダリング済みのパリティ、インタラクション、ステートレスなレンダラーの状態、タイミングです。リンクは実際のアンカーにし、JS/CSSをブロックせず、ランキングに必要なコンテンツにはSSRや事前レンダリングを優先し、無限スクロールを監視してください。高いレンダリング用ビューポートによって2ページが1ページとしてインデックス登録されることがあります。
TL;DR — JavaScript SEOの核心は、検索エンジンがあなたのコンテンツを見られるかという1つの問いです。現代のサイトは、ページの多くをJavaScriptでブラウザー上に構築します。重要なテキストやリンクがスクリプト実行の後に初めて表示されるなら、Googleがそれでも到達できることを確認する必要があります。通常は到達できますが、問題は細部にあります。
JavaScript SEOとは何か
多くのサイトは、JavaScriptでページの一部(または全体)をブラウザー上に構築します。サーバーは一部のHTMLを送り、スクリプトが実行されてコンテンツを埋めたり、項目を追加で読み込んだり、ページ全体を再読み込みせずに表示を切り替えたりします。JavaScript SEOとは、検索エンジンがそのコンテンツを引き続きクロール、レンダリング、インデックス登録できるようにする実務です。
Googleでは、次の順番で処理が進みます。
- クロール — GoogleがURLの生HTMLをダウンロードします。
- レンダリング — GoogleがブラウザーでページのJavaScriptを実行し、完成したページを構築します(レンダリングの段階)。
- インデックス登録 — Googleが完成したページを読み取り、保存します。
Googleは、JavaScriptウェブアプリの処理における主な3段階としてこれらを文書化しています。
Evidence for this claim Google processes JavaScript web apps in three main phases: crawling, rendering, and indexing; without rendering, Google might not see JavaScript-provided content. Scope: Google Search's processing of JavaScript pages; successful rendering does not guarantee indexing or ranking. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basicsコンテンツがJavaScript実行後にしか現れない場合、Googleはそれを見る前にページを正常にレンダリングする必要があります。ほとんどの場合は実行されますが、実行されなければ、コンテンツが検索結果から静かに消えることがあります。
まずは良い知らせ
JavaScriptはSEOに悪いものではありません。Googleは最新のChromeを実行し、訪問者と同じJavaScriptを実行できます。「GoogleはJavaScriptを読めない」という昔の不安は、もう事実ではありません。
問題になり得る点は、もっと具体的です。
- クリックまたはスクロールしないとコンテンツが読み込まれず、Googleはクリックもスクロールもしません。 Evidence for this claim Google Search does not interact with a page, so lazy-loaded content should load when it becomes visible in the viewport rather than requiring user interaction. Scope: Google Search's documented rendering behavior for lazy-loaded content; other crawlers can behave differently. Confidence: high · Verified: Google Search Central: Fix lazy-loaded content
- リンクが本物のリンクではなく(ボタンやクリックハンドラーになっていて)、Googleがたどれません。 Evidence for this claim Google can reliably discover links only when they are HTML anchor elements with an href attribute. Scope: Link discovery by Google Search; this does not claim that every discovered URL will be crawled or indexed. Confidence: high · Verified: Google Search Central: Make your links crawlable
- JavaScriptまたはCSSのファイルを誤って
robots.txtでブロックしているため、Googleがページを正しくレンダリングできません。 - ブラウザーではページが正常に見えるのに、Googleのレンダリング済み表示にはコンテンツが現れません。
シンプルなチェックリスト
- 生HTML(右クリック→ページのソースを表示)とレンダリング済みHTML(Google Search ConsoleのURL検査ツール)を比較します。レンダリング済み表示に重要なコンテンツがなければ、そこが問題です。
- リンクが
<div>のクリックハンドラーではなく、実際の<a href>リンクであることを確認します。 - JavaScriptまたはCSSのファイルを
robots.txtでブロックしないでください。 - クリックやスクロールで読み込む機能があるなら、そのコンテンツへ別の方法でも到達できるようにします。
- 絶対にランキングさせたいコンテンツには、コンテンツがすでに生HTMLに入っているサーバーサイドレンダリングまたは静的/事前レンダリングを優先します。 Evidence for this claim Google describes server-side rendering or pre-rendering as a good idea because it makes a website faster for users and crawlers. Scope: Google Search guidance for JavaScript sites; the source does not prescribe one framework or guarantee indexing. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basics
さらに詳しく、実際の失敗モード、2ページが1ページとしてインデックス登録される無限スクロールの落とし穴、レンダリング済みHTMLのテスト方法を知りたいですか? Advancedタブへ切り替えてください。Googleのレンダラー自体の仕組みや、選ぶべきレンダリング構成については、レンダリングページを参照してください。
TL;DR — GoogleはJavaScriptを実行できるため、「GoogleはJSを読めるか」は正しい問いではありません。失敗モードは、パリティ(生DOMとレンダリング済みDOMの差)、インタラクション(Googleはスクロールもクリックもしない)、状態(レンダラーはステートレス)、タイミングです。リンクは実際の
<a href>アンカーにし、JS/CSSをブロックせず、インタラクションではなくビューポートで遅延読み込みし、クライアント側のnot-found状態には実際のステータスを返してください。また、生のnoindexはJavaScriptが削除する前にレンダリングを妨げることがあります。実際に処理されたディレクティブを組み合わせ、常に生の値かレンダリング済みの値が勝つとは考えないでください。無限スクロールには特に注意が必要です。高いレンダリング用ビューポートがローダーを起動し、2つのURLを1つのインデックス登録ページに結合することがあります。レンダラーの内部と選ぶべきレンダリングモードについては、レンダリングを参照してください。
GoogleはJavaScriptを読めるか? はい。ただし、そこが問いではありません
Three stages run left to right: crawl, render, and index. The render stage branches into four failure modes: parity, where the rendered DOM may not match expectations; interaction, where content requires a scroll or click; state, where content relies on cookies or storage that the renderer clears; and timing, where content is deferred behind slow JavaScript.
© Patrick Stox LLC · CC BY 4.0 ·
GoogleはJavaScriptアプリを3段階で処理します。“Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” (翻訳)「GoogleはJavaScriptウェブアプリを、クロール、レンダリング、インデックス登録の3つの主な段階で処理します」中央の段階では、常に更新されるヘッドレスChromeでJSを実行し、インデックス登録されるDOMを構築します。“Rendering is important because websites often rely on JavaScript to bring content to the page, and without rendering Google might not see that content.” (翻訳)「ウェブサイトはコンテンツをページに表示するためJavaScriptに依存することが多く、レンダリングなしではGoogleがそのコンテンツを見られない可能性があるため、レンダリングは重要です」
Evidence for this claim Google processes JavaScript web apps in three main phases: crawling, rendering, and indexing; without rendering, Google might not see JavaScript-provided content. Scope: Google Search's processing of JavaScript pages; successful rendering does not guarantee indexing or ranking. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basicsつまり、GoogleはJavaScriptを実行できます。役立つ問いは、もっと具体的です。
- パリティ — レンダリング済みDOMには、想定した内容が実際に入っていますか?
- インタラクション — Googleが行わないスクロールやクリックを要求するものはありませんか?
- 状態 — ステートレスなレンダラーが消去するCookieやlocalStorageに依存していませんか?
- タイミング — 重要なコンテンツが遅い、または遅れて実行されるJavaScriptの後ろに置かれていませんか?
タイミングについて言えば、Googleはクロールしたページ(200を返したページ)をレンダリング用にキューへ入れ、“the page may stay on this queue for a few seconds, but it can take
longer than that.” (翻訳)「ページはこのキューに数秒間とどまることがありますが、それより長くかかる場合もあります」としています。公開された固定の遅延時間やタイムアウトはありません。非200ステータスを返すページや、最初からnoindexディレクティブがあるページは、JavaScriptが変更するのを待たずにレンダリングキューをスキップすることがあります。
Googleがどのようにレンダリングするかという仕組み、つまりWeb Rendering Service、ステートレス性、キャッシュ、「2つのウェーブ」という神話については、レンダリングページで説明しています。ここでは実際の問題と修正に集中します。
リンクは実際の<a href>アンカーにする
これはJS SEOで最もよくあるバグです。“Google can only discover your links if
they are <a> HTML elements with an href attribute.” (翻訳)「Googleがリンクを発見できるのは、それがhref属性を持つ<a> HTML要素である場合だけです」クリック可能な<div>にonclickハンドラーを付けても、Googleにはリンクとして見えません。たどられず、その発見に依存するページはクロールされない可能性があります。JavaScriptでリンクを注入すること自体は問題ありませんが、レンダリング済みDOMで実際の<a href>アンカーになる必要があります。ただし、そのアンカーはJavaScript実行後に解析されます。レンダリング済みDOMに入れば発見可能になるだけで、URLがクロール、インデックス登録されることや、生HTMLにあるリンクと同じように扱われることまでは保証しません。
遅延読み込みとインタラクションで制御されたコンテンツ
レンダラーは好奇心のあるユーザーのようには動きません。“Google Search does not interact with your page.” (翻訳)「Google検索はページを操作しません」スクロールも、クリックも、ホバーもありません。そのため、これらのイベントでしか読み込まれないコンテンツは見られません。
Googleのガイダンスは、ユーザーが操作したときではなく、コンテンツがビューポートに入ったときに読み込むことです。“make sure that your lazy-loading implementation loads all relevant content whenever
it is visible in the viewport,” (翻訳)「遅延読み込みの実装が、関連するコンテンツをビューポートに表示されるたびにすべて読み込むようにしてください」、そして*“don’t add lazy-loading to content that is
likely to be immediately visible when a user opens a page.”* (翻訳)「ユーザーがページを開いたときすぐに表示される可能性が高いコンテンツには遅延読み込みを追加しないでください」としています。画像にはIntersectionObserverまたはネイティブのloading="lazy"を使い、スクロールやクリックのハンドラーは使わないでください。通常のレンダリング中にコンテンツが読み込まれるようにします。
無限スクロール:2ページが1ページとしてインデックス登録されるとき
A normal browser viewport stops after the first page, but Google's render viewport expands much taller. The expansion reaches an infinite-scroll trigger, fires the loader without a real user scroll, and appends the next page into the same DOM. Google then indexes both pages' content under one URL.
© Patrick Stox LLC · CC BY 4.0 ·
これはほとんど誰も説明していない点で、このセクション全体を割く価値があります。
Googlebotは、一般的なブラウザーウィンドウよりかなり高いビューポートでレンダリングすることがあります。Googleは正確なレンダリング用ビューポートのサイズを公開しておらず、変更されることもあるため、特定の数値を前提に設計せず、自分の実装をテストしてください。重要なのは仕組みです。無限スクロールのローダーがスクロール位置やビューポートの高さを基準に起動する場合、想定より高いレンダリング用ビューポートがレンダリング中にローダー自体を起動し、次の記事や商品ページのコンテンツを同じDOMへ追加することがあります。すると、異なる2つのURLのコンテンツが一緒にレンダリングされ、Googleが1ページとしてインデックス登録できます。私自身の経験では、“occasionally, two pages get indexed as one” (翻訳)「ときどき、2ページが1ページとしてインデックス登録される」。「インデックス未登録」と報告されたページが、実際には別のページ(通常はフィードの前の投稿)の一部としてインデックス登録されていたことがあります。その原因は、“when Google resized the viewport to be longer … it triggered the infinite scroll and loaded another article in when it was rendering.” (翻訳)「Googleがビューポートをより長くなるようにサイズ変更したとき、レンダリング中に無限スクロールが起動して別の記事を読み込んだ」ことでした。自分の設定でも起きるか、途中で止まるはずのページについてURL検査のレンダリング済みHTMLを確認してください。サイズを決めつけたり、安全だと決めつけたりしないでください。
これを正しく行うには、2つの層があります。
まず、無限スクロールを検索に適したものにします。 無限スクロールの下にページ分割読み込みを用意します。各チャンクには*“its own persistent, unique
URL,”* (翻訳)「それ自体の永続的で一意なURL」を持たせ、各URLのコンテンツは読み込むたびに同じにします。?date=yesterdayのような相対パラメーターは避け、“link sequentially to
the individual URLs so that search engines can discover the URLs in a paginated set,” (翻訳)「検索エンジンがページ分割されたセットのURLを発見できるよう、個々のURLへ順番にリンクする」ようにし、新しいチャンクをスクロールで読み込んだときは*“update the displayed URL using the
History API.”* (翻訳)「History APIを使って表示URLを更新する」ようにします。実際の<a href>ページ分割リンクと一意のURLを使い、ページ番号には*“don’t use URL
fragment identifiers”* (翻訳)「URLフラグメント識別子を使わない」でください(#の後ろの部分)。Googleはそれらを無視します。私のJavaScript SEOガイド で説明しているとおり、“if you have an infinite scroll setup, I still recommend a
paginated page version so that Google can still crawl properly.” (翻訳)「無限スクロールを設定している場合でも、Googleが適切にクロールできるようページ分割版を推奨します」。
**バグのあるローダーが実際にページを結合している場合、**最も速い修正は単純です。“block the JavaScript file that handles the infinite scrolling so the functionality can’t trigger.” (翻訳)「無限スクロールを処理するJavaScriptファイルをブロックし、機能が起動できないようにする」ローダーがレンダリング中に実行できなければ、次のページのコンテンツを追加できず、各URLは再び自分自身としてレンダリングされます。
クライアント側ルーティング後のsoft-404s
シングルページアプリはHTTPステータスコードを変更せずにコンテンツを切り替えられるため、「見つかりません」ビューでも200を返すことがあります。Googleは返されたコンテンツを評価した後に、そのレスポンスをソフト404と分類する可能性がありますが、静的な取得だけではGoogleがその分類を行ったことを証明できません。修正は2つあります。History APIで移動し、本当の未検出状態では実際の404ステータスを返すURLへルーティングするか、noindexタグを追加します。また、ルーティングにURLフラグメントへ依存しないでください。“the AJAX-crawling scheme has been deprecated since 2015, so
you can’t rely on URL fragments to work with Googlebot.” (翻訳)「AJAXクロール方式は2015年以降非推奨なので、URLフラグメントがGooglebotで機能することに依存できません」。
クライアント側リダイレクトにも同じ証拠上の問題があります。JavaScriptが実行されるまで、初期レスポンスは200のままになり得ます。Googleは、サーバー側リダイレクトやmeta refreshが不可能な場合の代替策としてのみJavaScriptリダイレクトをサポートしています。静的ステータスと、観測されたレンダリング後の遷移を別々に記録してください。監査でHTTPステータスを書き換えたり、レンダリング後のURL変更をすべてリダイレクトと呼んだりしないでください。
robots.txtでJavaScriptやCSSをブロックしない
Googleは、ブロックされたファイルやブロックされたページからJavaScriptをレンダリングしません。バンドル(またはその中にある/_next/、/static/、/assets/ディレクトリ)を拒否するrobots.txtルールは、レンダリングを完全に壊すことがあります。Googleはシェルを取得してもスクリプトを実行できず、空のページをインデックス登録します。URL検査のページリソースでブロックされたものがないか確認してください。
DOMパリティと段階を意識したrobotsディレクティブ
生HTML(ソースを表示)とレンダリング済みHTML(URL検査)を比較します。レンダリング済みHTMLにしか存在しないコンテンツも、レンダリングされればインデックス登録されます。どちらにもないコンテンツはGoogleに存在しません。
Googleが直接文書化している段階の順序に関するリスクが1つあります。“When Google encounters the
noindex tag, it may skip rendering and JavaScript execution, which means using
JavaScript to change or remove the robots meta tag from noindex may not work as
expected.” (翻訳)「Googleがnoindexタグに遭遇すると、レンダリングとJavaScript実行をスキップすることがあり、JavaScriptでrobots metaタグをnoindexから変更または削除しても、期待どおりに動かない可能性があります」生HTMLに、JavaScriptで置き換えるつもりの初期noindexがある場合、Googleはその生のnoindexに従い、それを削除するスクリプトを実行しないことがあります。
これを「レンダリング済みが常に勝つ」という普遍的なルールにしないでください。照合はフィールドごとに行います。
| フィールド | 生HTML/レンダリング済みHTMLの比較で確認できること |
|---|---|
| メインコンテンツとリンク | レンダリングが成功すれば、Googleはレンダリング中に生成されたコンテンツと実際の<a href>リンクを使えます。生HTMLにあればその依存を減らせます。 |
| titleとdescription | GoogleはJavaScriptで設定されたメタデータを処理できますが、タイトルリンクとスニペットは複数の情報源から選ばれます。両方の状態を示し、レンダリング後、最初、最後のどれかが保証されるとは主張しないでください。 |
| robotsディレクティブ | 生のnoindexによりGoogleがレンダリングをスキップすることがあるため、JavaScriptによる削除が見られない可能性があります。後から制限を追加したことは、先の制限が取り消された証拠ではありません。 |
| canonical | GoogleのJavaScriptガイダンス は、ソースで1つの値を設定してからJavaScriptで変更しないよう述べています。1つの方法を使い、レンダリング後のheadにある1つの宣言を確認してください。 |
| HTTPステータスとリダイレクト | JavaScriptは、すでに受信したレスポンスのステータスを変更できません。静的ステータスと観測されたレンダリング後の遷移を別の事実として記録してください。 |
この表が示すように、監査担当者は、ソース、レンダリング後、レスポンスヘッダー、検索で観測された状態を別々に保ち、「実効値」という1つの値へまとめないようにすべきです。
コンテンツがDOMに入るレンダリングモードを選ぶ
JS SEOのリスクの多くは、HTMLがどのように生成されるかに帰着します。短く言えば、SSR、静的/事前レンダリング、ハイドレーションはすべてコンテンツをDOMに(またはすぐに)入れるため、可視性がレンダラーの成功に依存する度合いを下げます。一方、完全なクライアント側レンダリングでは、毎回、正しいタイミングでレンダリングを完了できるかにより多くを依存します。動的レンダリングは同等の選択肢ではなく回避策です。Googleの2025年12月更新のガイダンスでは、動的レンダリングを長期的な解決策ではなく回避策として説明し、代わりにサーバーサイドレンダリング、静的レンダリング、またはハイドレーションを推奨しています。私のJavaScript SEOガイド で述べたとおり、“any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines.” (翻訳)「どのようなSSR、静的レンダリング、事前レンダリングの構成でも検索エンジンには問題ありません」。CSR、SSR、SSG、ハイドレーション、ISR、エッジ、ストリーミング、動的レンダリングの全メニューと比較表は、レンダリングページにあります。Googleは別途、サーバーサイドレンダリングや事前レンダリングをユーザーとクローラーにとって良い考えだと説明しています。
Evidence for this claim Google describes server-side rendering or pre-rendering as a good idea because it makes a website faster for users and crawlers. Scope: Google Search guidance for JavaScript sites; the source does not prescribe one framework or guarantee indexing. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basicsテスト方法
Search ConsoleのURL検査が真実の基準です。ライブテストを実行し、レンダリング済みHTML、スクリーンショット、ページリソース/コンソールメッセージを確認して、何が読み込まれ何が失敗したかを見ます。リッチリザルトテストでは、レンダリング済みHTMLをすばやく確認できます。規模が大きい場合は、JavaScriptを実行するクローラー(Ahrefs Site Audit、JSレンダリングモードのScreaming Frog)でサイト全体の生HTMLとレンダリング済みHTMLを比較します。
An illustrative page has 1 title in both raw and rendered HTML, 18 headings in raw HTML and 19 rendered, 42 internal links in raw HTML and 71 rendered, 0 product descriptions in raw HTML and 12 rendered, and 6 canonical tags in raw HTML but only 1 rendered. These counts are synthetic.
JavaScriptはSEOに悪いものでも邪悪なものでもありません。多くのSEO担当者が慣れているものと違うだけです。開発者と協力して重要なコンテンツをDOMに入れ、何がレンダリングされたかの判断は、思い込みではなくGoogle自身のツールに任せてください。
次に進む:JavaScript SEOクラスター
このハブは地図です。下の各トピックが、それぞれ独立した深掘り記事になっています。
レンダリングとアーキテクチャ
- ヘッドレスCMSのSEO — 分離されたフロントエンドがクロール、レンダリング、メタデータ、サイトマップ、canonicalタグに与える影響、選ぶべきレンダリングモード、ヘッドレス特有の失敗モードを説明します。
フレームワーク別ガイド
- React SEO — CSR優先のReactがインデックス登録リスクを生む理由、GoogleがReactアプリをレンダリングする方法、React RouterとHistory API、メタタグ用のreact-helmet-async、Next.jsを選ぶタイミング。
- Angular SEO — AngularのSPAデフォルト、Angular Universalの後継である
@angular/ssr、組み込みのTitle/Metaサービス、事前レンダリング、現代のAngularにおけるインクリメンタルハイドレーション。 - Next.js SEO — Pages RouterとApp Routerの違い、Metadata API、
next/imageとCWV、ISRのタイミングとGooglebot、サイトマップ、よくあるNext.js SEOの誤り。 - Nuxt SEO — デフォルトのSSR、
useSeoMeta()、Nuxtのレンダリングモード、@nuxtjs/seoモジュールのエコシステム、インデックス可能性に関するNuxtと素のVueの比較。 - Vue SEO — Vue 3のCSRデフォルトがクローラーに意味すること、
createWebHistory()、@unhead/vue、メタフレームワークなしの事前レンダリング選択肢、Nuxtを選ぶべきタイミング。 - Svelte SEO — SvelteとSvelteKitの違い、SvelteKitのデフォルトSSR、
<svelte:head>、adapter-staticとssr: falseの落とし穴、アダプターの選択、AIクローラーへの影響。 - Astro SEO — デフォルトでゼロJS、アイランドアーキテクチャ、
@astrojs/sitemap、astro:assets、View TransitionsとHistory API、Server Islandsのフォールバック動作、AstroのCore Web Vitals上の利点。
AI要約
Advanced版を簡潔にまとめると、次のとおりです。
- 「GoogleはJSを読めるか」は間違った問い — 実行できます。失敗モードは、パリティ(生とレンダリング済みの差)、インタラクション(Googleはスクロール/クリックしない)、状態(ステートレスなレンダラー)、タイミングです。
- タイミングに固定遅延はない — Googleは
200ページをレンダリング用にキューへ入れ、「数秒」またはそれ以上待つことがあります。公開されたタイムアウトはありません。非200ステータスや初期noindexがあると、レンダリングキュー全体をスキップすることがあります。 - リンクは実際の
<a href>アンカーにする —<div>のonclickはリンクとして発見されません。JSでリンクを注入しても、最終的にアンカーになれば問題ありません。ただしレンダリング済みアンカーはJS実行後に解析されるため、発見可能になるだけでクロール/インデックス登録の保証ではありません。 - インタラクションではなくビューポートで遅延読み込みする — Googleは「ページを操作しません」。IntersectionObserver/ネイティブ遅延読み込みを使い、スクロールやクリックの後ろにコンテンツを置かないでください。
- 無限スクロールは2ページを1つに結合することがある — Googlebotは一般的なブラウザーより高いビューポートでレンダリングすることがあります(正確な公開サイズはないため、自分の設定をテストします)。その差がローダーを起動し、次ページを追加することがあります。修正はページ分割URL+実際の
<a href>リンク+History APIです。ローダーがページを結合しているなら、そのJSファイルをブロックします。 - クライアント側ルーティング後のソフト404 — 実際の
404またはnoindexを返し、空のシェルをインデックス登録しないでください。URLフラグメントにも依存しません(AJAXクロールは2015年に非推奨)。 - robots.txtでJS/CSSをブロックしない — Googleはブロックされたファイルからレンダリングしません。
noindexは自分自身の削除を妨げることがある — 初期noindexを見たGoogleはレンダリングをスキップし、削除するJSを実行しないことがあります。- DOMパリティ+段階順(robots metaタグ) — 生とレンダリング済みを比較します。ただし初期の生
noindexがレンダリングを止めることがある点に注意します。組み合わせのルールは実際に処理されたディレクティブだけに適用し、canonicalは独自のルールでパリティをテストします。 - レンダリングモードは依存関係を変えるが、結果を保証しない — SSR/静的/事前レンダリング/ハイドレーションはコンテンツを早くDOMへ入れ、レンダリング依存を減らします。完全CSRは最も依存し、動的レンダリングはGoogleの時点付き回避策であり、同等の選択肢ではありません。詳しくはレンダリングページを参照してください。
- 次のツールでテストする — URL検査(レンダリング済みHTML+スクリーンショット+コンソール)、リッチリザルトテスト、JSレンダリングクローラー。
公式ドキュメント
検索エンジンによる一次資料のドキュメントです。
- JavaScript SEOの基本を理解する — 3段階、クロール可能なリンク、レンダリング済みHTMLのテスト。
- 検索に関するJavaScriptの問題を修正する — ソフト404、History API、レンダラーの制約。
- 遅延読み込みコンテンツを修正する — インタラクションではなくビューポートで読み込み、検索に適した無限スクロールにする方法。
- ECのページ分割と段階的ページ読み込み — 一意のURL、
<a href>リンク、Googleがフラグメント識別子を無視する理由。 - Google検索の仕組みの詳細ガイド — クロール→インデックス→配信の中でレンダリングが位置する場所。
Bing/Microsoft
- bingbotシリーズ:JavaScript、動的レンダリング、クローキング — JSのレンダリングと動的レンダリングに関するBingの見解。
原文からの引用
Googleによる記録に残る発言(および私自身の執筆からの引用)です。各検索エンジンのリンクは、引用箇所へ移動するディープリンクです。
Google — レンダリングとリンク
- “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” (翻訳)「GoogleはJavaScriptウェブアプリを、クロール、レンダリング、インデックス登録の3つの主な段階で処理します」 引用へ移動
- “Google can only discover your links if they are <a> HTML elements with an href attribute.” (翻訳)「Googleがリンクを発見できるのは、href属性を持つ<a> HTML要素の場合だけです」 引用へ移動
- “Rendering is important because websites often rely on JavaScript to bring content to the page, and without rendering Google might not see that content.” (翻訳)「ウェブサイトはコンテンツをページに表示するためJavaScriptに依存することが多く、レンダリングなしではGoogleがそのコンテンツを見られない可能性があるため、レンダリングは重要です」 引用へ移動
- “The page may stay on this queue for a few seconds, but it can take longer than that.” (翻訳)「ページはこのキューに数秒間とどまることがありますが、それより長くかかる場合もあります」— レンダリングキューのタイミングに関する引用で、固定遅延は公開されていません。 引用へ移動
- “When Google encounters the noindex tag, it may skip rendering and JavaScript execution, which means using JavaScript to change or remove the robots meta tag from noindex may not work as expected.” (翻訳)「Googleがnoindexタグに遭遇すると、レンダリングとJavaScript実行をスキップすることがあり、JavaScriptでrobots metaタグをnoindexから変更または削除しても期待どおりに動かない可能性があります」 引用へ移動
Google — インタラクション、遅延読み込み、無限スクロール
- “Google Search does not interact with your page.” (翻訳)「Google検索はページを操作しません」 引用へ移動
- “…loads all relevant content whenever it is visible in the viewport.” (翻訳)「ビューポートに表示されるたびに、関連するすべてのコンテンツを読み込みます」 引用へ移動
- “Give each chunk its own persistent, unique URL.” (翻訳)「各チャンクにそれ自体の永続的で一意なURLを与えます」— 検索に適した無限スクロール。 引用へ移動
- “Don’t use URL fragment identifiers (the text after a # in a URL) for page numbers in a collection. Google ignores fragment identifiers.” (翻訳)「コレクションのページ番号にURLフラグメント識別子(URLの#後のテキスト)を使わないでください。Googleはフラグメント識別子を無視します」 引用へ移動
Google — ソフト404とルーティング
- “We recommend using the History API to load different views.” (翻訳)「異なるビューを読み込むにはHistory APIを使うことを推奨します」 引用へ移動
Patrick Stox (私自身の執筆 — JavaScript SEO: A Definitive Guide)
- robots metaタグについて:“With meta robots tags, Google is always going to take the most restrictive option it sees — no matter the location… Google will choose the most restrictive statements between HTML and the rendered version of a page.” (翻訳)「meta robotsタグでは、Googleは場所にかかわらず、見つけた中で最も制限的な選択肢を常に採用します。HTMLとレンダリング済みページの間でも、最も制限的な記述を選びます」
- “If you have an infinite scroll setup, I still recommend a paginated page version so that Google can still crawl properly.” (翻訳)「無限スクロールを設定していても、Googleが適切にクロールできるようページ分割版を推奨します」
- ページの結合について:“occasionally, two pages get indexed as one” (翻訳)「ときどき、2ページが1ページとしてインデックス登録される」 — “Google resized the viewport to be longer … it triggered the infinite scroll and loaded another article in when it was rendering.” (翻訳)「Googleがビューポートをより長くなるようにサイズ変更したとき、レンダリング中に無限スクロールが起動して別の記事を読み込んだ」ことが原因です。修正は、“block the JavaScript file that handles the infinite scrolling so the functionality can’t trigger.” (翻訳)「無限スクロールを処理するJavaScriptファイルをブロックし、機能が起動できないようにする」です。
JavaScript SEOチェックリスト
GoogleがJS依存コンテンツをレンダリングし、インデックス登録できることを確認する簡単なチェックです。
- 重要なコンテンツがレンダリング済みHTMLに現れる(View SourceだけでなくURL検査で確認する)。
- リンクが実際の
<a href>アンカーであり、<div>/<span>のonclickハンドラーではない。 - JavaScriptとCSSのファイルが
robots.txtでブロックされていない。 - コンテンツがクリック、スクロール、ホバーの後ろに隠れていない(Googleは操作しない)。IntersectionObserverまたは
loading="lazy"でビューポートに応じて遅延読み込みする。 - Above the foldのコンテンツを遅延読み込みしない。
- 生HTMLとレンダリング済みHTMLでrobotsディレクティブが一致する(JSで
noindexを注入していない)。Googleは最も制限的なものを採用する。 - クライアント側のルート変更でリソースが見つからない場合は、実際の
404またはnoindexを返す(ソフト404のシェルにしない)。 - 無限スクロールに一意の
<a href>URLとHistory API更新によるページ分割版があり、高いビューポートでページを結合しない。 - ランキングが必要なコンテンツが完全CSRではなくSSR/静的/事前レンダリングを使っている(レンダリングページを参照)。
- URL検査のライブテストで、レンダリング済みスクリーンショットとコンソールエラーをスポットチェックした。
メンタルモデル
1. 「GoogleはJSを実行できるか?」は間違った問いです。 実行できます。実際の問いはパリティ、インタラクション、状態、タイミングです。
- パリティ — レンダリング済みDOMには想定した内容が入っていますか?
- インタラクション — Googleが行わないスクロール/クリックを要求するものはありますか?
- 状態 — ステートレスなレンダラーが消去するCookie/localStorageに依存していますか?
- タイミング — 重要なコンテンツが遅い/遅れて実行されるJSの後ろに置かれていますか?
2. 「レンダリング済みDOMにないものは、存在しない」。 View Sourceは生HTMLを示し、URL検査はレンダリング済みDOMを示します。インデックス登録の判断はレンダリング済みDOMに基づくため、毎回確認する成果物はそこです。
3. 実リンクか、リンクなしです。
発見は<a href>アンカーに乗ります。クリックハンドラー、ボタン、アンカーを生成しないJSナビゲーションは、クロールにとって行き止まりです。
4. ページに触れないボット向けに設計する。 スクロールもクリックもホバーもありません。コンテンツの表示に操作が必要なら、Googleには見えないと考え、ビューポートで読み込みます。
5. 無限スクロールの高いビューポートの落とし穴をテストする。 Googlebotは一般的なブラウザーより高いビューポートでレンダリングできます(固定サイズは公開されていないため、特定の数値を前提に設計しません)。そのため、スクロール/高さで起動するローダーがレンダリング中に動き、次ページを追加して結合することがあります。ページ分割URL+実リンク+History APIで設計し、実際に結合している場合はローダーのJSをブロックします。
6. ツールに裁定させる。 ブラウザーはGooglebotではありません。URL検査のレンダリング済みHTML、スクリーンショット、コンソールが真実の基準であり、「自分のマシンでは正常に見える」ではありません。
JavaScript SEOの落とし穴 — チートシート
| 項目 | 実際に起きること |
|---|---|
robots.txtがJS/CSSをブロック | Googleはブロックされたファイルからレンダリングしないため、ページ全体を壊す可能性がある |
生のindex+JSで注入したnoindex | Googleは最も制限的なものに従う → noindexが勝つ |
<div>のonclickにしたリンク | 発見されない — <a href>でなければならない |
| スクロール/クリックでコンテンツを読み込む | 読み込まれない — Googleは操作しない。ビューポートで遅延読み込みする |
ページ分割にURLフラグメント(#page=2)を使う | 無視される — 実際の一意なURLを使う |
200ステータスのクライアント側404 | ソフト404のリスク — 実際の404またはnoindexを返す |
| 高いビューポートでの無限スクロール | 2つのURLを1つのインデックス登録ページに結合する可能性 — ページ分割し、必要ならローダーをブロックする |
どのレンダリングモードか?(レンダリング成功への依存)
| モード | 依存関係 |
|---|---|
| 静的/事前レンダリング(SSG) | 最低 — コンテンツはすでにHTMLにある |
| サーバーサイドレンダリング(SSR) | 低 — リクエストごとにコンテンツがHTMLにある |
| ハイドレーション(同形) | 低 — コンテンツがすぐDOMに入る |
| 完全なクライアント側レンダリング(CSR) | 最高 — コンテンツはレンダリング成功後にしか存在しない |
| 動的レンダリング | 回避策のみ — Googleは一時しのぎであり、修正ではないと呼ぶ |
これは結果を保証するものではありません。SSR/SSG/ハイドレーションでも正しくレンダリングされ、この記事のほかのチェックをすべて通る必要があります。完全な内訳(ISR、エッジ、ストリーミング、動的レンダリング、トレードオフ)はレンダリングページにあります。
Googlebotに見えているものを確認する
レンダリングのバグは、生HTML(サーバーが送るもの)とレンダリング済みHTML(JS実行後に存在するもの)の隙間に隠れます。本格的なクローラーを使う前に、コマンドラインで簡単な確認を行います。
生HTML(JS実行前に返ってくるもの)を取得する
macOS / Linux:
# Raw HTML as the server sends it — this is the "first fetch"
curl -sL -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://example.com/page/ -o raw.html
# Is your important text actually in the raw HTML? (empty result = JS-dependent)
grep -o "Your headline text" raw.htmlWindows (PowerShell):
$ua = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
Invoke-WebRequest -Uri "https://example.com/page/" -UserAgent $ua -OutFile raw.html
Select-String -Path raw.html -Pattern "Your headline text"テキストがraw.htmlにはないのにブラウザーでは見えるなら、JavaScriptによって追加されています。つまりレンダリングに依存しています。(レンダリング済みHTMLには、URL検査の「クロール済みページを表示→レンダリング済みHTML」や、ヘッドレスChromeのクローラーを使います。通常のcurlではJSを実行できません。)
robots.txtでJS/CSSをブロックしていないことを確認する
macOS / Linux:
curl -sL https://example.com/robots.txt | grep -iE "disallow.*\.(js|css)|Disallow:\s*/(_next|static|assets|dist)"Windows (PowerShell):
(Invoke-WebRequest "https://example.com/robots.txt").Content |
Select-String -Pattern "Disallow.*\.(js|css)","Disallow:\s*/(_next|static|assets|dist)"JavaScriptまたはCSSに一致するDisallowは、Googleがページを正しくレンダリングできないことを意味し、ほとんどの場合は誤りです。(URL検査にはブロックされたページリソースも表示されます。grepは明らかなものをすばやく見つけるだけです。)
JavaScript SEOをデバッグするツール
Render Gapで、生HTMLとGoogleのレンダリングの差を確認する:
- テストしたいページの完全なURLを貼り付けます。JavaScriptを多用するテンプレートページが最も分かりやすい結果になります。
- 不正利用対策の確認を解除してTest pageを押します。まず生HTMLを取得し、そのHTMLが空のシェルのように見える場合だけヘッドレスChromeでレンダリングします。
- 色分けされた判定を読み、Initial HTML vs Rendered DOM表でchangedの印が付いた行を確認します。
- Raw vs rendered diffタブへ切り替え、JavaScriptが追加または削除した内容を行単位で確認します。
- URL検査(Google Search Console) — 真実の基準です。ライブテストを実行し、レンダリング済みHTML、スクリーンショット、ページリソース(読み込まれたものとブロックされたもの)、JavaScriptコンソールメッセージを確認します。
- リッチリザルトテスト — サイトを確認せずに、URLのレンダリング済みHTMLと構造化データをすばやく確認します。
- Chrome DevTools — ソースを表示(生HTML)とElementsパネル(レンダリング済みDOM)を比較します。コンソールには、コンテンツを空にする可能性のあるJSエラーが表示されます。
- JavaScriptレンダリングクローラー — Ahrefs Site AuditとScreaming Frog SEO Spider(JSレンダリングモード)はJSを実行し、規模に応じて生HTMLとレンダリング済みHTMLを比較します。
- レンダリング済みソース表示ツール — レンダリング済みDOMと生HTMLを横並びで示すブラウザー拡張機能で、簡単なスポットチェックに使えます。
- サーバーログ分析 — Googlebotが実際にJS/CSSリソースを取得していることを確認します(ログファイル分析を参照)。
JavaScript SEOを診断するプロンプト
生HTMLとレンダリング済みHTMLを比較する
同じURLについて、生のレスポンスとレンダリング済みDOMを貼り付けます。先に顧客データとトークンを削除してください。
Act as a technical SEO reviewer. Compare RAW_HTML and RENDERED_HTML below. Report only
meaningful differences in title, meta robots, canonical, headings, body copy,
structured data, and crawlable <a href> links. For each difference, label its likely
indexing impact, show the exact conflicting snippets, and give a verification step.
Do not infer content that is not present.
RAW_HTML:
[paste]
RENDERED_HTML:
[paste]ルートのサンプルをトリアージする
Review this CSV of JavaScript routes with columns URL, HTTP_STATUS, RAW_TITLE,
RENDERED_TITLE, RAW_CANONICAL, RENDERED_CANONICAL, RAW_WORDS, RENDERED_WORDS. Group
failures into shared-shell duplicates, restrictive-directive conflicts, soft 404s,
and likely render timeouts. Rank groups by affected URL count. Return the exact rows
that support each conclusion and a test to confirm it; do not invent thresholds.
[paste CSV] JavaScript SEOの変更を検証する
JavaScriptの前にルートコンテンツの存在を証明する
実行するテスト: curlで代表的なルートを取得し、レスポンス本文を確認します。期待される結果: 各レスポンスに一意のタイトル、主見出し、本文、クロール可能なリンクが含まれます。失敗の解釈: デプロイはまだ共有アプリシェルを返しています。監視期間: 直ちに。ロールバックのトリガー: 以前はサーバーから見えていたルートがレンダリング依存になること。
処理段階間でディレクティブが一致することを証明する
実行するテスト: 生HTMLとURL検査のレンダリング済みHTMLでrobotsとcanonicalタグを比較します。期待される結果: 意図した1組のディレクティブが両方に現れ、生のシェルにより制限的な値がありません。失敗の解釈: JavaScriptが遅すぎる段階でインデックスシグナルを上書きしようとしています。監視期間: ローカルレンダリングでは直ちに、Search Consoleでは再クロール後。ロールバックのトリガー: どちらかの段階にnoindexまたは誤ったcanonicalが現れること。
リンクがクロール可能なままであることを証明する
実行するテスト: JavaScriptを無効にして、代表的なルートへのナビゲーションを調べます。期待される結果: 移動先が実際のアンカーのhref属性に残ります。失敗の解釈: 発見を所有しているのはリンクではなくクライアント側ハンドラーです。監視期間: 直ちに。ロールバックのトリガー: スクリプトが失敗したとき、重要なルートがリンクグラフから消えること。
時間をかける価値のあるリソース
私の関連記事
- JavaScript SEO: A Definitive Guide — レンダリング、DOMパリティ、最も制限的なディレクティブのルール、無限スクロール、2ページが1ページになる問題を扱う完全版ガイドです。この記事は、出典リンクを付けた要約版です。
- The Beginner’s Guide to Technical SEO — JavaScript SEOがより大きな全体像のどこに位置するかを説明します。
私の講演
- How Search Works (SlideShare)— クロール、レンダリング、インデックス登録、ランキングについての私の解説です。(私の定型的な注意書き:“This is my understanding of systems… not going to be 100% complete or accurate.” (翻訳)「これはシステムについての私の理解であり、100%完全または正確とは限りません」。)
他者による資料
- r/TechSEO — レンダリング/インデックスの問題をデバッグするコミュニティ。
- web.dev — Rendering on the Web — Chromeチームによるレンダリングのトレードオフの標準的な解説。
- Google Search Central — JavaScript SEO — 3段階の処理、クロール可能なリンク、レンダリング済みHTMLのテストに関する公式一次資料。
- Onely — JavaScript SEO hub — 専門エージェンシーによる、レンダリング、2ウェーブのインデックス登録、JS SEO監査の詳しい技術記事。
- Martin Splitt’s JavaScript SEO playlist — Googleのウェブエコシステムチームが制作した、各JS SEO概念を説明する公式Google動画シリーズ。
- Search Engine Journal — JavaScript SEO coverage — JSレンダリングの問題が生じた際の業界ニュースと実務者向けガイド。
ポッドキャスト
- Search Off the Record(Google検索担当チーム)— Martin Splitt、John Mueller、Gary IllyesがJavaScript SEOとレンダリングを内部事情も含めて定期的に扱います。 聴く
動画
- Google Search Central(YouTube)— Martin SplittのJavaScript SEOシリーズは、GoogleがJSをどう扱うかを解説する最良の公式動画シリーズです。 チャンネル
引用できる統計
- 現在の公式な説明:固定遅延はない。 Googleの公式ドキュメント(2026-03-04更新)は、クロールされた
200ページが*“may stay on this queue for a few seconds, but it can take longer than that”* (翻訳)「このキューに数秒間とどまることがありますが、それより長くかかる場合もあります」と述べています。公開された固定遅延やタイムアウトはなく、非200ステータスを返すページや最初からnoindexのページは、レンダリングを完全にスキップすることがあります。 引用へ移動 - 過去のデータポイント(時点付き):レンダリング遅延の中央値は約5秒。 以前の講演でGoogleスタッフ(Martin SplittとTom Greenaway)は、ページがレンダラーへ到達するまでの中央値を約5秒、90パーセンタイルを数分と説明しました。これは古い不安が示した「数週間」ではありません。私のJavaScript SEOガイド で引用しています。現在公開されている指標ではなく、その講演時点の歴史的なデータポイントとして扱ってください。Googleは継続的な数字として再公開しておらず、上のキュータイミングの引用が現在の公式説明です。
- Martin Splittによれば「2ウェーブのインデックス登録」は薄れつつある(2019年の発言)。 2019年8月にJohn Muellerと行った会話で、Splittは、レンダリングが安くなりクロール、レンダリング、インデックス登録が収束するにつれて、2ウェーブのインデックス登録は*“play[s] less and less of a role”* (翻訳)「役割が次第に小さくなっている」と述べました。完全になくなる時期は示していません。 報道 この発言はその会話におけるSplittの説明で、時点付きで引用できるGoogle仕様ではありません。どちらの方向にも現在の保証とはせず、方向性の文脈として使ってください。
Make rendering an architecture decision before launch: if revenue pages depend on JavaScript for primary content or links, verify what search engines receive instead of assuming the browser experience is enough.
- Client-side rendering, interaction-gated content, and nonstandard links are structural risks that cost more to correct after launch.
- Raw-versus-rendered parity testing shows whether important content, links, and status signals survive the crawl, render, and index process.
- Server-rendered or static primary content with JavaScript used only for enhancement may require no special remediation.
A short, template-level diagnostic before a build or replatform can prevent later re-architecture and focus spending on the routes with organic traffic at risk.
無視した場合のリスク: Search engines may miss primary content, interaction-gated elements, or internal links, leaving revenue pages under-indexed even though they work for users in a browser.
チームに確認: What do our top revenue templates return before JavaScript runs, and have we verified their content and links in rendered output before release?
GoogleはJavaScriptアプリをクロール、レンダリング、インデックス登録を通じて処理します。
Evidence for this claim Google processes JavaScript web apps in three main phases: crawling, rendering, and indexing; without rendering, Google might not see JavaScript-provided content. Scope: Google Search's processing of JavaScript pages; successful rendering does not guarantee indexing or ranking. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basics アンカーにhref属性があるリンクは、通常クロールします。 Evidence for this claim Google can reliably discover links only when they are HTML anchor elements with an href attribute. Scope: Link discovery by Google Search; this does not claim that every discovered URL will be crawled or indexed. Confidence: high · Verified: Google Search Central: Make your links crawlable Googleはサーバーサイドレンダリングまたは事前レンダリングをユーザーとクローラーにとって良い考えだと説明しています。 Evidence for this claim Google describes server-side rendering or pre-rendering as a good idea because it makes a website faster for users and crawlers. Scope: Google Search guidance for JavaScript sites; the source does not prescribe one framework or guarantee indexing. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basics Google検索は、コンテンツを起動するためにページを操作することもありません。 Evidence for this claim Google Search does not interact with a page, so lazy-loaded content should load when it becomes visible in the viewport rather than requiring user interaction. Scope: Google Search's documented rendering behavior for lazy-loaded content; other crawlers can behave differently. Confidence: high · Verified: Google Search Central: Fix lazy-loaded content
変更履歴
2026年8月22日に更新。
編集概要と記録された変更の詳細。変更の詳細
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
完全な比較は利用できません — この改訂の以前のスナップショットがアーカイブされていません。
2026年7月27日に更新。
編集概要と記録された変更の詳細。変更の詳細
-
変更の詳細な注記は現在英語でのみ提供されています。
完全な比較は利用できません — この改訂の以前のスナップショットがアーカイブされていません。
2026年7月18日に更新。
編集概要と記録された変更の詳細。変更の詳細
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
-
変更の詳細な注記は現在英語でのみ提供されています。
完全な比較は利用できません — この改訂の以前のスナップショットがアーカイブされていません。