Cloudflare Web Search API は、AI エージェントやアプリから Web を検索し、結果を「タイトル・URL・説明」の同じ形式で受け取れる API です。2026 年 10 月 2 日にベータとして公開されました1 。検索は AI Gateway を通り、Ceramic.ai・Exa・Linkup の 3 社から 1 つを provider で選びます2 。Worker からは env.AI.websearch() を呼ぶだけで使えます。この記事では、2026 年 10 月時点の公式ドキュメントに沿って、料金と制限、REST と Workers バインディングでの呼び方を整理します。さらに Agents SDK のツールと MCP サーバーとして AI エージェントに渡す TypeScript のコードを載せます。コードは筆者が型チェックとデプロイの予行(--dry-run)まで通したものです。
Cloudflare Web Search API は、検索クエリを送ると Web の検索結果を構造化して返す API です。モデルの学習時点より新しい情報を、エージェントに渡すために使います3 。
Cloudflare の発表ブログは、エージェントが「URL を推測して取りに行き、404 で失敗する」問題を出発点にしています4 。人が検索エンジンから調べ始めるのと同じように、まず検索して関連する URL を得る、という考え方です。
AI エージェントの web_search ツールから env.AI.websearch() を呼び、AI Gateway が選んだ検索プロバイダーに転送し、同じ形式に整えた結果をモデルに戻す流れ 図: 筆者作成(Cloudflare Web Search API 公式ドキュメントの How it works をもとに作図)
公式ドキュメントによると、1 回の検索は次の順で処理されます3 。
指定した AI Gateway を経由する
選んだプロバイダー(Ceramic.ai・Exa・Linkup)に転送する。指定しなければ Ceramic.ai になる
結果を共通の形式(URL・タイトル、任意で説明・画像・favicon・更新日)に整える
AI Gateway のログに記録し、アカウントに課金する
結果の形式がプロバイダーによらず同じなので、provider を 1 つ変えるだけで乗り換えられます3 。
Web Search API は AI Gateway(AI の呼び出しをまとめて記録・制御する Cloudflare のプロキシ)の上に作られています。そのため、モデルの推論と同じ仕組みがそのまま使えます3 。
機能 Web Search API での効き方 ログと分析 検索リクエストが、モデル呼び出しと同じゲートウェイのログに並ぶ Unified Billing AI Gateway のクレジットから引かれる。プロバイダーの定価で上乗せなし BYOK 自分のプロバイダー API キーをゲートウェイに保存して使える。請求はプロバイダーから直接 アクセス制御 ゲートウェイで使えるプロバイダーと、使える人を絞れる
AI Gateway でモデルの費用を管理する方法は「AI Gateway と Workers AI で LLM の費用を管理する方法 」にまとめています。
公開されたばかりで、反応も大きいからです。Web Search API は Cloudflare Birthday Week 2026 の最終日、2026-10-02 に発表されました4 。Hacker News では、Changelog の記事が 590 ポイントを集めています(筆者集計(元データ: Hacker News)2026-10-08 取得)。
Birthday Week 2026 のほかの発表は「Cloudflare Birthday Week 2026 発表まとめと影響 」で扱いました。この記事では Web Search API だけを掘り下げます。
もう 1 つの理由は、検索のクローラーに条件が付いたことです。3 社とも、Cloudflare の「検証済みボット」の要件(クローラーを名乗る・robots.txt を守る)を満たすと約束しています。検索結果には必ず元ページへのリンクが付きます3 。
料金はプロバイダーごとの定価そのままで、Cloudflare の上乗せはありません5 。2026 年 10 月時点の公式の表は次のとおりです。
Cloudflare Web Search API のプロバイダー別料金(1,000 リクエストあたり、2026 年 10 月時点) データを表で見る Cloudflare Web Search API のプロバイダー別料金(1,000 リクエストあたり、2026 年 10 月時点) プロバイダー 1,000 リクエストあたりの料金(米ドル)(ドル) Ceramic.ai(ceramic) 0.25 Linkup(linkup) 5 Exa(exa) 7
出典: Cloudflare Docs「Providers」(2026-10-02 更新、2026-10-08 参照)
プロバイダー providerZero Data Retention 料金(1,000 リクエスト) 特徴(公式ドキュメントの説明) Ceramic.ai ceramic(既定)Yes $0.25 400 億ページ超の独自インデックス。説明文は最大 8,000 文字 Exa exaNo $7.00 auto モードで検索。クエリに関係の深い抜粋(highlights)を説明文として返すLinkup linkupYes $5.00 fast の深さで、回答を生成せず生の検索結果を返す
表の値は Providers のページによります5 。注意が 1 つあります。Changelog では「3 社とも Cloudflare 経由のリクエストで Zero Data Retention(データを保持しない)に対応」と書かれています1 。一方、Providers のページでは Exa が「No」です(2026-10-08 時点)。データの保持が気になる用途では、使う前に Providers のページを確かめてください。
Unified Billing のクレジットを買うと、購入額に 5% の手数料がかかります。100 ドル分を買うと 105 ドルの請求です6 。検索 1 回ごとの料金に上乗せはありませんが、クレジット経由なら実質この分が乗ります。BYOK なら、プロバイダーとの自分の契約で請求されます5 。
項目 値 クエリの長さ 1〜1,024 文字 1 回で返る件数(limit) 1〜10(既定 10) providerceramic(既定)/ exa / linkupbyokAliasゲートウェイに保存したキーの別名(英数字・_・- で 64 文字まで)
値は How to use のページによります2 。ドメインの絞り込みや地域の指定のパラメーターは、2026 年 10 月時点のドキュメントにはありません。
Workers 以外のバックエンドからは、REST API に POST します。前提は次の 3 つです2 。
Cloudflare アカウント
AI Gateway(どのアカウントにも default というゲートウェイがある)
AI Gateway のクレジット、またはゲートウェイに保存したプロバイダーの API キー
API トークンには Account > Workers AI > Read と Account > AI Gateway > Read の 2 つの権限が要ります2 。
curl https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID /ai/websearch/ \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN " \
--header "Content-Type: application/json" \
--data '{
"query": "What are some fun things to do in Salt Lake City as fall approaches?",
"provider": "ceramic",
"limit": 5,
"options": {
"gateway": { "id": "default" }
}
}'
このコマンドは公式ドキュメントのものです2 。応答は次の形です。description などの任意の項目は、プロバイダーが返したときだけ入ります。
{
"items" : [
{
"url" : "https://example.com/salt-lake-city-fall-guide" ,
"title" : "Fall in Salt Lake City: A Local's Guide" ,
"description" : "From scenic drives up Big Cottonwood Canyon to pumpkin patches..."
}
] ,
"metadata" : {
"query" : "What are some fun things to do in Salt Lake City as fall approaches?" ,
"requestId" : "<REQUEST_ID>" ,
"latencyMs" : 612
}
}
Worker からは、AI バインディングの websearch() を使います。API トークンは要りません2 。
{
"$schema" : "./node_modules/wrangler/config-schema.json" ,
"name" : "web-search-worker" ,
"main" : "src/index.ts" ,
"compatibility_date" : "2026-10-08" ,
"ai" : {
"binding" : "AI"
}
}
公式の最小例は次のとおりです2 。websearch() は標準の Response を返すので、response.json() で中身を読みます。
export default {
async fetch (request, env): Promise <Response > {
const response = await env.AI .websearch ({
gatewayId : "default" ,
query : "What are some fun things to do in Salt Lake City as fall approaches?" ,
provider : "exa" ,
limit : 5 ,
});
const results = await response.json ();
return Response .json (results);
},
} satisfies ExportedHandler <Env >;
npx wrangler types で生成した型(@cloudflare/ workers-types 5.20261008.1 相当)には、websearch(request: AiWebSearchRequest): Promise<Response> がすでに入っていました。
エージェントに渡す前に、呼び出しを関数にまとめておくと後が楽です。筆者は次の src/ search.ts を使いました。上限(1,024 文字・10 件)を関数の中で守り、モデルに渡す文字列も短くします。Ceramic.ai の説明文は最大 8,000 文字あるため5 、そのまま渡すとコンテキストを圧迫するからです。
export type SearchProvider = "ceramic" | "exa" | "linkup" ;
export type SearchItem = {
url : string ;
title : string ;
description ?: string ;
};
export type SearchResult = {
items : SearchItem [];
metadata : { query : string ; requestId : string ; latencyMs : number };
};
export async function webSearch (
env : Env ,
query : string ,
options : { provider?: SearchProvider; limit?: number } = {},
): Promise <SearchResult > {
const response = await env.AI .websearch ({
gatewayId : env.GATEWAY_ID ,
query : query.slice (0 , 1024 ),
provider : options.provider ?? "ceramic" ,
limit : Math .min (options.limit ?? 5 , 10 ),
});
if (!response.ok ) {
throw new Error (`websearch failed: ${response.status} ${await response.text()} ` );
}
return (await response.json ()) as SearchResult ;
}
export function toContext (result : SearchResult , maxChars = 500 ): string {
return result.items
.map (
(item, i ) =>
`[${i + 1 } ] ${item.title} \n${item.url} \n${(item.description ?? "" ).slice(0 , maxChars)} ` ,
)
.join ("\n\n" );
}
GATEWAY_ID は wrangler.jsonc の vars に "GATEWAY_ID": "default" と書いておきます。
渡し方は、エージェントをどこで動かすかで選びます。
方法 向いている場面 必要なもの A. Workers AI のツール呼び出し 1 回の質問に 1 回検索して答える、単純な Worker AI バインディングだけ B. Agents SDK のツール 会話を保存するチャットエージェント Durable Object・AI SDK C. MCP サーバー Claude Code など外のエージェントから使う createMcpHandler
公式ドキュメントには、web_search という関数ツールをモデルに渡し、呼ばれたら検索して結果を戻す例があります2 。流れが一番分かりやすいので要点を抜き出します(コードは公式のまま。筆者は実行していません)。
const MODEL = "@cf/google/gemma-4-26b-a4b-it" ;
const completion = await env.AI .run (
MODEL ,
{
messages,
tools : [
{
type : "function" ,
function : {
name : "web_search" ,
description : "Search the web for current information." ,
parameters : {
type : "object" ,
properties : { query : { type : "string" } },
required : ["query" ],
},
},
},
],
},
{ gateway : { id : "default" } },
);
const toolCall = completion.tool_calls ?.[0 ];
if (toolCall?.name === "web_search" ) {
const searchResponse = await env.AI .websearch ({
gatewayId : "default" ,
query : toolCall.arguments .query ,
limit : 5 ,
});
const searchResults = await searchResponse.json ();
}
この例はツールを 1 回だけ呼びます。検索を何度も繰り返させたいなら、次の B のようにループを持つ仕組みに任せます。発表ブログによると、AI Gateway に Web 検索を組み込みの「Server Tools」として入れる作業も進んでいます4 。2026 年 10 月時点では「近日公開」で、今は自分でツールを定義します。
Agents SDK の AIChatAgent では、AI SDK の tool() でツールを定義します。公式の Chat agent の例7 の天気ツールを、Web 検索に置き換えたのが次のコードです。必要なパッケージは公式の例と同じです。
npm install agents @cloudflare/ai-chat ai workers-ai-provider zod
import { AIChatAgent } from "@cloudflare/ai-chat" ;
import { createWorkersAI } from "workers-ai-provider" ;
import { streamText, convertToModelMessages, tool, stepCountIs } from "ai" ;
import { z } from "zod" ;
import { webSearch, toContext } from "./search" ;
export class ChatAgent extends AIChatAgent <Env > {
async onChatMessage ( ) {
const workersai = createWorkersAI ({ binding : this .env .AI });
const result = streamText ({
model : workersai ("@cf/meta/llama-4-scout-17b-16e-instruct" ),
system :
"You are a helpful assistant. Use web_search for recent events, " +
"new releases, or anything after your training cutoff. Cite URLs." ,
messages : await convertToModelMessages (this .messages ),
tools : {
web_search : tool ({
description : "Search the web for current information." ,
inputSchema : z.object ({
query : z.string ().describe ("Search query" ),
}),
execute : async ({ query }) => {
const result = await webSearch (this .env , query, { limit : 5 });
return toContext (result);
},
}),
},
stopWhen : stepCountIs (5 ),
});
return result.toUIMessageStreamResponse ();
}
}
ポイントは stopWhen: stepCountIs(5) です。モデルが「検索 → 読む → 言い換えて再検索」を繰り返しても、5 ステップで止まります。検索 1 回ごとに課金されるので、上限は必ず付けてください。wrangler.jsonc の Durable Object の設定は公式の例7 と同じです。Agents SDK 自体の始め方は「Cloudflare Agents SDK 入門 」を参照してください。
同じ webSearch() を MCP サーバーのツールにすれば、Claude Code などの外のエージェントからも使えます。新しく作るなら、Agents SDK の createMcpHandler(ステートレスな MCP ハンドラー)を使います8 。
npm install agents @modelcontextprotocol/server@2.0.0 zod
import { createMcpHandler } from "agents/mcp/server" ;
import { McpServer } from "@modelcontextprotocol/server" ;
import { env } from "cloudflare:workers" ;
import { z } from "zod" ;
import { webSearch, toContext } from "./search" ;
function createServer ( ) {
const server = new McpServer ({ name : "web-search" , version : "1.0.0" });
server.registerTool (
"web_search" ,
{
description : "Search the web via Cloudflare Web Search API" ,
inputSchema : {
query : z.string ().min (1 ).max (1024 ),
provider : z.enum (["ceramic" , "exa" , "linkup" ]).optional (),
},
},
async ({ query, provider }) => {
const result = await webSearch (env, query, { provider, limit : 5 });
return { content : [{ type : "text" , text : toContext (result) }] };
},
);
return server;
}
const mcpHandler = createMcpHandler (createServer);
export default {
async fetch (request : Request , env : Env , ctx : ExecutionContext ) {
const url = new URL (request.url );
if (url.pathname .startsWith ("/mcp" )) {
return mcpHandler (request, env, ctx);
}
return new Response ("Not found" , { status : 404 });
},
} satisfies ExportedHandler <Env >;
createServer はリクエストごとに呼ばれるので、env は cloudflare:workers から読みます。Zod のスキーマに 1,024 文字の上限を書いておくと、長すぎるクエリはツールを呼ぶ前に弾かれます。
筆者は B と C を 1 つの Worker にまとめ、型チェックとデプロイの予行を通しました。さらに wrangler dev で起動し、tools/ list で web_search が見えることを確かめました(Wrangler 4.148.0、agents 0.27.0)。
npx tsc と wrangler deploy --dry-run が通り、wrangler dev で起動した MCP サーバーに tools/list を送ると web_search ツールが返る様子 筆者の実行結果(2026-10-08、Wrangler 4.148.0)。長い行は省略して表示
デプロイしたら、Claude Code には次のコマンドで追加します。認証なしのまま公開すると、誰でもあなたのクレジットで検索できてしまいます。本番では OAuth などで保護してください。手順は「リモート MCP サーバーを Cloudflare Workers で作る 」にあります。
claude mcp add --transport http web-search https://web-search-agent.<サブドメイン>.workers.dev/mcp
モデル側に組み込みの検索ツールを使う手もあります。たとえば Claude API には web_search のサーバーツールがあります9 。公式ドキュメントに書かれている事実だけで比べると、次のとおりです。
項目 Cloudflare Web Search API Claude API の web_search ツール 料金(2026 年 10 月時点) 1,000 リクエストあたり $0.25〜$7.00(プロバイダーによる)5 1,000 検索あたり $10 + 検索結果のトークン料金9 使えるモデル どのモデルでもよい(結果を自分で渡す) Claude のモデル 検索の実行 自分のコード(ツール定義と呼び出しを書く) API 側が実行し、引用付きで答える ドメインの絞り込み ドキュメントに記載なし allowed_domains / blocked_domains1 回の件数の上限 10 件 — ログ AI Gateway のログにモデル呼び出しと並ぶ Claude API の usage に検索回数が出る
使い分けは次のように言い切れます。
Claude だけを使い、引用付きの答えが欲しい : Claude API の web_search ツールが手早い
Workers AI や複数のモデルを使う、検索結果を自分で加工したい : Cloudflare Web Search API
検索の回数が多い : 料金の表どおり、Ceramic.ai が最も安い
byokAlias を指定したのに、ゲートウェイにそのプロバイダーとキーの別名が無いと、400 で失敗します。クレジットには切り替わりません2 。逆に byokAlias を省くと、default の別名のキーがあればそれを使い、無ければクレジットから引かれます。どちらで請求されるかを、ゲートウェイの Provider Keys で確かめてください。
BYOK を使わない場合は、AI Gateway のクレジットが必要です2 。ダッシュボードの AI Gateway の Credits Available から購入します。自動チャージ(auto top-up)も設定できます6 。
@cloudflare/ workers-types 5.20261008.1 の AiWebSearchRequest のコメントには「上限 20」とあります。一方、ドキュメントの上限は 10 件です2 。筆者のコードはドキュメントに合わせて 10 で止めています。
2026 年 10 月時点でオープンベータです1 。パラメーターや料金は変わる可能性があります。本番で使うなら Changelog を購読しておくと安心です。
Cloudflare Web Search API は、AI Gateway 経由で Ceramic.ai・Exa・Linkup の検索結果を同じ形式で返す API(2026-10-02 ベータ公開)
料金は 1,000 リクエストあたり Ceramic.ai $0.25、Linkup $5、Exa $7。クレジット購入時は 5% の手数料
Worker からは env.AI.websearch({ gatewayId, query, provider, limit })。1 回 10 件・1,024 文字まで
エージェントには、Workers AI のツール呼び出し・Agents SDK の tool()・MCP サーバーのどれでも渡せる
次にやること: default ゲートウェイにクレジットを入れ、上の webSearch() を Worker に置いて 1 回呼んでみる
無料枠はドキュメントに書かれていません。AI Gateway のクレジットか、自分のプロバイダー API キー(BYOK)が必要です2 。料金は 1,000 リクエストあたり $0.25(Ceramic.ai)から $7.00(Exa)です(2026 年 10 月時点)5 。
回数が多いエージェントなら、最も安く既定でもある Ceramic.ai から始めるのがよいでしょう。クエリに関係の深い抜粋だけをモデルに渡したいなら Exa、回答を生成しない素早い検索結果が欲しいなら Linkup が公式に勧められています5 。結果の形式は同じなので、provider を変えて比べられます。
使えます。https:/ / api.cloudflare.com/ client/ v4/ accounts/ {account_id}/ ai/ websearch/ に POST します。API トークンには Workers AI と AI Gateway の Read 権限が要ります2 。
返るのは URL・タイトルと、任意の説明・画像・favicon・更新日です3 。本文が必要なら、返った URL を別に取得します。説明文の長さはプロバイダーで違い、Ceramic.ai は最大 8,000 文字です5 。
Providers のページでは、Ceramic.ai と Linkup が Zero Data Retention「Yes」、Exa が「No」です(2026-10-08 時点)5 。Changelog は 3 社とも対応と書いているため1 、気になる場合は最新の Providers のページを確認してください。検索リクエスト自体は AI Gateway のログに残ります3 。