Get your content updates into AI Search faster and avoid a full rescan when you do not need it.
Reindex individual files without a full sync
Updated a file or need to retry one that errored? When you know exactly which file changed, you can now reindex it directly instead of rescanning your entire data source.
Go to Overview > Indexed Items and select the sync icon next to any file to reindex it immediately.
Crawl only the sitemap you need
By default, AI Search crawls all sitemaps listed in your robots.txt, up to the maximum files per index limit. If your site has multiple sitemaps but you only want to index a specific set, you can now specify a single sitemap URL to limit what the crawler visits.
For example, if your robots.txt lists both blog-sitemap.xml and docs-sitemap.xml, you can specify just https://example.com/docs-sitemap.xml to index only your documentation.
Configure your selection anytime in Settings > Parsing options > Specific sitemaps, then trigger a sync to apply the changes.
New reference documentation is now available for AI Crawl Control:
GraphQL API reference — Query examples for crawler requests, top paths, referral traffic, and data transfer. Includes key filters for detection IDs, user agents, and referrer domains.
Bot reference — Detection IDs and user agents for major AI crawlers from OpenAI, Anthropic, Google, Meta, and others.
Worker templates — Deploy the x402 Payment-Gated Proxy to monetize crawler access or charge bots while letting humans through free.
The latest release of the Agents SDK ↗ brings first-class support for Cloudflare Workflows, synchronous state management, and new scheduling capabilities.
Cloudflare Workflows integration
Agents excel at real-time communication and state management. Workflows excel at durable execution. Together, they enable powerful patterns where Agents handle WebSocket connections while Workflows handle long-running tasks, retries, and human-in-the-loop flows.
Use the new AgentWorkflow class to define workflows with typed access to your Agent:
Secure email reply routing — Email replies are now secured with HMAC-SHA256 signed headers, preventing unauthorized routing of emails to agent instances.
Routing improvements:
basePath option to bypass default URL construction for custom routing
Server-sent identity — Agents send name and agent type on connect
New onIdentity and onIdentityChange callbacks on the client
We have partnered with Black Forest Labs (BFL) again to bring their optimized FLUX.2 [klein] 9B model to Workers AI. This distilled model offers enhanced quality compared to the 4B variant, while maintaining cost-effective pricing. With a fixed 4-step inference process, Klein 9B is ideal for rapid prototyping and real-time applications where both speed and quality matter.
The model hosted on Workers AI is optimized for speed with a fixed 4-step inference process and supports up to 4 image inputs. Since this is a distilled model, the steps parameter is fixed at 4 and cannot be adjusted. Like FLUX.2 [dev] and FLUX.2 [klein] 4B, this image model uses multipart form data inputs, even if you just have a prompt.
With the REST API, the multipart form data input looks like this:
curl --request POST \ --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-9b' \ --header 'Authorization: Bearer {TOKEN}' \ --header 'Content-Type: multipart/form-data' \ --form 'prompt=a sunset at the alps' \ --form width=1024 \ --form height=1024
With the Workers AI binding, you can use it as such:
const form = new FormData();form.append("prompt", "a sunset with a dog");form.append("width", "1024");form.append("height", "1024");// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-9b", { multipart: { body: formStream, contentType: formContentType, },});
The parameters you can send to the model are detailed here:
JSON Schema for ModelRequired Parameters
prompt (string) - Text description of the image to generate
Optional Parameters
input_image_0 (string) - Binary image
input_image_1 (string) - Binary image
input_image_2 (string) - Binary image
input_image_3 (string) - Binary image
guidance (float) - Guidance scale for generation. Higher values follow the prompt more closely
width (integer) - Width of the image, default 1024 Range: 256-1920
height (integer) - Height of the image, default 768 Range: 256-1920
seed (integer) - Seed for reproducibility
Note: Since this is a distilled model, the steps parameter is fixed at 4 and cannot be adjusted.
Multi-reference images
The FLUX.2 klein-9b model supports generating images based on reference images, just like FLUX.2 [dev] and FLUX.2 [klein] 4B. You can use this feature to apply the style of one image to another, add a new character to an image, or iterate on past generated images. You would use it with the same multipart form data structure, with the input images in binary. The model supports up to 4 input images.
For the prompt, you can reference the images based on the index, like take the subject of image 1 and style it like image 0 or even use natural language like place the dog beside the woman.
You must name the input parameter as input_image_0, input_image_1, input_image_2, input_image_3 for it to work correctly. All input images must be smaller than 512x512.
curl --request POST \ --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-9b' \ --header 'Authorization: Bearer {TOKEN}' \ --header 'Content-Type: multipart/form-data' \ --form 'prompt=take the subject of image 1 and style it like image 0' \ --form input_image_0=@/Users/johndoe/Desktop/icedoutkeanu.png \ --form input_image_1=@/Users/johndoe/Desktop/me.png \ --form width=1024 \ --form height=1024
Through Workers AI Binding:
//helper function to convert ReadableStream to Blobasync function streamToBlob(stream: ReadableStream, contentType: string): Promise<Blob> { const reader = stream.getReader(); const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); } return new Blob(chunks, { type: contentType });}const image0 = await fetch("http://image-url");const image1 = await fetch("http://image-url");const form = new FormData();const image_blob0 = await streamToBlob(image0.body, "image/png");const image_blob1 = await streamToBlob(image1.body, "image/png");form.append('input_image_0', image_blob0)form.append('input_image_1', image_blob1)form.append('prompt', 'take the subject of image 1 and style it like image 0')// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-9b", { multipart: { body: formStream, contentType: formContentType }})
You can now store up to 10 million vectors in a single Vectorize index, doubling the previous limit of 5 million vectors. This enables larger-scale semantic search, recommendation systems, and retrieval-augmented generation (RAG) applications without splitting data across multiple indexes.
Vectorize continues to support indexes with up to 1,536 dimensions per vector at 32-bit precision. Refer to the Vectorize limits documentation for complete details.
AI Search now includes path filtering for both website and R2 data sources. You can now control which content gets indexed by defining include and exclude rules for paths.
By controlling what gets indexed, you can improve the relevance and quality of your search results. You can also use path filtering to split a single data source across multiple AI Search instances for specialized search experiences.
Path filtering uses micromatch ↗ patterns, so you can use * to match within a directory and ** to match across directories.
Use case
Include
Exclude
Index docs but skip drafts
**/docs/**
**/docs/drafts/**
Keep admin pages out of results
—
**/admin/**
Index only English content
**/en/**
—
Configure path filters when creating a new instance or update them anytime from Settings. Check out path filtering to learn more.
You can now create AI Search instances programmatically using the API. For example, use the API to create instances for each customer in a multi-tenant application or manage AI Search alongside your other infrastructure.
If you have created an AI Search instance via the dashboard before, you already have a service API token registered and can start creating instances programmatically right away. If not, follow the API guide to set up your first instance.
For example, you can now create separate search instances for each language on your website:
for lang in en fr es de; do curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-search/instances" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ --data '{ "id": "docs-'"$lang"'", "type": "web-crawler", "source": "example.com", "source_params": { "path_include": ["**/'"$lang"'/**"] } }'done
We've partnered with Black Forest Labs (BFL) again to bring their optimized FLUX.2 [klein] 4B model to Workers AI! This distilled model offers faster generation and cost-effective pricing, while maintaining great output quality. With a fixed 4-step inference process, Klein 4B is ideal for rapid prototyping and real-time applications where speed matters.
The model hosted on Workers AI is optimized for speed with a fixed 4-step inference process and supports up to 4 image inputs. Since this is a distilled model, the steps parameter is fixed at 4 and cannot be adjusted. Like FLUX.2 [dev], this image model uses multipart form data inputs, even if you just have a prompt.
With the REST API, the multipart form data input looks like this:
curl --request POST \ --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-4b' \ --header 'Authorization: Bearer {TOKEN}' \ --header 'Content-Type: multipart/form-data' \ --form 'prompt=a sunset at the alps' \ --form width=1024 \ --form height=1024
With the Workers AI binding, you can use it as such:
const form = new FormData();form.append("prompt", "a sunset with a dog");form.append("width", "1024");form.append("height", "1024");// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-4b", { multipart: { body: formStream, contentType: formContentType, },});
The parameters you can send to the model are detailed here:
JSON Schema for ModelRequired Parameters
prompt (string) - Text description of the image to generate
Optional Parameters
input_image_0 (string) - Binary image
input_image_1 (string) - Binary image
input_image_2 (string) - Binary image
input_image_3 (string) - Binary image
guidance (float) - Guidance scale for generation. Higher values follow the prompt more closely
width (integer) - Width of the image, default 1024 Range: 256-1920
height (integer) - Height of the image, default 768 Range: 256-1920
seed (integer) - Seed for reproducibility
Note: Since this is a distilled model, the steps parameter is fixed at 4 and cannot be adjusted.
## Multi-Reference ImagesThe FLUX.2 klein-4b model supports generating images based on reference images, just like FLUX.2 [dev]. You can use this feature to apply the style of one image to another, add a new character to an image, or iterate on past generated images. You would use it with the same multipart form data structure, with the input images in binary. The model supports up to 4 input images.For the prompt, you can reference the images based on the index, like `take the subject of image 1 and style it like image 0` or even use natural language like `place the dog beside the woman`.Note: you have to name the input parameter as `input_image_0`, `input_image_1`, `input_image_2`, `input_image_3` for it to work correctly. All input images must be smaller than 512x512.```bashcurl --request POST \ --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-klein-4b' \ --header 'Authorization: Bearer {TOKEN}' \ --header 'Content-Type: multipart/form-data' \ --form 'prompt=take the subject of image 1 and style it like image 0' \ --form input_image_0=@/Users/johndoe/Desktop/icedoutkeanu.png \ --form input_image_1=@/Users/johndoe/Desktop/me.png \ --form width=1024 \ --form height=1024
Through Workers AI Binding:
//helper function to convert ReadableStream to Blobasync function streamToBlob(stream: ReadableStream, contentType: string): Promise<Blob> { const reader = stream.getReader(); const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); } return new Blob(chunks, { type: contentType });}const image0 = await fetch("http://image-url");const image1 = await fetch("http://image-url");const form = new FormData();const image_blob0 = await streamToBlob(image0.body, "image/png");const image_blob1 = await streamToBlob(image1.body, "image/png");form.append('input_image_0', image_blob0)form.append('input_image_1', image_blob1)form.append('prompt', 'take the subject of image 1 and style it like image 0')// FormData doesn't expose its serialized body or boundary. Passing it to a// Request (or Response) constructor serializes it and generates the Content-Type// header with the boundary, which is required for the server to parse the multipart fields.const formResponse = new Response(form);const formStream = formResponse.body;const formContentType = formResponse.headers.get('content-type');const resp = await env.AI.run("@cf/black-forest-labs/flux-2-klein-4b", { multipart: { body: formStream, contentType: formContentType }})
We've shipped a new release for the Agents SDK ↗ v0.3.0 bringing full compatibility with AI SDK v6 ↗ and introducing the unified tool pattern, dynamic tool approval, and enhanced React hooks with improved tool handling.
This release includes improved streaming and tool support, dynamic tool approval (for "human in the loop" systems), enhanced React hooks with onToolCall callback, improved error handling for streaming responses, and seamless migration from v5 patterns.
This makes it ideal for building production AI chat interfaces with Cloudflare Workers AI models, agent workflows, human-in-the-loop systems, or any application requiring reliable tool execution and approval workflows.
Additionally, we've updated workers-ai-provider v3.0.0, the official provider for Cloudflare Workers AI models, and ai-gateway-provider v3.0.0, the provider for Cloudflare AI Gateway, to be compatible with AI SDK v6.
Agents SDK v0.3.0
Unified Tool Pattern
AI SDK v6 introduces a unified tool pattern where all tools are defined on the server using the tool() function. This replaces the previous client-side AITool pattern.
Server-Side Tool Definition
import { tool } from "ai";import { z } from "zod";// Server: Define ALL tools on the serverconst tools = { // Server-executed tool getWeather: tool({ description: "Get weather for a city", inputSchema: z.object({ city: z.string() }), execute: async ({ city }) => fetchWeather(city) }), // Client-executed tool (no execute = client handles via onToolCall) getLocation: tool({ description: "Get user location from browser", inputSchema: z.object({}) // No execute function }), // Tool requiring approval (dynamic based on input) processPayment: tool({ description: "Process a payment", inputSchema: z.object({ amount: z.number() }), needsApproval: async ({ amount }) => amount > 100, execute: async ({ amount }) => charge(amount) })};
If you need the v5 behavior (static-only checks), use the new functions:
import { isStaticToolUIPart, getStaticToolName } from "ai";
convertToModelMessages() is now async
The convertToModelMessages() function is now asynchronous. Update all calls to await the result:
import { convertToModelMessages } from "ai";const result = streamText({ messages: await convertToModelMessages(this.messages), model: openai("gpt-4o")});
ModelMessage type
The CoreMessage type has been removed. Use ModelMessage instead:
import { convertToModelMessages, type ModelMessage } from "ai";const modelMessages: ModelMessage[] = await convertToModelMessages(messages);
generateObject mode option removed
The mode option for generateObject has been removed:
// Before (v5)const result = await generateObject({ mode: "json", model, schema, prompt});// After (v6)const result = await generateObject({ model, schema, prompt});
Structured Output with generateText
While generateObject and streamObject are still functional, the recommended approach is to use generateText/streamText with the Output.object() helper:
Note: When using structured output with generateText, you must configure multiple steps with stopWhen because generating the structured output is itself a step.
workers-ai-provider v3.0.0
Seamless integration with Cloudflare Workers AI models through the updated workers-ai-provider v3.0.0 with AI SDK v6 support.
Model Setup with Workers AI
Use Cloudflare Workers AI models directly in your agent workflows:
import { createWorkersAI } from "workers-ai-provider";import { useAgentChat } from "agents/ai-react";// Create Workers AI model (v3.0.0 - enhanced v6 internals)const model = createWorkersAI({ binding: env.AI,})("@cf/meta/llama-3.2-3b-instruct");
Enhanced File and Image Support
Workers AI models now support v6 file handling with automatic conversion:
// Send images and files to Workers AI modelssendMessage({ role: "user", parts: [ { type: "text", text: "Analyze this image:" }, { type: "file", data: imageBuffer, mediaType: "image/jpeg", }, ],});// Workers AI provider automatically converts to proper format
Streaming with Workers AI
Enhanced streaming support with automatic warning detection:
// Streaming with Workers AI modelsconst result = await streamText({ model: createWorkersAI({ binding: env.AI })("@cf/meta/llama-3.2-3b-instruct"), messages: await convertToModelMessages(messages), onChunk: (chunk) => { // Enhanced streaming with warning handling console.log(chunk); },});
ai-gateway-provider v3.0.0
The ai-gateway-provider v3.0.0 now supports AI SDK v6, enabling you to use Cloudflare AI Gateway with multiple AI providers including Anthropic, Azure, AWS Bedrock, Google Vertex, and Perplexity.
AI Gateway Setup
Use Cloudflare AI Gateway to add analytics, caching, and rate limiting to your AI applications:
import { createAIGateway } from "ai-gateway-provider";// Create AI Gateway provider (v3.0.0 - enhanced v6 internals)const model = createAIGateway({ gatewayUrl: "https://gateway.ai.cloudflare.com/v1/your-account-id/gateway", headers: { "Authorization": `Bearer ${env.AI_GATEWAY_TOKEN}` }})({ provider: "openai", model: "gpt-4o"});
Migration from v5
Deprecated APIs
The following APIs are deprecated in favor of the unified tool pattern:
Deprecated
Replacement
AITool type
Use AI SDK's tool() function on server
extractClientToolSchemas()
Define tools on server, no client schemas needed
createToolsFromClientSchemas()
Define tools on server with tool()
toolsRequiringConfirmation option
Use needsApproval on server tools
experimental_automaticToolResolution
Use onToolCall callback
tools option in useAgentChat
Use onToolCall for client-side execution
addToolResult()
Use addToolOutput()
Breaking Changes Summary
Unified Tool Pattern: All tools must be defined on the server using tool()
convertToModelMessages() is async: Add await to all calls
CoreMessage removed: Use ModelMessage instead
generateObject mode removed: Remove mode option
isToolUIPart behavior changed: Now checks both static and dynamic tool parts
Installation
Update your dependencies to use the latest versions:
The Overview tab is now the default view in AI Crawl Control. The previous default view with controls for individual AI crawlers is available in the Crawlers tab.
What's new
Executive summary — Monitor total requests, volume change, most common status code, most popular path, and high-volume activity
Operator grouping — Track crawlers by their operating companies (OpenAI, Microsoft, Google, ByteDance, Anthropic, Meta)
Customizable filters — Filter your snapshot by date range, crawler, operator, hostname, or path
Get started
Log in to the Cloudflare dashboard and select your account and domain.
Go to AI Crawl Control, where the Overview tab opens by default with your activity snapshot.
Use filters to customize your view by date range, crawler, operator, hostname, or path.
Navigate to the Crawlers tab to manage controls for individual crawlers.
Pay Per Crawl is introducing enhancements for both AI crawler operators and site owners, focusing on programmatic discovery, flexible pricing models, and granular configuration control.
For AI crawler operators
Discovery API
A new authenticated API endpoint allows verified crawlers to programmatically discover domains participating in Pay Per Crawl. Crawlers can use this to build optimized crawl queues, cache domain lists, and identify new participating sites. This eliminates the need to discover payable content through trial requests.
The API endpoint is GET https://crawlers-api.ai-audit.cfdata.org/charged_zones and requires Web Bot Auth authentication. Refer to Discover payable content for authentication steps, request parameters, and response schema.
Payment header signature requirement
Payment headers (crawler-exact-price or crawler-max-price) must now be included in the Web Bot Auth signature-input header components. This security enhancement prevents payment header tampering, ensures authenticated payment intent, validates crawler identity with payment commitment, and protects against replay attacks with modified pricing. Crawlers must add their payment header to the list of signed components when constructing the signature-input header.
New crawler-error header
Pay Per Crawl error responses now include a new crawler-error header with 11 specific error codes for programmatic handling. Error response bodies remain unchanged for compatibility. These codes enable robust error handling, automated retry logic, and accurate spending tracking.
For site owners
Configure free pages
Site owners can now offer free access to specific pages like homepages, navigation, or discovery pages while charging for other content. Create a Configuration Rule in Rules > Configuration Rules, set your URI pattern using wildcard, exact, or prefix matching on the URI Full field, and enable the Disable Pay Per Crawl setting. When disabled for a URI pattern, crawler requests pass through without blocking or charging.
Some paths are always free to crawl. These paths are: /robots.txt, /sitemap.xml, /security.txt, /.well-known/security.txt, /crawlers.json.
The latest release of @cloudflare/agents ↗ brings resumable streaming, significant MCP client improvements, and critical fixes for schedules and Durable Object lifecycle management.
Resumable streaming
AIChatAgent now supports resumable streaming, allowing clients to reconnect and continue receiving streamed responses without losing data. This is useful for:
Long-running AI responses
Users on unreliable networks
Users switching between devices mid-conversation
Background tasks where users navigate away and return
Real-time collaboration where multiple clients need to stay in sync
Streams are maintained across page refreshes, broken connections, and syncing across open tabs and devices.
The MCPClientManager API has been redesigned for better clarity and control:
New registerServer() method: Register MCP servers without immediately connecting
New connectToServer() method: Establish connections to registered servers
Improved reconnect logic: restoreConnectionsFromStorage() now properly handles failed connections
// Register a server to Agentconst { id } = await this.mcp.registerServer({ name: "my-server", url: "https://my-mcp-server.example.com",});// Connect when readyawait this.mcp.connectToServer(id);// Discover tools, prompts and resourcesawait this.mcp.discoverIfConnected(id);
The SDK now includes a formalized MCPConnectionState enum with states: idle, connecting, authenticating, connected, discovering, and ready.
Enhanced MCP discovery
MCP discovery fetches the available tools, prompts, and resources from an MCP server so your agent knows what capabilities are available. The MCPClientConnection class now includes a dedicated discover() method with improved reliability:
Supports cancellation via AbortController
Configurable timeout (default 15s)
Discovery failures now throw errors immediately instead of silently continuing
Bug fixes
Fixed a bug where schedules ↗ meant to fire immediately with this.schedule(0, ...) or this.schedule(new Date(), ...) would not fire
Fixed an issue where schedules that took longer than 30 seconds would occasionally time out
Fixed SSE transport now properly forwards session IDs and request headers
Fixed AI SDK stream events conversion to UIMessageStreamPart
We've partnered with Black Forest Labs (BFL) to bring their latest FLUX.2 [dev] model to Workers AI! This model excels in generating high-fidelity images with physical world grounding, multi-language support, and digital asset creation. You can also create specific super images with granular controls like JSON prompting.
Pricing documentation is available on the model page or pricing page. Note, we expect to drop pricing in the next few days after iterating on the model performance.
Workers AI Platform specifics
The model hosted on Workers AI is able to support up to 4 image inputs (512x512 per input image). Note, this image model is one of the most powerful in the catalog and is expected to be slower than the other image models we currently support. One catch to look out for is that this model takes multipart form data inputs, even if you just have a prompt.
With the REST API, the multipart form data input looks like this:
curl --request POST \ --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-dev' \ --header 'Authorization: Bearer {TOKEN}' \ --header 'Content-Type: multipart/form-data' \ --form 'prompt=a sunset at the alps' \ --form steps=25 --form width=1024 --form height=1024
With the Workers AI binding, you can use it as such:
const form = new FormData();form.append('prompt', 'a sunset with a dog');form.append('width', '1024');form.append('height', '1024');//this dummy request is temporary hack//we're pushing a change to address this soonconst formRequest = new Request('http://dummy', { method: 'POST', body: form});const formStream = formRequest.body;const formContentType = formRequest.headers.get('content-type') || 'multipart/form-data';const resp = await env.AI.run("@cf/black-forest-labs/flux-2-dev", { multipart: { body: formStream, contentType: formContentType }});
The parameters you can send to the model are detailed here:
JSON Schema for ModelRequired Parameters
prompt (string) - Text description of the image to generate
Optional Parameters
input_image_0 (string) - Binary image
input_image_1 (string) - Binary image
input_image_2 (string) - Binary image
input_image_3 (string) - Binary image
steps (integer) - Number of inference steps. Higher values may improve quality but increase generation time
guidance (float) - Guidance scale for generation. Higher values follow the prompt more closely
width (integer) - Width of the image, default 1024 Range: 256-1920
height (integer) - Height of the image, default 768 Range: 256-1920
seed (integer) - Seed for reproducibility
## Multi-Reference ImagesThe FLUX.2 model is great at generating images based on reference images. You can use this feature to apply the style of one image to another, add a new character to an image, or iterate on past generate images. You would use it with the same multipart form data structure, with the input images in binary.For the prompt, you can reference the images based on the index, like `take the subject of image 1 and style it like image 0` or even use natural language like `place the dog beside the woman`.Note: you have to name the input parameter as `input_image_0`, `input_image_1`, `input_image_2` for it to work correctly. All input images must be smaller than 512x512.```bashcurl --request POST \ --url 'https://api.cloudflare.com/client/v4/accounts/{ACCOUNT}/ai/run/@cf/black-forest-labs/flux-2-dev' \ --header 'Authorization: Bearer {TOKEN}' \ --header 'Content-Type: multipart/form-data' \ --form 'prompt=take the subject of image 1 and style it like image 0' \ --form input_image_0=@/Users/johndoe/Desktop/icedoutkeanu.png \ --form input_image_1=@/Users/johndoe/Desktop/me.png \ --form steps=25 --form width=1024 --form height=1024
Through Workers AI Binding:
//helper function to convert ReadableStream to Blobasync function streamToBlob(stream: ReadableStream, contentType: string): Promise<Blob> { const reader = stream.getReader(); const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); } return new Blob(chunks, { type: contentType });}const image0 = await fetch("http://image-url");const image1 = await fetch("http://image-url");const form = new FormData();const image_blob0 = await streamToBlob(image0.body, "image/png");const image_blob1 = await streamToBlob(image1.body, "image/png");form.append('input_image_0', image_blob0)form.append('input_image_1', image_blob1)form.append('prompt', 'take the subject of image 1and style it like image 0')//this dummy request is temporary hack//we're pushing a change to address this soonconst formRequest = new Request('http://dummy', { method: 'POST', body: form});const formStream = formRequest.body;const formContentType = formRequest.headers.get('content-type') || 'multipart/form-data';const resp = await env.AI.run("@cf/black-forest-labs/flux-2-dev", { multipart: { body: form, contentType: "multipart/form-data" }})
JSON Prompting
The model supports prompting in JSON to get more granular control over images. You would pass the JSON as the value of the 'prompt' field in the multipart form data. See the JSON schema below on the base parameters you can pass to the model.
AI Search now supports custom HTTP headers for website crawling, solving a common problem where valuable content behind authentication or access controls could not be indexed.
Previously, AI Search could only crawl publicly accessible pages, leaving knowledge bases, documentation, and other protected content out of your search results. With custom headers support, you can now include authentication credentials that allow the crawler to access this protected content.
This is particularly useful for indexing content like:
Internal documentation behind corporate login systems
Premium content that requires users to provide access to unlock
Sites protected by Cloudflare Access using service tokens
To add custom headers when creating an AI Search instance, select Parse options. In the Extra headers section, you can add up to five custom headers per Website data source.
For example, to crawl a site protected by Cloudflare Access, you can add service token credentials as custom headers:
AI Crawl Control now supports per-crawler drilldowns with an extended actions menu and status code analytics. Drill down into Metrics, Cloudflare Radar, and Security Analytics, or export crawler data for use in WAF custom rules, Redirect Rules, and robots.txt files.
What's new
Status code distribution chart
The Metrics tab includes a status code distribution chart showing HTTP response codes (2xx, 3xx, 4xx, 5xx) over time. Filter by individual crawler, category, operator, or time range to analyze how specific crawlers interact with your site.
Extended actions menu
Each crawler row includes a three-dot menu with per-crawler actions:
View Metrics — Filter the AI Crawl Control Metrics page to the selected crawler.
View on Cloudflare Radar — Access verified crawler details on Cloudflare Radar.
Copy User Agent — Copy user agent strings for use in WAF custom rules, Redirect Rules, or robots.txt files.
View in Security Analytics — Filter Security Analytics by detection IDs (Bot Management customers).
Copy Detection ID — Copy detection IDs for use in WAF custom rules (Bot Management customers).
Get started
Log in to the Cloudflare dashboard, and select your account and domain.
Go to AI Crawl Control > Metrics to access the status code distribution chart.
Go to AI Crawl Control > Crawlers and select the three-dot menu for any crawler to access per-crawler actions.
Select multiple crawlers to use bulk copy buttons for user agents or detection IDs.
Workers, including those using Durable Objects and Browser Rendering, may now process WebSocket messages up to 32 MiB in size. Previously, this limit was 1 MiB.
This change allows Workers to handle use cases requiring large message sizes, such as processing Chrome Devtools Protocol messages.
AI Search now supports reranking for improved retrieval quality and allows you to set the system prompt directly in your API requests.
Rerank for more relevant results
You can now enable reranking to reorder retrieved documents based on their semantic relevance to the user’s query. Reranking helps improve accuracy, especially for large or noisy datasets where vector similarity alone may not produce the optimal ordering.
You can enable and configure reranking in the dashboard or directly in your API requests:
const answer = await env.AI.autorag("my-autorag").aiSearch({ query: "How do I train a llama to deliver coffee?", model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", reranking: { enabled: true, model: "@cf/baai/bge-reranker-base", },});
Set system prompts in API
Previously, system prompts could only be configured in the dashboard. You can now define them directly in your API requests, giving you per-query control over behavior. For example:
// Dynamically set query and system prompt in AI Searchasync function getAnswer(query, tone) { const systemPrompt = `You are a ${tone} assistant.`; const response = await env.AI.autorag("my-autorag").aiSearch({ query: query, system_prompt: systemPrompt, }); return response;}// Example usageconst query = "What is Cloudflare?";const tone = "friendly";const answer = await getAnswer(query, tone);console.log(answer);
AI Crawl Control now includes a Robots.txt tab that provides insights into how AI crawlers interact with your robots.txt files.
What's new
The Robots.txt tab allows you to:
Monitor the health status of robots.txt files across all your hostnames, including HTTP status codes, and identify hostnames that need a robots.txt file.
Track the total number of requests to each robots.txt file, with breakdowns of successful versus unsuccessful requests.
Check whether your robots.txt files contain Content Signals ↗ directives for AI training, search, and AI input.
Identify crawlers that request paths explicitly disallowed by your robots.txt directives, including the crawler name, operator, violated path, specific directive, and violation count.
Filter robots.txt request data by crawler, operator, category, and custom time ranges.
Take action
When you identify non-compliant crawlers, you can:
Deepgram's newest Flux model @cf/deepgram/flux is now available on Workers AI, hosted directly on Cloudflare's infrastructure. We're excited to be a launch partner with Deepgram and offer their new Speech Recognition model built specifically for enabling voice agents. Check out Deepgram's blog ↗ for more details on the release.
The Flux model can be used in conjunction with Deepgram's speech-to-text model @cf/deepgram/nova-3 and text-to-speech model @cf/deepgram/aura-1 to build end-to-end voice agents. Having Deepgram on Workers AI takes advantage of our edge GPU infrastructure, for ultra low latency voice AI applications.
Promotional Pricing
For the month of October 2025, Deepgram's Flux model will be free to use on Workers AI. Official pricing will be announced soon and charged after the promotional pricing period ends on October 31, 2025. Check out the model page for pricing details in the future.
Example Usage
The new Flux model is WebSocket only as it requires live bi-directional streaming in order to recognize speech activity.
Create a worker that establishes a websocket connection with @cf/deepgram/flux
Write a client script to connect to your worker and start sending random audio bytes to it
const ws = new WebSocket('wss://<your-worker-url.com>');ws.onopen = () => { console.log('Connected to WebSocket'); // Generate and send random audio bytes // You can replace this part with a function // that reads from your mic or other audio source const audioData = generateRandomAudio(); ws.send(audioData); console.log('Audio data sent');};ws.onmessage = (event) => { // Transcription will be received here // Add your custom logic to parse the data console.log('Received:', event.data);};ws.onerror = (error) => { console.error('WebSocket error:', error);};ws.onclose = () => { console.log('WebSocket closed');};// Generate random audio data (1 second of noise at 44.1kHz, mono)function generateRandomAudio() { const sampleRate = 44100; const duration = 1; const numSamples = sampleRate * duration; const buffer = new ArrayBuffer(numSamples * 2); const view = new Int16Array(buffer); for (let i = 0; i < numSamples; i++) { view[i] = Math.floor(Math.random() * 65536 - 32768); } return buffer;}
We’re shipping three updates to Browser Rendering:
Playwright support is now Generally Available and synced with Playwright v1.55 ↗, giving you a stable foundation for critical automation and AI-agent workflows.
We’re also adding Stagehand support (Beta) so you can combine code with natural language instructions to build more resilient automations.
To get started with Stagehand, refer to the Stagehand example that uses Stagehand and Workers AI to search for a movie on this example movie directory ↗, extract its details using natural language (title, year, rating, duration, and genre), and return the information along with a screenshot of the webpage.
Stagehand examplets
const stagehand = new Stagehand({ env: "LOCAL", localBrowserLaunchOptions: { cdpUrl: endpointURLString(env.BROWSER) }, llmClient: new WorkersAIClient(env.AI), verbose: 1,});await stagehand.init();const page = stagehand.page;await page.goto("https://demo.playwright.dev/movies");// if search is a multi-step action, stagehand will return an array of actions it needs to act onconst actions = await page.observe('Search for "Furiosa"');for (const action of actions) await page.act(action);await page.act("Click the search result");// normal playwright functions work as expectedawait page.waitForSelector(".info-wrapper .cast");let movieInfo = await page.extract({ instruction: "Extract movie information", schema: z.object({ title: z.string(), year: z.number(), rating: z.number(), genres: z.array(z.string()), duration: z.number().describe("Duration in minutes"), }),});await stagehand.close();
AutoRAG is now AI Search! The new name marks a new and bigger mission: to make world-class search infrastructure available to every developer and business.
With AI Search you can now use models from different providers like OpenAI and Anthropic. By attaching your provider keys to the AI Gateway linked to your AI Search instance, you can use many more models for both embedding and inference.
In Provider Keys, choose your provider, click Add, and enter the key.
Connect a gateway to AI Search: When creating a new AI Search, select the AI Gateway with your provider keys. For an existing AI Search, go to Settings and switch to a gateway that has your keys under Resources.
Select models: Embedding models are only available to be changed when creating a new AI Search. Generation model can be selected when creating a new AI Search and can be changed at any time in Settings.
Once configured, your AI Search instance will be able to reference models available through your AI Gateway when making a /ai-search request:
export default { async fetch(request, env) { // Query your AI Search instance with a natural language question to an OpenAI model const result = await env.AI.autorag("my-ai-search").aiSearch({ query: "What's new for Cloudflare Birthday Week?", model: "openai/gpt-5" }); // Return only the generated answer as plain text return new Response(result.response, { headers: { "Content-Type": "text/plain" }, }); },};
In the coming weeks we will also roll out updates to align the APIs with the new name. The existing APIs will continue to be supported for the time being. Stay tuned to the AI Search Changelog and Discord ↗ for more updates!
AutoRAG now includes a Metrics tab that shows how your data is indexed and searched. Get a clear view of the health of your indexing pipeline, compare usage between ai-search and search, and see which files are retrieved most often.
You can find these metrics within each AutoRAG instance:
Indexing: Track how files are ingested and see status changes over time.
Search breakdown: Compare usage between ai-search and search endpoints.
Top file retrievals: Identify which files are most frequently retrieved in a given period.