Cloudflare WorkersのSEO

Cloudflare Workersで技術SEOを実装する方法を、fetchハンドラー、HTMLRewriterによるcanonical・hreflang・JSON-LDの注入、KVリダイレクト、Cache API・エッジキャッシュ・Cache-Controlの違い、クローキング境界、Googlebotをブロックし得るBot Fight Modeの観点から説明します。

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

Cloudflare Workers SEOは、Cloudflareのサーバーレスランタイムで技術SEOを行うことです。Workerは設定済みルートに一致するリクエストだけを受け、1つのfetchハンドラーでリクエスト、レスポンスヘッダー、本文を順に書き換えます。本文の書き換えはHTMLRewriterで行い、canonical、hreflang、JSON-LDをCMSデプロイなしに注入できますが、欠落・重複・非HTMLに対して冪等でなければなりません。大量リダイレクトはKVまたはD1、小規模ならBulk Redirects/Rulesが簡単ですが、URLごとの所有者は1つにします。Workers Cache API、Cloudflareエッジキャッシュ、オリジンCache-Controlという3つのcacheを混同せず、キャッシュキー、層、TTL、無効化で診断します。厳格なルールはGooglebotとユーザーへ同じロジックを適用することです。Worker固有の大きな落とし穴は、WAFのallowルールが届かないBot Fight ModeがGooglebotをブロックすることです。変更はバージョン情報とテスト済みロールバックを記録して出荷し、GSC URL検査とCF-Cache-Statusで検証します。一般概念はEdge SEOハブを参照してください。

要点 — Cloudflare Workerは、設定されたルートに一致するリクエストだけを受け取り、1つのfetchハンドラーで、リクエスト、レスポンスヘッダー、HTMLRewriterによるレスポンス本文を順に書き換えます。これは「canonicalを注入する」「titleを修正する」実際の仕組みであり、単に正常系が動くだけでなく、欠落、重複、非HTMLレスポンスに対して冪等であることをテストする必要があります。大量のリダイレクトは高速なキー検索のKVまたはリレーショナルなD1に置き、小規模な集合ならBulk Redirects/Rulesがより簡単です。ただし、Worker、Bulk Redirect、Redirect Rule、オリジンのリダイレクトが同じパスで発火し得るため、URLごとの所有者は1つに決めます。「cache」という語を共有するのは、Workers Cache API(caches.default)、Cloudflareエッジキャッシュ、オリジンのCache-Controlの3つです。これらを混同すると、注入したタグが表示されない原因を誤診します。キャッシュキー、層、TTL、無効化で切り分けてください。GoogleのETag/If-None-Match/304に関する指針も、レスポンスを所有するWorkerに直接適用できます。クローキングの境界は、すべてのリクエスト元へ同じロジックを実行することです。さらに、WAFルールが届かない場所でBot Fight Modeが動き、Googlebotをブロックすることがあります。SEOに影響する変更は、バージョン情報、テスト済みロールバック、停止条件を記録して出荷し、GSC URL検査とCF-Cache-Statusヘッダーで検証します。

この記事の範囲

これはEdge SEOハブの実務・コードレベルの補足です。一般定義、Workers・Akamai・Fastly・Lambda@Edge・Vercel・Netlifyの比較、SnippetsとWorkersの選択、クローキングルールの全体像はハブが扱うため、ここでは繰り返しません。このページでは、Cloudflare Workers、つまりこのサイト自身のWorkerもwrangler.tomlrun_worker_firstを通じて使っているランタイムを、エッジコンピュートならタグを注入できるという曖昧な説明ではなく、実際のAPIで掘り下げます。

コードの前に明記すると、GoogleにはCloudflare Workers専用のSEO文書はありません。適用されるクローキング、HTTPキャッシュ、CDNクロールの公式指針は一般論であり、どのエッジ実装にも当てはまります。

Workerがリクエスト/レスポンス経路に入る場所

WorkerはV8 isolate上で動くサーバーレススクリプトです。ルーティングされたすべてのリクエストはfetchハンドラーから入ります。 Evidence for this claim A Cloudflare Worker receives HTTP requests through a fetch handler. Scope: Cloudflare Workers handlers. Confidence: high · Verified: Cloudflare Workers: Fetch handler この文で「ルーティングされた」は重要です。Workerが見るのは、設定済みのルートまたはカスタムドメイン に一致するリクエストだけで、それ以外はfetchハンドラーへ到達しません。2つのルートが同じURLに一致し得る場合は、より具体的なパターンが優先されます。したがって、特定URLでWorkerの挙動を信頼する前に、ルートが実際に一致することと、どのデプロイ済みバージョンが稼働しているかを確認してください(Wranglerの環境や段階的ロールアウトによって、実際にトラフィックを処理するバージョンがエディター上のものと違うことがあります)。ハンドラー内で行うことは、次の3つに分かれます。

  1. リクエストを書き換える。 オリジンへ送る前に変更します。
  2. レスポンスヘッダーを書き換える。 戻りの途中で変更します。
  3. レスポンス本文を書き換える。 HTMLRewriterを使います。

最小構成は次の形です。

export default {
  async fetch(request, env, ctx) {
    // 1. (optionally) inspect/modify the request
    const response = await fetch(request);   // hit the origin

    // 2. rewrite headers
    const headers = new Headers(response.headers);
    headers.set("X-Robots-Tag", "index, follow");

    // 3. rewrite the body with HTMLRewriter (see next section)
    return new Response(response.body, { ...response, headers });
  },
};

SALT.agencyのチームは、リクエスト、レスポンス、本文の3つのフィルターからなるチェーンを作りました。名前は違っても同じ3段階です。

HTMLRewriterでHTMLを書き換える

HTMLRewriterはCloudflareのストリーミングHTMLパーサーで、タグを注入する仕組みの実際のAPIです。 Evidence for this claim Cloudflare HTMLRewriter provides selector-based handlers that can transform streamed HTML elements. Scope: Cloudflare Workers HTMLRewriter API. Confidence: high · Verified: Cloudflare Workers: HTMLRewriter .on(selector, handler)で要素ハンドラーを登録すると、ハンドラーからgetAttributesetAttributeprependappendsetInnerContentreplaceを使えます。ストリーミング方式なので、文書全体をメモリへバッファリングする必要もありません。

canonicalタグを注入または修正する

class CanonicalHandler {
  constructor(url) { this.url = url; }
  element(el) { el.setAttribute("href", this.url); }
}

const rewriter = new HTMLRewriter()
  .on('link[rel="canonical"]', new CanonicalHandler("https://example.com/preferred/"));

return rewriter.transform(response);

ページにcanonicalがまったくない場合は、headにハンドラーを付けてappendし、既存タグを編集する代わりに追加します。どちらの方法でも、canonicalization側で説明した教訓を忘れないでください。rel=canonicalは命令ではなくヒントです。Workerでプラットフォーム全体に一貫して設定できても、最終判断はGoogleが行います。

上のCanonicalHandlerは、タグがすでに存在し、レスポンスがHTMLであることを前提にしています。本番ではどちらも保証されません。前提を誤ると、1ページにcanonicalが1つではなく2つできます。このような書き換えを出荷する前に冪等にし、次をテストしてください。

  • 既存のcanonicalがない場合。 ハンドラーは欠落を検出し、link[rel="canonical"]に一致するものがなくても何もしないのではなく、headへ1つappendする必要があります。
  • 重複または不正なcanonicalがすでにある場合。 余分なタグを削除するのか、書き換えで2つ目を追加するのかを決めます。後者は実際のバグであり、例外的なケースではありません。
  • 非HTMLレスポンスの場合。 APIルート、画像、リダイレクトを同じWorkerが通す場合、HTMLRewriterを適用してはいけません。実際に確認したルートとコンテンツタイプだけに変換範囲を限定します。
  • 同じレスポンスを2回処理する場合。 リトライや入れ子のfetchでも、タグを2つ目に追加しないことを確認します。

hreflang alternateを追加または修正する

設定データを使い、ロケールごとにalternateリンクをheadへ1つ追加します。関係を持つ設定はD1、単純な対応表ならKVに置けます。リクエスト元を分岐せず、全員へ同じように注入します。(link[rel="alternate"]

JSON-LD構造化データを注入する

new HTMLRewriter().on("head", {
  element(head) {
    head.append(
      `<script type="application/ld+json">${JSON.stringify(schema)}</script>`,
      { html: true }
    );
  },
});

大規模運用で効くCPU制限

競合ページの「制約なしでサブミリ秒」という主張には反論したいところです。実際の上限はCPU時間で、無料プランは10 ms、有料プランは30 msです(fetchで待つ壁時計時間は数えず、CPU時間を数えます)。通常の書き換えでは気になりませんが、非常に大きなページへ重いHTMLRewriter処理を行う場合は、煽りではなく設計上の制約になります。

エッジのリダイレクト:KV、D1、Rules

リダイレクトはサーバーよりエッジに置く方を通常は好みます。オリジンの処理を減らし、ページ生成前に適用できるからです。Cloudflareでは単一・一括リダイレクト、Redirect Rules、Page Rules、KVペアを使うWorkerなど複数の選択肢があります。 出典

Workerの表形式リダイレクトには、URLをキーにする高速で結果整合性のある検索を提供するKVが自然です。

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const target = await env.REDIRECTS.get(url.pathname);   // KV namespace
    if (target) return Response.redirect(target, 301);
    return fetch(request);
  },
};

リダイレクトがロケール別・セグメント別のSQLならD1を使います。小規模で固定的ならBulk RedirectsまたはRedirect Rulesが簡単で、50件のためにKV Workerを自作する必要はありません。 出典

特定URLの所有者は1つに決め、Workerリダイレクト、Bulk Redirect、Redirect Rule、オリジンリダイレクトを同じパスへすべて適用しないでください。これらは別々のシステムなので、同じリクエストでそれぞれ発火し得ます。複数が一致すると、きれいな1回のリダイレクトではなく優先順位をデバッグすることになります。どこかにリダイレクトを追加する前に、他のシステムが同じパスをすでに所有していないかを確認してください。照合の複雑さ(単純な1対1かパターンか)、規模、誰が監視・ロールバックするかで層を選びます。Workerリダイレクトはコードとログにあり、Bulk RedirectやRuleはダッシュボードにあり、開発者以外でも監査・復元しやすいという違いがあります。

キャッシュは3種類、名前は1つ

ここは競合ページが省きがちなセクションで、「変更を出したのに、なぜ表示されないのか」という混乱が最も起きる場所です。「cache」という語を共有する別々の層は3つあります。

  • Workers Cache APIcaches.defaultcaches.open()。コードから読み書きする、Worker単位のプログラム可能なキャッシュです。
  • Cloudflareエッジキャッシュ — アセットを配信するCDNキャッシュで、Cache APIとは別物です。
  • オリジンのCache-Control — オリジンまたはWorkerが設定するヘッダーで、上の2層とGooglebotの挙動に影響します。

3つを混同すると、実際にはpurgeしていない層から配信されているだけなのに、デプロイが失敗したと思い込みます。

変更が本当に表示されないときは、推測せず層ごとに診断します。

  1. キャッシュキー。 URL、ヘッダー、Cookieなど、2つのリクエストが同じキャッシュ項目に当たるかを決める属性を確認します。キャッシュキーに含まれない値で書き換えが変わると、誤ったバリアントを返します。
  2. どの層がレスポンスを返したか。 CF-Cache-StatusHITMISSEXPIREDDYNAMIC)を確認し、エッジキャッシュが応答したのか、Workerへ届いたのかを見ます。
  3. 場所と状態。 Cloudflareのキャッシュはデータセンターへ分散しているため、purgeや新しいデプロイが全エッジをすぐに無効化するとは限りません。
  4. TTLと設定したルール。 キャッシュルール、オリジンのCache-Control、Worker自身が設定したヘッダーのどれがTTLを制御しているか確認します。
  5. 無効化。 特定URLだけをpurgeしたのか、全消去したのか、TTLの期限切れを待ったのかを確認します。Workerが所有するCache APIの項目(caches.default)には個別のdelete()が必要で、CDNキャッシュのpurgeでは消えません。

GooglebotがETag/If-None-Match/304をどう扱うか

Workerがレスポンスを生成または書き換えるなら、キャッシュヘッダーを所有します。つまり、Googleの2024年12月のHTTPキャッシュ指針を直接適用できます。GoogleはETagIf-None-MatchLast-ModifiedIf-Modified-SinceによるヒューリスティックHTTPキャッシュをサポートし、ETag を強く推奨しています。クローラーのETagが一致した場合、サーバーは本文なしの304 Not Modifiedを返すべきです。レスポンスを生成するWorkerなら、ETagを計算しIf-None-Matchと比較して、自ら304へ短絡できます。計算量を節約し、Googlebotへ高速でキャッシュ可能な信号を返せます。

max-ageと再クロールのトレードオフ

Googleは、クローラーが特定URLをいつ再クロールするか判断しやすくするため、Cache-Control: max-ageの設定も検討するよう述べています。ただしHTMLを書き換えるWorkerでは、注入タグを変更した直後のページに長いmax-ageを設定すると、Googlebotが更新を見るまで遅れる可能性があります。書き換えたHTMLへ長いキャッシュ期間を設定して放置しないでください。

Workersに適用するクローキング境界

Workersでの厳格なルールは、すべてのリクエスト元へ同じロジックを実行することです。Googleのスパムポリシーは、ランキング操作の意図でユーザーと検索エンジンに異なる内容を提示すること をクローキングと定義し、検索エンジンからのリクエストにだけテキストやキーワードを挿入すること を具体例として挙げています。

ここで、過剰に反応しないための補足を2つ確認します。

  • User-Agentの確認は自動的にクローキングではありません。 ボット通信の記録や全クライアントへの高速キャッシュは可能です。
  • WorkersでURL単位のA/Bテストは可能です。 URLでユーザーを分け全リクエストに同じ扱いをするのは合法ですが、ボットと人間で分けるのは違反です。

このサイト自身のプレビューゲートは安全なパターンの実例です。Workerは、Cookieが秘密値と一致しない/preview/パスへ、Googlebotを含む全員に404を返します。ボットだけに何かを隠し、ユーザーへ別のものを見せるのではなく、1つのルールを一律に適用しているため安全です。

Workersでボットだけに事前レンダリングする方法を、きれいに構築できたとしても採用しないでください。Googleは動的レンダリングを回避策であり長期的な解決策ではない と説明しています。ボットだけに事前レンダリングするWorkerは、その非推奨パターンを引き継ぎます。

WorkerがGooglebotを誤ってブロック・遅延させる仕組み

Workersで最も固有の落とし穴ですが、通常はWorkerコード内ではありません。

Bot Fight ModeはRuleset Engineの外で動く

Bot Fight Mode(およびSuper Bot Fight Mode)は、Googlebotを含む正当なクローラーを誤検知することがあります。落とし穴は、Bot Fight ModeがWAF Ruleset Engineとは別のパイプラインで評価されることです。そのため通常のWAFの「allow」または「skip」カスタムルールでは上書きできません。Bot Fight ModeがGooglebotへチャレンジしているなら、allowルールで直すのではなく、モード自体を変更または無効化します。依存する前に、CloudflareのBot Fight ModeSuper Bot Fight Mode の現行ドキュメントで仕組みを確認してください。ボット製品は変わります。

検証済みボットのカスタムルール

Cloudflareにはcf.client.botフィールドと検証済みボットを許可するパターン があり、カスタムルールで既知の良好なクローラーを許可できます。これはWAF側には有用ですが、前述のとおりBot Fight Modeには届きません。

CDN自体は中立からプラス

