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.
Personal Agents inherit your existing Agents policy by default. Cloudflare recommends Allow (do not block) for Personal Agents.
AI Search billing has been postponed by one month and now begins on December 1, 2026, instead of November 1, 2026. You will not be charged for AI Search usage before December 1, 2026. Pricing and included usage are unchanged.
The default sync interval for AI Search instances is changing from 6 hours to 24 hours. You can still choose any supported interval, from 15 minutes to 24 hours, with the Sync interval setting in your instance settings or the sync_interval field in the API.
You can now assign key-value tags to Access service tokens and use those tags to organize credentials or control application access. Each token supports up to five tags, such as environment: production or team: payments.
Add or edit tags when you create or update a token in the dashboard or service token API. You can search and filter by tag on the Service Tokens page. Tags also appear in Resource Tagging, where you can query them alongside other tagged resources.
The Service Token Tag policy selector matches valid tokens with an exact key-value pair. Use it in a Service Auth policy to authorize tokens by environment or team without listing each token individually. For example, this API policy configuration accepts valid tokens tagged environment: production:
Flagship bindings now evaluate flags against a local flag store during local development, instead of calling your remote app. You can develop offline and test flag changes without affecting production. This applies to wrangler dev, the Cloudflare Vite plugin, the Vitest integration, and cf dev.
The local store starts empty, so evaluations return the default value you pass in code. Add and manage local flags in any of these ways:
Wrangler — Add --local to wrangler flagship flags commands, such as create, update, and evaluate. To copy all flags from your remote app, run npx wrangler flagship flags pull <APP_ID>.
Local Explorer — Create, edit, toggle, and evaluate flags in Local Explorer while your dev server runs.
To keep evaluating against your remote app instead, set remote: true on the binding.
The local flag store requires Wrangler v4.135.0 or @cloudflare/vite-plugin v1.56.0 or later. Flagship in Local Explorer requires Wrangler v4.148.0 or @cloudflare/vite-plugin v1.63.0 or later.
Starting November 17, 2026, JavaScript Workers with a compatibility date of 2026-11-17 or later will use the new module registry by default. You will no longer need the new_module_registry flag for these dates. Python Workers keep using the legacy registry.
The module registry finds and loads JavaScript modules in your Worker. We announced the new registry in September 2026 ↗︎. It improves compatibility with JavaScript standards and Node.js. In Workers using Node.js compatibility, you can use require() to load ES modules. The module and its dependencies must not use top-level await.
You can also use import.meta to get information about the current module and find the URL of another module without loading it:
When deployed with src/index.ts as the unbundled entrypoint, isEntrypoint is true. helperUrl is a URL within your Worker bundle. Resolving the URL does not check whether the module exists or load it over the network. Build tools may transform import.meta. To try this example directly, refer to unbundled deployments.
Existing Workers keep their current behavior until you change their compatibility date or flags. To try the new registry before November 17, keep your current date and add new_module_registry to your compatibility flags.
Before updating, check your dependencies for invalid import attributes and changes to require() behavior. The new registry rejects invalid import attributes. Calls to require() also fail if the module or any of its dependencies use top-level await. To keep the legacy registry with a compatibility date of 2026-11-17 or later, add legacy_module_registry.
Starting November 17, 2026, Workers with a compatibility date of 2026-11-17 or later will receive client disconnection events through request.signal by default. Use these events to stop unnecessary work when a client leaves. You will no longer need the enable_request_signal compatibility flag for these dates.
Existing Workers keep their current behavior until you change their compatibility date or flags. To try this feature before November 17, keep your current date and add enable_request_signal to your compatibility flags.
With a compatibility date of 2026-11-17 or later, add disable_request_signal to opt out. This change does not enable request_signal_passthrough. Pass the signal explicitly, as the example does.
The SCIM population viewer lets you inspect the users and groups provisioned to Cloudflare One by each identity provider. You can check which resources Cloudflare has received without making API requests or opening a support ticket.
In Zero Trust > Integrations > Identity providers, select a user or group count in SCIM resources to open the viewer. You can:
Search users by username, email, name, or resource ID, and groups by name or resource ID.
Inspect resource attributes in formatted or JSON views.
View group members and compare Cloudflare and IdP resource IDs with provisioning logs.
Delete individual resources from the Cloudflare SCIM population when you have edit permission.
The viewer shows provisioned resources rather than provisioning event history. Use SCIM provisioning logs to investigate failed requests. Existing SCIM deprovisioning and policy behavior remain unchanged.
Audit Logs v2 now includes analytics for account-level audit logs in the Cloudflare dashboard. The Actions over time chart separates successful and failed actions for the selected time range.
Summary cards show Total actions, Unique actors, Products impacted, and Failure rate. Select a card to investigate action types, authentication methods, top actors, top products, or failed actions. You can apply or exclude values as filters to update both the analytics and audit log table.
Account analytics are not available for organization-level audit logs.
Browser Run now runs Chrome 152 by default. Your sessions get current web platform features, rendering fixes, and security patches. You do not need to change your code.
This release also includes the following improvements:
Updated default User-Agent. The default User-Agent for Quick Actions now reports Chrome 152 instead of Chrome 119. If you allowlist or match the Browser Run User-Agent, update your rules. You can still set your own value with the userAgent parameter. Refer to Automatic request headers.
Better site compatibility. Quick Actions requests now look more like requests from a regular Chrome browser, so fewer sites block them.
Large response headers. Pages that return large response headers now load correctly.
Updated root certificates. Browser Run removed distrusted root certificates from its trust store.
Absolute links./links now returns absolute URLs, and links-only crawls now follow relative links.
Better Markdown output./markdown and crawl Markdown output now keep code block languages.
Clearer errors. Quick Actions that time out now return a consistent error. Outbound Workers that throw an exception now return an HTTP error to the browser.
Beginning Wednesday, November 4, 2026, D1 will enforce a maximum query result size of 50 MB. Queries that return a result larger than 50 MB will fail and return the following error:
D1 query result exceeded the maximum response size limit of 50 MB
The 50 MB limit covers the 99.999th percentile of requests across D1, so most D1 users will not be impacted.
Import and export operations via the REST API are not subject to this limit and will continue to work as they do today.
If your queries return large results, reduce the result size before the enforcement date. For example, select only the columns you need instead of using SELECT *, and paginate large result sets with LIMIT and OFFSET.
Cloudflare WAN traffic can now use a Gateway processing region with Regional Services. HTTPS traffic enters a Cloudflare data center (that may be outside the selected region) via an IPsec or GRE tunnel, or through Direct CNI, and remains encrypted until Gateway forwards it to the selected region for TLS decryption and HTTP inspection. This feature gives organizations control over where their sensitive traffic is processed, supporting their data sovereignty goals.
This feature requires unified routing. The processing region applies to Gateway HTTP traffic and does not apply to Gateway DNS or network policy processing.
Contact your account team to configure a processing region. For supported regions, configuration details, and limitations, refer to Data residency for Cloudflare One.
The new DNS records experience announced in May is now the default for all users on all plans, including Enterprise. The classic DNS records page has been retired and is no longer available in the Cloudflare dashboard.
Changing a record's type
When the new experience first launched, it did not support changing the type of an existing DNS record. Based on your feedback, we have since added this, so you can now change a record's type (for example, from A to CNAME) directly from the DNS records page. Under the hood, the dashboard uses the batch DNS records endpoint for this.
Questions or feedback
If you run into an issue with the new experience, contact your account team or Cloudflare Support.
Durable Objects can stay active across requests, allowing you to run long-running agents, maintain long-lived WebSocket connections and coordinate state across many clients. This is possible because each Durable Object is globally unique, and this means it must run only one version of your code at a time. Previously, when you deployed a change to your Durable Objects code, that change would be applied immediately, which could interrupt in-flight work and terminate open connections.
Durable Objects now defer code updates by default. When you deploy, an active Durable Object can keep running its current code for up to 5 minutes (300 seconds) while it waits to hibernate. This gives in-flight work time to finish. WebSocket connections that use the Hibernation API remain connected when an object adopts new code after hibernating.
For an active Durable Object, a code update follows this flow:
flowchart TD
accTitle: Code updates for an active Durable Object
accDescr: By default, an active object can keep running its current code until it hibernates or the delay ends. After hibernating, it starts on new code on the next request. If the delay ends first, or immediate mode is selected, it resets and adopts the new code. Deferral is best effort.
A["You deploy new code"] -->|"Default: deferred"| B["The object can keep running<br/>its current code"]
B --> C{"Hibernates before<br/>the delay ends?"}
C -->|Yes| D["Starts on the new code<br/>on the next request"]
C -->|No| E["The object resets<br/>and adopts the new code"]
A -.->|"Override: immediate"| E
To change the delay, add code_update_strategy to durable_objects in your Wrangler configuration:
max_delay is in seconds, from 0 to 86400 (24 hours), with millisecond precision. Omit it to use the default of 300 seconds.
To set the strategy for a single deployment, pass --durable-objects-code-update-mode with immediate or deferred <duration>. For example, apply an update right away during an incident, or when your deployment tooling calls a Durable Object right after deploying and needs the new code:
A deferred code update is best effort and does not guarantee that every operation finishes. The object can still reset before max_delay is reached, for example during a Cloudflare runtime update.
For more information, including how this interacts with gradual deployments and the REST API, refer to Durable Objects code updates.
Keyless SSL supports TLS 1.3 for ECDSA certificates. When TLS 1.3 is enabled on your zone, visitors connecting to a hostname that serves a Keyless ECDSA certificate negotiate TLS 1.3, and your private keys stay on your own key server.
Keyless SSL connections that use RSA certificates continue to negotiate up to TLS 1.2.
This emergency release adds a new rule to the Cloudflare Managed Ruleset, disabled by default, for a vulnerability in Nuxt Image and IPX. The rule offers partial coverage. Please follow the advisory and patch to the latest version.
This release introduces updates to the underlying rule expressions for PHP out-of-memory (OOM) vulnerabilities CVE-2026-109618, CVE-2026-109619 and CVE-2026-115560. The improvements are iterative changes based on reports from Security Researchers as part of PHP Capture the Flag (CTF) challenge ↗︎.
Cloudflare now preserves Workers context when a subrequest targets a Cloudflare-proxied hostname using Bring Your Own IP (BYOIP). These requests are identified as Cloudflare-to-Cloudflare traffic instead of external Internet traffic.
Previously, some BYOIP subrequests could lose Workers context and original client signals. This could cause security rules to behave unexpectedly, Bot Management to evaluate an internal Cloudflare connection instead of the original client, or affected requests to return false 403 responses.
Workers subrequests to BYOIP destinations now preserve the CF-Worker header and cf.worker.upstream_zone field. This supports consistent security rule evaluation across same-zone and cross-zone subrequests.
Bot Management fields on the destination zone now represent the original end-user connection for affected BYOIP subrequests. Bot scores, verified bot status, and JA3/JA4 fingerprints no longer represent the internal connection between Cloudflare services.
Because Cloudflare-proxied BYOIP destinations now follow standard Workers subrequest handling, cross-zone requests set CF-Connecting-IP to the Workers client IP address 2a06:98c0:3600::103 for security reasons. This applies when a Worker in one Cloudflare zone sends a subrequest to a hostname in another Cloudflare zone. Same-zone subrequests continue to reflect the client IP through CF-Connecting-IP.
Agent Skills in the Cloudflare Agents SDK are now files. Write a folder with a SKILL.md into your agent's Computer ↗︎ Workspace, under /workspace/.agents/skills/, and the agent can use it on its next turn. You do not need a build step or a deploy, and the agent can write its own skills.
Three sources. Load skills from a Computer Workspace, an R2 bucket, or code. Think lists every source again before each turn.
The open format. Every SKILL.md is checked against the Agent Skills specification ↗︎. As the specification's guide for agents recommends, a skill that breaks a rule still loads, with a logged warning. Use parseSkill() to check a skill before you write it.
Scripts in the Workspace. Skill scripts are Workspace files, and the model runs them with the Workspace exec tool. Refer to Execution.
Skill tools for any harness. Use the same activate_skill and read_skill_resource tools in Think, Pi Durable, or the AI SDK. Refer to Skills tools.
Warm prompt caches. When a skill changes mid-conversation, Think sends the new catalog as a reminder instead of rebuilding the cached system prompt. An overridden getSystemPrompt() now stays at the top of the system prompt, above context blocks.
This is a breaking change for code that uses agents/skills directly. The agents:skills Vite import, agents/skills/compile, SkillRegistry, and Think's skillWorkspace are removed, and runner() moved to agents/skills/runner. Install Agents SDK v0.32.0 ↗︎ and Think v0.23.0 ↗︎ or later. Refer to the computer-skills ↗︎ and r2-skills ↗︎ examples.
The Cloudflare dashboard now includes a Data Localization Suite Overview, a read-only view of the data localization settings on your account. It shows your Regional Services, Customer Metadata Boundary, and Geo Key Manager settings in one place, so you no longer need to check several dashboard pages and APIs to see where your traffic is processed and where your logs and private keys are stored.
To find it, go to Application Security > Data Localization Suite, or search for "DLS" in the dashboard.
The Overview has a tab for each product:
Regional Services: regionalized hostnames (filter by region or zone), regionalized IP bindings, and regionalized Spectrum applications, each with its region.
Customer Metadata Boundary: whether the boundary is on, the region (US or EU), and whether out-of-region access is allowed.
Geo Key Manager: every custom certificate with a geo policy, with its hostname, zone, region, and status.
Each item links to the dashboard page where you change its setting, and each tab links to the product's documentation.
System for Cross-domain Identity Management (SCIM) is an open standard that synchronizes user identities between an identity provider and a service. For more information, refer to SCIM provisioning. Google Workspace is rolling out custom SCIM profiles in beta. Organizations with access to the feature can use Google's built-in provisioning service to send user updates and deprovisioning events to Cloudflare One.
You must use a generic SAML identity provider in Cloudflare One. The dedicated Google Workspace integration does not support SCIM. Configure a SAML app in Google, then enter the Cloudflare SCIM endpoint and secret in the app's autoprovisioning settings. Turn on Enable user deprovisioning in Cloudflare One to revoke active Access sessions when Google deprovisions a user. Google's configured deprovisioning delay still applies. Support for the existing Google Workspace OIDC client will be added once Google adds support for OIDC + SCIM.
Group membership is configured separately. Have the Google SAML app send a groups attribute to include the user's selected Google groups during authentication. Selecting groups as a SCIM provisioning scope does not synchronize group membership, Google is still adding support for this in their SCIM provider.
Cloudflare One users must first authenticate to Access or register a device with the Cloudflare One Client before SCIM updates can apply. Availability of custom SCIM profiles depends on Google's beta rollout.
MCP tool-call analytics support a response_status query parameter on the account, portal, and server timeseries endpoints. Use success, error, or cached to count one status, or all to include every status.
The default is success. Previously, counts included failed and cached calls. If you need the previous all-status counts, set response_status=all explicitly:
GET /accounts/{account_id}/access/ai-controls/mcp/analytics/tool-calls/timeseries?response_status=all
The response includes the selected response_status. Invalid values, including an empty value, return 400.
Agents that build websites need to check their work in a real browser. Internal hostnames let your agent's browser preview a dev server running in a container without exposing that server to the public Internet.
With internal hostnames, the persistent browser in the Cloudflare Agents SDK can open sites that only your agent serves. Give the browser hostnames such as preview.internal, and its requests to them go to your agent instead of the Internet. The model can check a dev server in its sandbox, a folder in its workspace, or another Worker in the same browser it uses for the web, and nothing is exposed publicly.
Each internal host has a fetch function that runs in your Durable Object, so it can use the object's bindings and state. A host can also send its requests straight to another Worker through a service binding. Add a target schema to a host, and the model chooses what it serves, such as which port or which folder.
Internal hostnames are a capability of the browser, independent of your agent harness. Use the built-in adapters for Pi Durable, AI SDK, and TanStack AI, or connect another harness by implementing a tool with browser.session(). No prebuilt adapter is required.
This example adds a private dev-server preview to a Pi Durable agent. Start with that guide's packages, bindings, and request handler, and install Agents SDK v0.31.0 ↗︎ or later. The example has three parts:
Browser configuration:internalHosts defines how the browser reaches the dev server.
Durable Object wiring: Lifecycle and fetchInternalHost() connect the browser to your application.
Harness integration:browserTool from agents/browser/pi registers the tool with Pi.
import { DurableObject } from "cloudflare:workers";import { createModels } from "@earendil-works/pi-ai/models";import { createRegistry, Harness } from "@earendil-works/pi-durable";import { Browser, browserRun } from "agents/browser";import { browserTool } from "agents/browser/pi";import { PiHarness } from "agents/harness/pi";import { Lifecycle } from "agents/lifecycle";import { createAI } from "agents/models/pi-ai";import { z } from "zod";// Your own code: reach a port on your sandbox and return its Response.import { fetchSandboxPort } from "./hosts";// Browser Run calls back into your Worker through this entrypoint.export { InternalHostRouter } from "agents/browser";export class BrowserAssistant extends DurableObject { ai = createAI({ binding: this.env.AI }); registry = createRegistry(); browser = new Browser({ provider: browserRun(this.env.BROWSER, { internalHosts: { router: this.ctx.exports.InternalHostRouter, hosts: { "preview.internal": { description: "Your dev servers", // What the model passes to browser.assignHost() to choose // what this host serves. fetch receives it as its second argument. target: z.object({ port: z.number().int().min(1024) }), fetch: (request, { port }) => fetchSandboxPort(port, request), }, }, }, }), }); harness = new PiHarness({ harness: ({ storage, context, onWake }) => { const models = createModels(); models.setProvider(this.ai.provider); this.registry.install({ name: "browser", tools: [ browserTool({ browser: this.browser, loader: this.env.LOADER }), ], }); return Harness.open( storage, { models, registry: this.registry, onWake }, context, ); }, defaults: { model: this.ai("@cf/zai-org/glm-5.3-flash") }, }); lifecycle = Lifecycle.install(this).use(this.browser).use(this.harness); // InternalHostRouter calls this method to reach your Browser. fetchInternalHost(message) { return this.browser.fetchInternalHost(message); } async ask(prompt) { const { text } = await this.harness.prompt(prompt); return text; }}
import { DurableObject } from "cloudflare:workers";import { createModels } from "@earendil-works/pi-ai/models";import { createRegistry, Harness } from "@earendil-works/pi-durable";import { Browser, browserRun, type InternalHostMessage } from "agents/browser";import { browserTool } from "agents/browser/pi";import { PiHarness } from "agents/harness/pi";import { Lifecycle } from "agents/lifecycle";import { createAI } from "agents/models/pi-ai";import { z } from "zod";// Your own code: reach a port on your sandbox and return its Response.import { fetchSandboxPort } from "./hosts";// Browser Run calls back into your Worker through this entrypoint.export { InternalHostRouter } from "agents/browser";export class BrowserAssistant extends DurableObject<Env> { ai = createAI({ binding: this.env.AI }); registry = createRegistry(); browser = new Browser({ provider: browserRun(this.env.BROWSER, { internalHosts: { router: this.ctx.exports.InternalHostRouter, hosts: { "preview.internal": { description: "Your dev servers", // What the model passes to browser.assignHost() to choose // what this host serves. fetch receives it as its second argument. target: z.object({ port: z.number().int().min(1024) }), fetch: (request, { port }) => fetchSandboxPort(port, request), }, }, }, }), }); harness = new PiHarness({ harness: ({ storage, context, onWake }) => { const models = createModels(); models.setProvider(this.ai.provider); this.registry.install({ name: "browser", tools: [ browserTool({ browser: this.browser, loader: this.env.LOADER }), ], }); return Harness.open( storage, { models, registry: this.registry, onWake }, context, ); }, defaults: { model: this.ai("@cf/zai-org/glm-5.3-flash") }, }); lifecycle = Lifecycle.install(this).use(this.browser).use(this.harness); // InternalHostRouter calls this method to reach your Browser. fetchInternalHost(message: InternalHostMessage) { return this.browser.fetchInternalHost(message); } async ask(prompt: string) { const { text } = await this.harness.prompt(prompt); return text; }}
To use another harness, keep the browser configuration. Choose a browser-tool adapter if one is available, or implement a tool using browser.session().
browserTool tells the model about each host, including the schema of its target. Because preview.internal has a target schema, the model can choose which port it serves. To check its dev server, the model calls browser.assignHost() with a target that matches the schema, such as { port: 5173 }, and opens the URL it gets back:
The target is checked against the schema and stored, so it lasts across turns, browser restarts, and redeploys. Each request to http://preview.internal/ then calls the host's fetch function with { port: 5173 }.
This release also simplifies browserTool. It runs the model's code in its own Dynamic Worker and no longer needs a CodemodeRuntime export. Refer to the v0.31.0 upgrade notes ↗︎ if you already use browserTool.
For the complete example, limits, and security guidance, refer to Internal hostnames.
Challenge Pages served through the Cloudflare China Network now use Turnstile widgets hosted in Mainland China. This means that visitors in Mainland China can complete challenges faster and more reliably because widgets no longer need to make cross-border requests.
You do not need to take any action: this change applies automatically when a China Network zone presents a Challenge Page. Visitors served by Cloudflare's global network will continue to receive the global Challenge Page experience.
This release introduces updates to the underlying rule expressions for PHP out-of-memory (OOM) vulnerabilities CVE-2026-109618, CVE-2026-109619 and CVE-2026-115560. The improvements are iterative changes based on reports from Security Researchers as part of PHP Capture the Flag (CTF) challenge ↗︎.
VPC Network bindings can select a specific virtual network by setting network_id to cf1:vnet:<UUID>, where the UUID is the ID of the virtual network. Continue to use cf1:network to select your account's default virtual network.
Multiple bindings can select different virtual networks. This lets one Worker reach separate backends that use the same private IP address: