Skip to content

Changelog

New updates and improvements at Cloudflare.

Evaluate Flagship feature flags from Rust

Flagship now has an official Rust SDK. Use it to evaluate feature flags from async Rust server applications through OpenFeature, with the same targeting rules and percentage rollouts as the other Flagship SDKs.

Install the cloudflare-flagship ↗︎ crate:

cargo add cloudflare-flagship

Then register the provider and evaluate a flag:

let options = FlagshipClientOptions::builder()
    .app_id("<APP_ID>")
    .account_id("<ACCOUNT_ID>")
    .auth_token("<API_TOKEN>")
    .build()?;

let mut api = OpenFeature::default();
api.set_provider(FlagshipServerProvider::new(options)?).await;

let context = EvaluationContext::default().with_targeting_key("user-42");
let enabled = api
    .create_client()
    .get_bool_value("new-checkout", Some(&context), None)
    .await
    .unwrap_or(false);

The provider evaluates flags over HTTP by default. Turn on local evaluation to download flag definitions and evaluate flags in-process, without a network request per evaluation. The SDK also supports structured evaluation context, an optional response cache, and logging and telemetry hooks.

The SDK requires Rust 1.88 or later and a Tokio runtime. For setup and configuration options, refer to the Rust SDK documentation.

Faster MP4 downloads from Cloudflare Stream

Generating MP4 downloads from Cloudflare Stream is now up to 40% faster, with no changes to your implementation required. This improvement is most impactful for on-demand videos over 1 minute in duration.

You can generate an MP4 download in the Dashboard, with the cf, the Cloudflare CLI CLI, or by sending a POST request.

cf clish
cf stream videos downloads create default --identifier "$VIDEO_UID"
Create downloadbash
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/stream/$IDENTIFIER/downloads/default" \
	--request POST \
	--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

Both of these response include the download URL and processing progress:

{
	"result": {
		"default": {
			"status": "inprogress",
			"percentComplete": 75.0,
			"url": "https://customer-<CODE>.cloudflarestream.com/<VIDEO_UID>/downloads/default.mp4"
		}
	},
	"success": true,
	"errors": [],
	"messages": []
}

For more information, refer to Generate downloadable MP4 files.

Workers Builds and Pages now list GitHub repositories based on your GitHub account

When you connect a GitHub repository to Workers Builds or Pages, the accounts and repositories you can pick from are now based on your own GitHub account, so the list reflects the repositories you work with on GitHub. Previously, the list was based on the Cloudflare Workers & Pages GitHub App installations linked to your Cloudflare account, so it could include repositories that you cannot access on GitHub.

Three developers on the same Cloudflare account have all authorized the app, and the app is installed on acme-corp and dev-1. Each sees a different repository picker. dev-1 can pick acme-corp or dev-1, with payments-api and website listed for acme-corp. dev-2 can only pick acme-corp, with only website listed. dev-3 has no accounts or repositories, only the option to add a GitHub account.

The list now shows:

  • Your own GitHub account, if the app is installed on it.
  • GitHub organizations that have the app installed, where you can access at least one repository.
  • The repositories you can access in each of them.

GitHub accounts that belong to other users are no longer listed, even if they have given you access to one of their repositories.

What this means for you:

Authorizing the app and installing it are two separate steps on GitHub. For more details, refer to Install and authorize the app for Workers Builds and Pages.

Authorize: tells Cloudflare who you are, once per person, listed under Authorized GitHub Apps. Install: decides which repositories Cloudflare can access, listed under Installed GitHub Apps.
  • If you have already authorized the app with your GitHub user: Nothing changes. You can check on the Authorized GitHub Apps page ↗︎ on GitHub.
  • If you have not: The next time you connect a repository, Cloudflare sends you to GitHub to authorize the app. You only need to do this once, even if someone else on your Cloudflare account already connected GitHub.
  • If the app is not installed on any GitHub account you can access: After you authorize, install the app on your own GitHub account or an organization, the same as before.
  • If an account or organization is missing from the list: Select Add GitHub account and install the app on it.

Projects that are already connected to a repository are not affected and keep building.

For more information, refer to Repository access for Workers Builds and Pages.

Set a concurrency limit for each Workflow

You can now set a concurrency limit on an individual Workflow to cap how many of its instances run at the same time. Use it to protect a database or third-party API that slows down or rejects requests past a certain number of concurrent connections, or to distribute load more evenly across your Workflows so that one high-volume Workflow does not use all of your account's concurrency.

For example, to allow only 10 instances of a Workflow to run at a time, set concurrency.limit on its workflows binding and redeploy:

{
	"workflows": [
		{
			"name": "my-workflow",
			"binding": "MY_WORKFLOW",
			"class_name": "MyWorkflow",
			"concurrency": {
				"limit": 10,
			},
		},
	],
}
[[workflows]]
name = "my-workflow"
binding = "MY_WORKFLOW"
class_name = "MyWorkflow"

  [workflows.concurrency]
  limit = 10

You can also set concurrency on a Workflow declared in exports, or with exports.workflow() in @cloudflare/config.

Instances above the limit are not rejected. They are queued and start automatically as running instances finish or move to the waiting state.

The limit must be a positive integer, and cannot be higher than your account's concurrency limit (100 on Workers Free, 50,000 on Workers Paid). Lowering the limit does not stop instances that are already running. Workflows without a concurrency limit can still use up to your account's full concurrency limit.

Per-Workflow concurrency limits require Wrangler 4.127.0 or above.

For more information, refer to Concurrency limits.

Run the Codex agent loop on Cloudflare Workers

Run the Codex agent loop in a Cloudflare Durable Object with this experimental Agents SDK example ↗︎. Conversations, files, and completed model and tool results persist across restarts, allowing the agent to recover after interruptions.

The example adapts Codex’s Rust turn-processing code ↗︎ to WebAssembly and uses Agents SDK capabilities for storage and recovery.

The harness combines Agents SDK capabilities for durable execution:

  • Tasks journals model calls and tool execution. Completed steps reuse their recorded results after a restart. Interrupted steps can run again.
  • Sessions stores conversation history and compacts the model context.
  • Streams stores ordered events for replay after reconnecting.
  • Workspace provides tools to read and write persistent files.

For example, use OpenAI's GPT-6.1 Sol through AI Gateway. Configure the model with createAI and install the capabilities on a Durable Object:

import { DurableObject } from "cloudflare:workers";
import { Workspace } from "@cloudflare/computer";
import { Lifecycle } from "agents/lifecycle";
import { createAI } from "agents/models/ai-sdk";
import { Sessions } from "agents/sessions";
import { Streams } from "agents/streams";
import { Tasks } from "agents/tasks";
import { CodexHarness } from "./codex-harness";

export class Coder extends DurableObject {
	tasks = new Tasks();
	streams = new Streams();
	sessions = new Sessions();
	workspace = new Workspace({ storage: this.ctx.storage });

	codex = new CodexHarness({
		tasks: this.tasks,
		streams: this.streams,
		sessions: this.sessions,
		workspace: this.workspace,
		model: createAI({ binding: this.env.AI, id: "default" })(
			"openai/gpt-6.1-sol",
		),
	});

	lifecycle = Lifecycle.install(this)
		.use(this.tasks)
		.use(this.streams)
		.use(this.sessions)
		.use(this.codex);
}
import { DurableObject } from "cloudflare:workers";
import { Workspace } from "@cloudflare/computer";
import { Lifecycle } from "agents/lifecycle";
import { createAI } from "agents/models/ai-sdk";
import { Sessions } from "agents/sessions";
import { Streams } from "agents/streams";
import { Tasks } from "agents/tasks";
import { CodexHarness } from "./codex-harness";