誤解のないように言うと、CloudflareというCDN自体はSEOを損ないません。Googleの2024年のCrawling December 資料は、CDNを検出するとクロール率を上げる一方、WAFやボットルールがGooglebotを誤ってブロックする可能性があり、ボット検証インタースティシャルより503の方がよいと説明しています。リスクはインフラではなく、誤設定されたWorkerまたはボット設定です。

Googlebotが実際に受け取ったものを検証する

Workerをデプロイしたら、クローラーが実際に受け取った内容を推測せず確認します。

  • GSC URL検査 → ライブURLをテスト。 Googleとしてページを取得し、注入したcanonical、hreflang、JSON-LDが実際に存在するレンダリングHTMLを確認します。
  • HTMLとCF-Cache-Statusを一緒に確認。 HITMISSEXPIREDで、見ているのが新しいWorkerレスポンスかキャッシュかを判断します。「変更が表示されない」問題が本当はキャッシュ層の問題だと気付く最速の方法です。
  • Googlebotとして直接取得。 Googlebotのユーザーエージェントでリクエストして比較します。ただし文字列が一致しても身元の証明にはなりません。Scriptsタブの手順どおり、Googleの公開範囲に対する逆引きDNSと正引きDNSで本物のGooglebotを確認します。

Workers固有のデプロイ衛生

成功したwrangler deployはスクリプトが出荷されたことを示すだけで、Googlebotが正しいレンダリング出力を受け取っているとは限りません。SEOに影響するWorker変更は、単なるpushではなく記録を伴うリリースとして扱います。

  • ルートを限定する。 既定で/*へWorkerを実行せず、wrangler.tomlの必要なパスのルートパターンに絞り、バグがサイト全体を停止させないようにします。
  • 規模を約束する前に現行制限を確認する。 CPU時間、サブリクエスト数、スクリプトサイズはプランや時期で変わるため、具体的な上限を記憶に頼らずCloudflareの現行制限ページ で確認します。
  • リリースのバージョン情報を記録する。 Cloudflareのバージョンとデプロイ モデルは、デプロイごとのソースバージョン、互換性日付、バインディング、ルートを追跡します。どのルートでどのバージョンが稼働しているかを記録します。
  • Wrangler環境でバージョン管理とロールバックを行う。 ステージングへ出し、割合を決めて段階的に展開し、直前のバージョンへ即座に戻せる状態を維持します。
  • 制限を踏まえてスコープ付きログを使う。 Workers Logs とログテーリングは段階的ロールアウトのデバッグに使えますが、ログはサンプリングされ、保持期間も限られます。捕捉したリクエストの証拠であり、すべてのクローラー訪問の完全な記録ではないと扱います。
  • 停止条件を決め、必要になる前にロールバックをテストする。 エラー率、スポットチェックでの誤ったレスポンス、クロール率の低下など、何がロールアウトを止めるかを先に決め、実際にロールバックできることを確認します。
  • デプロイの一部としてキャッシュをpurgeする。 3つのキャッシュ層があるため、書き換えを出荷する際の明示的な手順にキャッシュのpurge/無効化を含めます。

Bingに関する注意と、今後の1点

BingにもCloudflare/エッジ専用の指針はありません。しかしWorkerのデプロイは即時でもクロールはそうではないため、IndexNow を組み合わせ、Workerによるリダイレクト表やタグ変更を出荷した瞬間に通知して、Bingや他の参加エンジンへ早く再クロールしてもらうのが自然です。Cloudflareは「Redirects for AI Training」というエッジ強制canonical化を製品機能として提供し、切り替え1つで検証済みAIトレーニングクローラーをcanonical URLへ301します。これはWorkerでcanonicalロジックを自作する場合との有用な対比であり、クローラーへユーザーと異なるものを提供するボット条件分岐を見直す材料でもあります。

より広い背景(プラットフォーム比較、SnippetsとWorkers、開発キュー、ガバナンス)については、Edge SEOハブへ戻ってください。

Add an expert note

Pin an expert quote

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