JavaScriptのSEO

検索エンジンがJavaScriptに依存するコンテンツをクロール、レンダリング、インデックス登録できるようにする方法を説明します。実際のリンク、パリティ、遅延読み込み、無限スクロール、soft-404s、テストを扱います。

初回公開:2026年6月23日 · 最終更新:2026年8月22日 · Advanced
言語
このページには証拠シグナルが1件あります

JavaScript SEOは、JavaScriptに依存するコンテンツを検索エンジンがクロール、レンダリング、インデックス登録できるかを扱います。GoogleはJSを実行できます。失敗モードはより具体的で、生とレンダリング済みのパリティ、インタラクション、ステートレスなレンダラーの状態、タイミングです。リンクは実際のアンカーにし、JS/CSSをブロックせず、ランキングに必要なコンテンツにはSSRや事前レンダリングを優先し、無限スクロールを監視してください。高いレンダリング用ビューポートによって2ページが1ページとしてインデックス登録されることがあります。

TL;DR — GoogleはJavaScriptを実行できるため、「GoogleはJSを読めるか」は正しい問いではありません。失敗モードは、パリティ(生DOMとレンダリング済みDOMの差)、インタラクション(Googleはスクロールもクリックもしない)、状態(レンダラーはステートレス)、タイミングです。リンクは実際の<a href>アンカーにし、JS/CSSをブロックせず、インタラクションではなくビューポートで遅延読み込みし、クライアント側のnot-found状態には実際のステータスを返してください。また、生のnoindexはJavaScriptが削除する前にレンダリングを妨げることがあります。実際に処理されたディレクティブを組み合わせ、常に生の値かレンダリング済みの値が勝つとは考えないでください。無限スクロールには特に注意が必要です。高いレンダリング用ビューポートがローダーを起動し、2つのURLを1つのインデックス登録ページに結合することがあります。レンダラーの内部と選ぶべきレンダリングモードについては、レンダリングを参照してください。

GoogleはJavaScriptを読めるか? はい。ただし、そこが問いではありません

Google can run your JavaScript — the real risks are parity, interaction, state, and timing. 出典: /technical-seo/javascript-seo/

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が変更するのを待たずにレンダリングキューをスキップすることがあります。

Evidence for this claim Google queues crawled pages with a 200 response for rendering; the page may stay in that queue for a few seconds but can take longer, with no published fixed delay or timeout, and non-200 or initial noindex responses may skip rendering. Scope: Google Search's documented render-queue behavior; not a guaranteed or universal timing figure. Confidence: high · Verified: Google Search Central: Understand the JavaScript SEO basics

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にあるリンクと同じように扱われることまでは保証しません。

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 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"を使い、スクロールやクリックのハンドラーは使わないでください。通常のレンダリング中にコンテンツが読み込まれるようにします。

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

無限スクロール:2ページが1ページとしてインデックス登録されるとき

Google's tall render viewport can trigger an infinite-scroll loader and merge two pages into one indexed URL. 出典: /technical-seo/javascript-seo/

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とdescriptionGoogleはJavaScriptで設定されたメタデータを処理できますが、タイトルリンクとスニペットは複数の情報源から選ばれます。両方の状態を示し、レンダリング後、最初、最後のどれかが保証されるとは主張しないでください。
robotsディレクティブ生のnoindexによりGoogleがレンダリングをスキップすることがあるため、JavaScriptによる削除が見られない可能性があります。後から制限を追加したことは、先の制限が取り消された証拠ではありません。
canonicalGoogleの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を比較します。

A render diff is diagnostic, not a score: investigate essential elements that appear only after JavaScript—or disappear after rendering.

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-staticssr: falseの落とし穴、アダプターの選択、AIクローラーへの影響。
  • Astro SEO — デフォルトでゼロJS、アイランドアーキテクチャ、@astrojs/sitemapastro:assets、View TransitionsとHistory API、Server Islandsのフォールバック動作、AstroのCore Web Vitals上の利点。

Add an expert note

Pin an expert quote

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