export class Coder extends DurableObject<Env> {
	tasks = new Tasks();
	streams = new Streams();
	sessions = new Sessions();
	workspace = new Workspace({ storage: this.ctx.storage });

	codex = new CodexHarness({
		tasks: this.tasks,
		streams: this.streams,
		sessions: this.sessions,
		workspace: this.workspace,
		model: createAI({ binding: this.env.AI, id: "default" })("openai/gpt-6.1-sol"),
	});

	lifecycle = Lifecycle.install(this)
		.use(this.tasks)
		.use(this.streams)
		.use(this.sessions)
		.use(this.codex);
}

To use this model, configure the default gateway with Unified Billing or a stored OpenAI API key.

For setup, models, tools, and recovery behavior, refer to the Codex harness guide.

Run Exo agents on Cloudflare

You can now run Exo agents on Cloudflare, with Durable Objects coordinating conversations and Cloudflare Sandboxes running Linux tools. Define an agent in Markdown, then use Exo's CLI or HTTP API to run it.

After deploying the Cloudflare adapter and configuring your Exo provider ↗︎, add an openai vault credential and save this definition as agent.md:

---
harness: basic
model:
  name: gpt-6.1-sol
  credential: openai
---

Help the user with their task.

Run the agent against your Cloudflare deployment with Exo's CLI:

exo --provider cloudflare agent run --agent-file agent.md

The Exo project maintains the Cloudflare adapter independently of Cloudflare. It does not require the Agents SDK.

Follow the Exo guide for architecture, recovery behavior, and upstream setup instructions.

Run the Nanocode agent harness in Cloudflare Durable Objects

You can now run Nanocode ↗︎ coding agents in Cloudflare Durable Objects, with persistent session history and recovery after interruptions.

Nanocode's Rust engine runs as WebAssembly and implements Codex and Claude Code prompt and tool conventions. Its Cloudflare host saves turn progress and tool results in SQLite and uses alarms to resume pending work. The Nanocode project maintains the host independently of Cloudflare; it does not require the Agents SDK.

Start with the reference Worker ↗︎ and follow Nanocode on Workers for setup, models, and recovery limits.

Improved Durable Object Startup Placement

Cloudflare has improved how it chooses where to start a Durable Object after the object has been inactive.

Reactivated Durable Objects now start on the machine that last ran them whenever possible, so their data doesn't need to be loaded again.

This can make cold starts less frequent for SQLite-backed Durable Objects that are reactivated soon after going idle. Actual results depend on your workload and traffic patterns.

The change is live in all regions. No action is needed by customers to see benefits from this change.

To learn more about how Durable Objects are placed, refer to Data location.

Improved investigation search for Email security

Email security now has a unified search bar for investigations. It replaces the Email Screener side modal and makes searches easier to refine.

Search with keywords or field:value filters. Autocomplete suggests filters and values as you type. Add terms and press Enter to refine results, or select From, To, Disposition, Status, or Threat type values in results. Narrow results with a date preset or custom range.

The Email Security investigation search bar displays suggestions for disposition, status, threat type, sender, recipient, and other filters

This feature is available to all Email security customers.

Markdown for Agents analytics and tracing

Markdown for Agents is generally available, with new tools to monitor conversions and investigate partial or failed output.

In the Cloudflare dashboard, select your zone and go to Agent Readiness > Markdown for Agents:

  • Analytics shows conversion outcomes, estimated token reduction, top converted pages, top user agents, failure reasons, content limits, and pages with partial or failed conversions.
  • Logs provides sampled conversion events with outcome, failure reason, and content-limit filters.
  • Playground requests Markdown for a page on your zone and compares it with HTML. Inspect the Markdown, preview, response headers, and estimated token reduction.
Markdown for Agents dashboard showing conversion totals, full conversion rate, estimated token reduction, and conversions over time.

The GraphQL Analytics API exposes the same analytics through markdownForAgentsAdaptiveGroups at zone and account scope. Query conversion totals, outcomes, estimated token savings, and page diagnostics over the last seven days. Counts are sample-weighted estimates. Token savings use byte-based estimates from full conversions, not tokenizer counts.

Cloudflare Traces includes a markdown_conversion span for sampled streaming conversions. Inspect conversion outcomes, input and output bytes, converter CPU time, and content-limit flags alongside the rest of the request timeline.

For details and a GraphQL query example, refer to the Markdown for Agents documentation.

Redesigned Bots Directory on Cloudflare Radar, now powered by BotBase

The Cloudflare Radar Bots Directory ↗︎ now uses BotBase, Cloudflare's catalog of the bots and agents it tracks, and has a new design matching the Radar homepage.

Animation filtering the Bots Directory and opening the Cloudflare Crawler bot page, with its Identity and Traffic sections

Each bot page has a new Identity section showing the bot's access level, content use, Web Bot Auth verification, and user agents. Bot operators are also searchable from the Radar site search.

API

The List bots and Get bot details endpoints now describe each bot with:

  • categories: a bot can now have more than one category. Categories follow BotBase's groups, which add COMMERCE, and some older categories are now part of broader groups.
  • accessLevel: DIRECT if the bot reaches websites under its own identity, or INTERMEDIARY if it acts on behalf of another agent or a person.
  • contentUse: full if the content it fetches is kept and reused (for example, for model training or a search index), reference if it is cited or linked back to the source, or immediate if it is used once to answer a user's request.
  • documentationUrl and operatorWebsiteUrl (bot details only).

category and operatorUrl are deprecated in favor of categories and documentationUrl.

Visit the Bots Directory ↗︎ on Cloudflare Radar.

Review provider key activity in AI Gateway

AI Gateway now shows usage activity for your stored provider keys. Use this information to review credentials for rotation or removal.

In Provider Keys, keys are grouped by provider with masked previews, aliases, and last-used and last-updated dates. The Key security section highlights keys with recorded activity older than 90 days. You can review these keys and delete them after checking their dependencies.

Usage tracking starts November 2026.

For details on storing, rotating, and removing provider keys, refer to Bring your own keys.

Sign in to Cloudflare Access with passkeys

Cloudflare Access supports passkeys as a login method for protected applications and the App Launcher. Users can sign in with a passkey saved on their device, security key, or password manager instead of entering a one-time PIN or configuring an identity provider.

Users verify their identity with an existing login method once before enrolling a passkey. Administrators choose which applications accept passkeys and can remove a user's registered passkeys. Access policies still determine whether a user can access an application.

Passkeys identity-provider settings with automatic browser prompts turned on.

For setup and enrollment instructions, refer to Passkeys.

Cloudflare One adds fast flux detection to UEBA

Cloudflare One now includes fast flux detection as a predefined risk behavior for user and entity behavior analytics (UEBA). When enabled, detections contribute to a user's risk score.

Fast flux is a DNS technique that rapidly changes the IP addresses returned for a domain. Threat actors can use it to make malicious infrastructure harder to track and take down. Detecting it can help security teams identify potentially risky activity and investigate it sooner.

To turn on fast flux detection, go to Risk score > Risk behaviors in the Cloudflare Zero Trust dashboard.

Fast flux detection is available on Enterprise plans.

For more information, refer to User risk score.

User API tokens have a redesigned creation experience

User API tokens now use a redesigned dashboard experience that more closely matches Account API tokens, making it easier to create and review user-owned credentials while preserving their user-scoped behavior.

Redesigned User API token creation flow

What's new

  • A more consistent creation flow: User API tokens now follow the same modern dashboard pattern as Account API tokens, including a clearer create and review experience.
  • Improved policy editing: Policies are now easier to read and manage, with inline controls to add, edit, and remove policy blocks before creating the token.
  • Clearer restrictions during setup: Expiration presets and client IP address filtering are built directly into the creation flow so you can review token restrictions in one place.

