Why build a browser for agents

The question of whether Cloudflare should build its own browser has resurfaced internally for years. The browser is the most important software on our computers — effectively the operating system of the Internet — and Cloudflare's mission of helping build a better Internet makes the idea tempting. But the balance between technical difficulty and the unique problems such a project would solve never quite lined up, and the idea was shelved repeatedly.

That balance has now shifted. The Developer Platform has reached a tipping point where several powerful capabilities are mature: WebAssembly (Wasm) in Workers, dynamic workers, SQLite-based Durable Objects, Worker-to-Worker RPC, service bindings, higher NodeJS compatibility, and higher limits. Meanwhile, the rise of AI agents has created urgent demand for a new kind of browser. Browser Run, Cloudflare's headless browser automation API, has grown rapidly with AI adoption — agents need browsers to perform many tasks and often cannot succeed without them.

But browser engines like Chromium were built for humans, not agents. They carry overhead that AI models simply do not need. Memory and compute consumption are so high that giving every agent its own instance is prohibitively expensive, locking out many agentic applications and restricting large parts of the Web to only the most sophisticated AI models.

Agents need a browser excelling at what matters for an AI model, even if that means being light on what's only useful for humans:

  • AI doesn't care about tabs, themes, browser extensions, or cross-device synchronization. It cares about token count, context windows, scalability, performance, and costs.
  • Structured, machine-readable content matters; visual perfection and smooth 60-fps scrolling don't. Agents will be fine if CSS parsing is slightly off or rendering isn't pixel-perfect.
  • The threat model differs with AI. Prompt injection and tool safety are top priorities.

Twelve weeks ago, we asked the question again. This time the answer was unanimous: Yes!

Today we are announcing Kitesurf, a new browser that runs entirely on top of Workers, built specifically for agents and available for free while in beta in Browser Run. Kitesurf is significantly more efficient in CPU and memory consumption than Chromium for common agentic tasks like screenshots and HTML extraction.

From bright idea to working prototype

Kitesurf started the way many Cloudflare projects do: someone found something interesting and ended up "nerd sniping" the rest of the team with an attractive, seemingly impossible idea. The initial inspiration came from obscura, a headless engine written in Rust for AI automation with "no Chrome, no Node.js, no dependencies."

We tried porting it to Workers with the help of an AI agent. Early attempts didn't work well. But once we gave the AI a solid plan and a clear definition of success — detailed enough for the agent to loop endlessly and ask questions when needed — it worked. Blown away by this barely working proof of concept, we decided to let the team cook.

Design decisions

Before we started, we made several explicit design decisions.

Tests, tests, tests

Moving from prototype to a production-ready browser for scale would take significant work and iteration. AI acceleration was key, but quality control required guardrails. The answer was providing as many tests as possible. The Web Platform Tests (WPT) suite offered an extensive set of success criteria, giving AI agents clear goalposts for assessing feature conformance. We curated the selection and order of features assigned to agents, letting humans focus on architecture and review.

WPT tests only measure conformance to W3C standards, not a browser's ability to render and interact with real websites. To bridge that gap, we implemented integration testing with visual regression testing: multistep Puppeteer tests run on real websites against both Chromium and Kitesurf, comparing not just assertions but also rendered outputs at every step to highlight unwanted differences.

Use Rust when possible

Cloudflare has invested significantly in WebAssembly (Wasm) support in Workers, enabling high-performance C, C++, and Rust packages compiled to Wasm. Approaches like Emscripten with its layered mocked dependencies produce bulky, slow compiled binaries. Instead, we used native Rust whenever possible, compiling directly to WebAssembly with wasm-bindgen to avoid emulation layers and run as close to the metal as possible.

Exception handling

A browser must render the unreliable and sometimes hostile web without ever dropping the page it's holding. Exception handling isn't just hygiene — it's how the application survives bad input without crashing. We committed to one rule: any failure degrades to a blank frame or missing element, never a dead session. Catch faults at every boundary, default to something safe and empty, log enough to diagnose.

Isolation

Unlike a browser on your laptop where sites are trusted and resource sharing is acceptable, an agent is pointed at arbitrary code from arbitrary origins. We built Kitesurf on the assumption that every page load is untrusted input and every session starts fresh. Each component is isolated with access only to the resources strictly necessary for its function.

This fits naturally with Cloudflare Workers' isolation-by-design security model. But the platform only provides boundaries between isolates; we still enforce the same principle at the application level, deciding what each component may touch and ensuring nothing leaks across pages.

Stateless whenever possible

State is what makes failure expensive — without state to reconstruct, recovery from a crash means starting fresh and replaying the request. Stateless components are disposable and parallel: kill them when they stall, run thousands at once, size them to demand instead of keeping them warm. That fits automation, where load arrives in bursts and the cheapest work is what uses only what it consumed and vanishes when done. Wherever a component can be stateless, it should be.

Architecture: three Workers, one browser

Kitesurf's request lifecycle breaks down across three stateless or semi-stateful components — Engine, PageScript, and PageRenderer — plus a dedicated outbound worker for all network traffic.

BLOG-3466 4.png

The Engine

The Engine is the only public-facing component. It accepts Chrome DevTools Protocol (CDP) WebSocket connections and HTTP REST requests, serves the internal test landing page, and stores session state. Everything else is stateless.

BLOG-3466 6.png

CDP compatibility is a deliberate design choice: Puppeteer, Playwright, chrome-remote-interface, and the genuine Chrome DevTools frontend can all point at Kitesurf without modification. That is also how Browser Run's existing CDP endpoint works.

PageScript and Dynamic Workers

Every page and out-of-process iframe (OOPIF) gets its own long-lived PageScript isolate, created on demand via Dynamic Workers. Each isolate has a clean globalThis and a DOM document object populated from HTML parsing and JavaScript execution. HTML and CSS parsing leverages parts of Blitz and Stylo — Firefox's CSS parser — both in Rust. Every <script> tag and .wasm file runs inside the same isolate.

BLOG-3466 7.png

Evals are the exception. Workers does not support native eval, and a separate isolate would lose access to globalThis. Kitesurf's workaround is Boa JS, a Rust ECMAScript engine, compiled to run on Workers — a runtime on top of a runtime that is not optimal but handles the occasional eval. Native eval support in Workers would allow migrating away from Boa.

PageRenderer

PageRenderer generates pixels from the computed page objects. It operates in a loop with the Engine: each frame request pulls the page object (scene) from PageScript, fetches internal fonts and images from Static Assets, rasterizes everything into an image buffer via the blitz-paint module, and returns the buffer as a renderable format. Workers' built-in RPC system connects the components — the Engine makes a single renderFrame() call and receives a PNG. Because the renderer holds only a disposable cache, it can be killed and relaunched on any failed or stuck RPC call.

All outbound traffic goes through one door

Fetching arbitrary images, fonts, CSS, JavaScript, and Wasm from the Internet is the highest-risk operation a browser performs. In Kitesurf, only the SandboxOutbound worker touches the network, enforced by Dynamic Workers. The Engine uses it to bootstrap the main document; PageScript fetches stylesheets, images, fonts, and the page's own fetch() calls.

SandboxOutbound enforces CORS, injects browser-shaped headers, filters responses, and keeps each page's cookies isolated in their own jar. Anything that fails policy returns a 403.

BLOG-3466 5.png

Compliance and performance numbers

Kitesurf currently passes more than 215,000 WPT tests, with hundreds added weekly. Coverage is strongest for what matters to agents — CSS, DOM, HTML, selection, SVG, and XHR — with streams also adequately supported.

BLOG-3466 9.png
BLOG-3466 10.png

Performance medians from five Browser Run quick-action runs across a 14-URL corpus show Chromium about 1.7x faster on wall time; the gap comes primarily from rasterization and JPEG/PNG encoding. Kitesurf wins on memory and CPU by 3-7x, which translates directly to cost — lower resource usage enables more concurrent sessions and better scaling.

Metric

Kitesurf

Chromium (warm pool)

Kitesurf, relative

CPU: screenshot

380 ms

1,173 ms

3.1× less CPU than Chromium

CPU: HTML extraction

229 ms

877 ms

3.8× less than Chromium

Memory: screenshot

57.8 MiB

271.0 MiB

4.7× less than Chromium

Memory: HTML extraction

39.4 MiB

273.7 MiB

7.0× less than Chromium

Wall time: screenshot

1,148 ms

637 ms

1.8× slower than Chromium

Wall time: HTML extraction

820 ms

472 ms

1.7× slower than Chromium

Trying Kitesurf today

Kitesurf is available in Browser Run for free during beta, subject to per-account limits. Existing clients — Puppeteer, Playwright, chrome-remote-interface, or AI agents speaking MCP and CDP — work by adding browser=kitesurf to Browser Run's CDP endpoint or quick-action endpoints.

{
  "mcp": {
    "kitesurf": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "chrome-devtools-mcp@latest",
        "--wsEndpoint=wss://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-run/devtools/browser?browser=kitesurf",
        "--wsHeaders={\"Authorization\":\"Bearer <API_TOKEN>\"}"
      ],
      "enabled": true
    }
  }
}
curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<accountId>/browser-run/screenshot?browser=kitesurf' \
  -H 'Authorization: Bearer <apiToken>' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://example.com"
  }' \
  --output "screenshot.png"

A public playground at kitesurf.cloudflare.app includes injected Chrome DevTools for inspecting expanded DOM, console messages, and network activity. The Memory panel reports the WebAssembly footprint per isolate, including frames, to show per-page resource consumption.

BLOG-3466 12.png

Where Kitesurf fits — and where it doesn't

Kitesurf renders TodoMVC (vanilla, React, Vue, Angular, Preact), Wikipedia, Hacker News, the Cloudflare Blog, and much of the Cloudflare dashboard correctly today. It suits AI agents requiring page rendering without pixel-perfect Chromium fidelity, plus one-shot quick actions like content extraction, PDFs, or screenshots. It is an ephemeral, fully-isolated, stateless engine for bursty AI workloads.

The current limitations are concrete: no video playback, no WebGL, no bot-challenge handshakes with real TLS fingerprints, and no long-lived authenticated sessions. For those, Browser Run's default Chromium remains the option. The only reliable compatibility test is trying the target site in the playground or via API.

Roadmap

Kitesurf's first commit was May of this year. Active work focuses on four areas:

  • CDP coverage — expanding beyond the subset needed for DOM and network inspection toward more complete protocol support.
  • Rendering fidelity — improving screenshots and PDFs, since LLMs often work better from images than text.
  • WPT coverage — adding more web APIs and passing more tests toward production readiness.
  • Efficiency — continuous CPU, memory, and wall-time benchmarking alongside other Developer Platform teams.

Early days and what comes next

Kitesurf is still in its early stages, but it's available now for hands-on testing. The team plans to ship frequent updates focused on performance, efficiency, and compatibility as it gathers feedback from early users.

There's also a commitment to open sourcing Kitesurf once the team feels it's ready, with the goal of letting any customer deploy their own version on their own Cloudflare accounts.

You can try it out in the playground, track changes in the official changelog, and reach the team on Discord. Feedback will be actively reviewed as development continues.