These tokens still act on behalf of the creating user, even though the dashboard experience is now more consistent with Account API tokens. For more information, refer to Create API token, Create tokens via API, and Account API tokens.

Automatic retries for Durable Object calls

The runtime now retries fetch() and RPC calls to a Durable Object when they fail with a retryable error before reaching it. This applies whether the caller is a Worker or another Durable Object. Short disruptions, such as brief network interruptions, no longer need a retry loop in your code.

By default, the runtime retries a call up to four times, and starts no retry more than 10 seconds after the initial call starts. It does not retry errors thrown by your Durable Object code, or errors with .overloaded set to true.

If the connection drops and the runtime cannot tell whether the Durable Object received the call, it still retries, but the Durable Object rejects the retry if the first attempt arrived. A method never runs twice because of a retry, unless you mark it with retryable() from cloudflare:durable-objects:

src/index.jsjs
import { DurableObject } from "cloudflare:workers";
import { retryable } from "cloudflare:durable-objects";

export class Cart extends DurableObject {
	static {
		retryable(this.prototype.setQuantity);
	}
	// Idempotent: a second run sets the same quantity.
	async setQuantity(itemId, quantity) {
		await this.ctx.storage.put(itemId, quantity);
	}

	// Not retryable: a second run would add another item.
	async addOne(itemId) {
		const quantity = (await this.ctx.storage.get(itemId)) ?? 0;
		await this.ctx.storage.put(itemId, quantity + 1);
	}
}
src/index.tsts
import { DurableObject } from "cloudflare:workers";
import { retryable } from "cloudflare:durable-objects";

export class Cart extends DurableObject {
	static {
		retryable(this.prototype.setQuantity);
	}
	// Idempotent: a second run sets the same quantity.
	async setQuantity(itemId: string, quantity: number): Promise<void> {
		await this.ctx.storage.put(itemId, quantity);
	}

	// Not retryable: a second run would add another item.
	async addOne(itemId: string): Promise<void> {
		const quantity = (await this.ctx.storage.get<number>(itemId)) ?? 0;
		await this.ctx.storage.put(itemId, quantity + 1);
	}
}

To change the limits for one stub, pass a retry option to get() or getByName(). maxRetries accepts 0 to 10 retries, and timeoutMs accepts 500 to 60,000 milliseconds:

src/index.jsjs
const stub = env.CART.getByName("user-123", {
	retry: { maxRetries: 1, timeoutMs: 2000 },
});
src/index.tsts
const stub = env.CART.getByName("user-123", {
	retry: { maxRetries: 1, timeoutMs: 2000 },
});

If you already retry Durable Object calls in your own code, each of your attempts now includes the runtime's retries. Lower your own attempt count, or set maxRetries: 0 on stubs where your code handles retries.

To use retryable() and the retry option, update to Wrangler 4.158.0 or later.

For more information, refer to Automatic retries.

Set expiration dates for Email security policies

Email security now lets you set an expiration date when creating an allow or block policy. This helps you apply temporary policy changes without removing them manually.

After the selected date passes, the policy expires and no longer applies.

This feature is available to all Email security customers, regardless of plan.

Planned model deprecations on Workers AI

We are refreshing the Workers AI model catalog to make room for new releases and updated models. Update your apps to remove references to the models listed below before November 20, 2026. We originally stated these models would be deprecated on November 15, 2026, and have moved the deprecation date to November 20, 2026.

Starting November 20, 2026, these models will stop returning responses. Requests to them will fail with an HTTP 410 Gone error and error code 5028.

We recommend moving to newer models for the best token efficiency and throughput. For pricing, refer to the Workers AI pricing page.

Models deprecated on November 20, 2026

LLMs

  • @cf/deepseek-ai/deepseek-r1-distill-qwen-32b
  • @cf/nvidia/nemotron-3-120b-a12b
  • @cf/deepseek-ai/deepseek-v4-pro-0813
  • @cf/deepseek-ai/deepseek-v4-flash-0731
  • @cf/qwen/qwq-32b
  • @cf/qwen/qwen3-30b-a3b-fp8
  • @cf/moonshotai/kimi-k2.6
  • @cf/moonshotai/kimi-k2.7-code
  • @cf/zai-org/glm-5.2
  • @cf/zai-org/glm-5.3-flash
  • @cf/meta-llama/llama-2-7b-chat-hf-lora
  • @cf/google/gemma-2b-it-lora
  • @cf/google/gemma-7b-it-lora
  • @cf/meta/llama-3.1-8b-instruct-fp8
  • @cf/meta/llama-3.2-1b-instruct
  • @cf/meta/llama-3.2-3b-instruct

Other models

Each deprecated model is followed by its suggested replacement.

For the full list of available models, refer to the Workers AI model catalog.

Route across a pool of models with model aliases

AI Gateway now supports model aliases. A model alias is a pool of models that your application calls by one name, such as custom/support-fast. AI Gateway tries the models in the order you set and falls back to the next one if a request fails, or uses smart routing to choose a model for each request.

Because your application only references the alias, you can swap models or change the routing algorithm on your gateway without redeploying. Create and manage aliases on your gateway's Routing page, alongside dynamic routes.

To call an alias through the REST API, use its name as the model. For example, send this body to /accounts/{account_id}/ai/run:

{
	"model": "custom/support-fast",
	"input": {
		"messages": [{ "role": "user", "content": "Reply with a short greeting." }]
	}
}

Include the cf-aig-gateway-id header to select the gateway where you created the alias. Aliases are scoped to individual gateways.

For setup instructions and routing options, refer to Model aliases.

Granular access controls for the top Personal Agents

The Configure AI bot policies setting is now named AI Crawler and Agent access policies.

Personal agents act on a person's behalf, fetching information or browsing in response to a request. The updated policies let you set actions for the top Personal Agents individually. This gives you control over agent access while allowing visitors to use agents to find answers or compare products using your site's content.

Customize how Personal Agents access your site via Security > Settings > AI Crawler and Agent access policies.

AI Crawler and Agent access policies dialog showing the Agents policy and individual Personal Agents settings

For more information, check out our blog ↗︎ or refer to our documentation for AI Crawler and Agent access policies.

Block data entry with Browser Isolation without losing search, copy, and zoom (beta)

Isolation policies now support a third keyboard option in beta: Allow read-only actions. Previously, the keyboard setting was binary — allow all input or block everything. With Allow read-only actions, you can block data entry while preserving the built-in browser actions your users depend on.

In Allow read-only actions mode, users can still find in page, select all, copy, print, and zoom. All other keyboard input is blocked from reaching the isolated page. Copy and print remain subject to their own policy settings, so the controls compose instead of overriding each other. For example, setting the keyboard to Allow read-only actions and copy to Do not allow lets users search and zoom but prevents them from copying content.

To use this feature, set Keyboard to Allow read-only actions in your isolation policy settings. Via the API, set keyboard to enable_read_only_actions in the biso_admin_controls object with version set to v2.

For more information, refer to Keyboard.

New managed rule to help mitigate CVE-2026-98432.

Cloudflare Network Firewall has a new managed rule to help mitigate the Linux IPv4 TCP use-after-free vulnerability (CVE-2026-98432 ↗︎):

  • Rule name: Block CVE-2026-98432 traffic
  • Rule ID: 6a4df2bf984946a88c74b07349557e83

The rule is disabled by default. To use it:

  1. Go to Networking > Firewall Policies > Managed Rulesets.
  2. Enable the rule with action Log first.
  3. Review traffic that matches the rule.
  4. If the matching traffic is not expected for your environment, change the action to Block.

For more information on enabling managed rulesets, refer to Enable managed rulesets.

For more details about the vulnerability, including an agent assessment prompt and evidence sources, refer to the Cloudflare Radar Zero Wire briefing ↗︎.