Cloudflare built a browser for AI agents, Kitesurf — and cut CPU and memory use by 3–7x
- Cloudflare built a browser from scratch that runs entirely on its own Workers platform, tailored for AI agents. It's in free public beta as of today.
- The trade-off is deliberate: tabs, themes, extensions, and pixel-perfect rendering are gone, in exchange for 3–4x lower CPU usage and 5–7x lower memory usage.
- Built in 12 weeks, with the first version ported by an AI. They also shared how they kept a complex AI-written project from spiraling out of control.
What exactly is Kitesurf?
In short, Cloudflare built a lightweight browser purpose-made for AI agents, and it runs directly inside the V8 isolateHow Cloudflare Workers executes code: instead of spinning up a VM per script, it runs many small isolated compartments inside a single V8 engine process. Fast to start, low overhead. architecture of Cloudflare Workers — a much lighter-weight way to run code than a virtual machine.
It's free for public beta today inside Browser Run. Migration cost is close to zero: add one parameter to your API call and you're switched over. Your existing Puppeteer or Playwright code doesn't need a single line changed.
Why build a browser at all: Chromium was made for people
For years at Cloudflare, the question "should we build our own browser?" resurfaced every few months. Each time it was shelved — the technical difficulty and the question of what unique problem it would solve never quite aligned.
This time the answer flipped to "yes" because two things hit a tipping point at once. The platform side matured: WebAssembly on Workers is solid now, and once Dynamic Workers, SQLite-backed Durable Objects, and direct Worker-to-Worker calls were all in place, complex applications that weren't possible before became feasible. The demand side pushed hard: Browser Run, Cloudflare's headless browser automation product, grew fast alongside the AI boom — and agents simply can't do much of their work without a browser.
The catch was this: traditional browsers are designed for humans, with polished UI, tabs, rich extensions, and smooth 60fps scrolling. All of that makes them so memory- and CPU-hungry that giving every agent its own instance becomes prohibitively expensive. The result: most of the web stays out of reach for all but the priciest, most capable models, keeping many agent applications locked out.
But AI agents don't care about any of those frills. They laid out what each side actually needs, side by side. That table is the conceptual core of the whole piece:
The half you can cut
- Tabs
- Themes & skins
- Browser extensions
- Cross-device sync
- Pixel-perfect rendering
- Silky 60fps scrolling
The half that stays
- Token count
- Context window
- Scalability
- Performance
- Cost
- Structured, machine-readable content
There's another line that's easy to miss: the threat model is different. A human opens a browser to visit sites they know; an AI drives a browser wherever the task points it. New problems like prompt injection and tool security become the top priority in this scenario.
So 12 weeks ago, they asked the old question once more. This time it passed unanimously: build it. Strip everything only a human would want visually or functionally, and keep only the core capabilities an AI can use.
What makes it worth it: massive cost savings, fully stateless, drop-in compatible
1. Extremely cheap on resources (the core value)
This is the most direct comparison against standard Chromium. The benchmark opponent here is a warm Chromium — one that's pre-heated and ready to take work immediately.
The raw numbers, in full:
| Metric | Kitesurf | Chromium (warm) | Delta |
|---|---|---|---|
| CPU · screenshot | 380 ms | 1,173 ms | 3.1x less |
| CPU · HTML extraction | 229 ms | 877 ms | 3.8x less |
| Memory · screenshot | 57.8 MiB | 271.0 MiB | 4.7x less |
| Memory · HTML extraction | 39.4 MiB | 273.7 MiB | 7.0x less |
| Wall time · screenshot | 1,148 ms | 637 ms | 1.8x slower |
| Wall time · HTML extraction | 820 ms | 472 ms | 1.7x slower |
The point: memory and CPU are the bill. Cutting them by 3 to 7 times means the same spend now runs several times more agents at once. That's the entire reason this browser exists.
The trade-off / the small catch: wall time per page render is 1.7 to 1.8 times slower than Chromium. The official explanation: a JIT that has already seen a page is always going to be faster than a cold-start software renderer. The gap is mostly in rasterization and JPEG/PNG encoding, and they're still optimizing it. Trading a little wait time for 3 to 7 times the resources is a good deal for AI automation workloads.
Data and explanation from the Kitesurf launch post
2. Fully stateless and strongly isolated
The whole thing runs on Workers, treating every page load as untrusted input and starting every session from scratch. Of the three components, only the engine holds any state; everything else is stateless. With nothing to rebuild, recovering from a crash is just starting a new one and replaying the request.
The benefits are tangible: a page crashing doesn't take down the whole system, a stuck render can be killed and restarted on the spot, and you can run a thousand sessions at once without having to keep them all alive.
3. Drop-in compatible: switch with one parameter
It speaks standard CDPChrome DevTools Protocol — the protocol Chrome's devtools use to talk to the browser. Puppeteer, Playwright, and similar automation tools all drive the browser through it. (Chrome DevTools Protocol). That means whatever you're already using — Puppeteer, Playwright, chrome-remote-interface, or any AI framework that speaks MCP and CDP — switches over seamlessly by changing a single URL parameter. Not one line of code changes.
On spec conformance, it has already passed 215,000+ tests in the WPTWeb Platform Tests — a large public test suite that checks how well a browser implements web standards. (Web Platform Tests), with a few hundred more added each week.
Breaking it down by area is more revealing: the parts agents actually use are covered well, but the same table shows some notably low numbers:
| Test area | Subtest pass rate | Test area | Subtest pass rate |
|---|---|---|---|
| encodingCharacter encoding | 99.5% | streamsStreams | 76.4% |
| selectionText selection | 98.8% | fetchNetwork requests | 58.6% |
| domDocument Object Model | 97.0% | wasmWebAssembly | 51.1% |
| svgVector graphics | 96.9% | domparsingDOM parsing | 45.1% |
| xhrLegacy async requests | 94.7% | webidlInterface definitions | 43.5% |
| htmlHTML spec | 94.1% | webmessagingCross-window messaging | 26.0% |
| cssStyling | 84.0% | close-watcherClose gesture | 0.0% |
And then the classic test: it runs Doom. Their words: no matter how many tests you have, a project isn't truly done until it runs Doom.
Technical architecture: three modules plus one network exit
The one thing to remember from this whole diagram: who holds state, who doesn't, and who can touch the network.
Engine: the only externally facing component. It handles CDP WebSocket and HTTP interfaces and stores the state for each session. The name sounds the most intimidating, but it's actually the simplest of the three.
PageScript (scripting and parsing): every time a new page or cross-process iframe opens, it spins up a long-lived isolated environment via Dynamic Workers, with a clean global object and DOM document. HTML and CSS parsing use parts of Blitz (a modular rendering engine) and Stylo (Firefox's high-performance CSS parser) — both written in Rust.
There's a detail worth pausing on: what about eval in web pages? Workers still doesn't natively support eval for security reasons. You can't spawn a separate isolated environment to handle it either, because then it wouldn't have access to the page's global object. Their solution: use Boa JS (a JavaScript engine written in Rust) compiled to run on Workers. That's one runtime running on top of another — they admit it's not elegant, and it isn't, but it's good enough for the occasional eval that appears in real code. The moment Workers supports eval natively, Boa gets swapped out.
PageRenderer: takes the page object (they call it a "scene") produced by PageScript, pulls in fonts and images, rasterizes it into an image buffer, and returns JPEG / PNG / PDF as the client requested. It holds no page state — only a disposable cache — so if a render call fails or hangs, the engine can just kill and restart it. Every render request is self-contained and retryable.
SandboxOutbound (network exit): rendering an untrusted webpage means going out to the internet to fetch arbitrary resources — images, fonts, CSS, JavaScript, Wasm files. That's one of the most dangerous things a browser can do. Kitesurf narrows it all down to one component; nothing else can touch the network, and Dynamic Workers enforces this. It executes CORS policies, injects browser-shaped request headers, filters responses, keeps each page's cookies in a separate jar, and returns 403 for anything that violates policy.
How it was built in 12 weeks
This is the most takeaway-friendly part of the whole post: how to hand an AI a job that's complex and easy to lose control of.
The starting point was an open source project called obscura — a headless engine written in Rust, with "no Chrome, no Node.js, no dependencies" as its pitch.
They had an AI agent try to port it to Workers. The first attempts were bad. The turning point: they gave the AI a solid plan plus a clear definition of success, detailed enough that the agent could keep looping on its own and know when to come back and ask questions. And then it worked. Once they saw that barely-functional prototype, the team committed to building the real thing.
Then comes the core question they asked out loud:
Getting from a prototype to a full browser that can hold up in production takes a lot of work and iteration. We won't deny it: using AI to speed that up was key. But how do you use AI on a project this complex without letting the quality of both the code and the result slip, and without slowing down?
The answer: give it as many tests as possible.
Kitesurf launch blog post
The tool was the WPT — it gave the AI agent a clear goal: a test either passes or it doesn't, no ambiguity. Humans do exactly two things: choose and prioritize which features to hand to the agent, and watch the architecture to make sure the agent's approach stays sound.
But WPT only measures spec conformance — it can't tell you whether a real website renders and behaves correctly. So they added another layer: integration tests plus visual regression tests, using Puppeteer to run multi-step operations on real sites while running Chromium and Kitesurf in parallel. They compare not just the assertion results, but the rendered output of every single step, flagging any unexpected differences.
You can lift this method out of the browser context entirely: to get an AI to do a job that's complex and easy to lose control of, first give it a target that scores itself. Then humans retreat to the two positions that matter: choosing the problems and watching the architecture. Wherever the test can't reach, add another layer that can compare automatically.
Four rules set before the first line of production code
Beyond testing, there were four rules locked in before any real code was written. Each one comes with its "and here's what that means."
Use Rust wherever possible, compiled straight to WebAssembly
No Emscripten-style emulation layer — compile directly with wasm-bindgen. What that means: the compiled binary stays lean and fast, running as close to the metal as possible.
Exception handling is a survival problem, not a hygiene problem
A browser has to render the entire unreliable, sometimes hostile web — and it must never lose track of the page it's on. Their iron rule: any failure degrades into a blank frame or a missing element. A session must never just die. Every boundary catches errors, defaults to a safe empty result, and logs enough to debug.
Treat every page load as untrusted input
When you open a browser on your laptop, you're visiting sites you trust, and sharing a few resources between pages is fine. An agent is different — it gets pointed anywhere the task demands, running arbitrary code from arbitrary sources. So every session starts from scratch, and every component can only touch the resources its job strictly requires.
Be stateless whenever possible
State is what makes failures expensive. With nothing to rebuild, recovering from a crash is just starting over and replaying the request. What that means: stateless components are disposable by nature, parallelizable, killable the moment they hang, runnable a thousand at once, and they scale on demand without needing to stay warm — which fits automation workloads perfectly, since they arrive in bursts.
What it's good for, and what it isn't
This section exists to help you decide: should my workload switch over?
These workloads can move today
- AI agents that need page rendering but can accept "not a full-featured, pixel-perfect Chromium"
- One-shot automation: extracting text content from a page
- One-shot automation: generating a PDF
- One-shot automation: taking a screenshot
Use Chromium for these four
- Playing videouse Chromium
- Rendering WebGLuse Chromium
- Bot-challenge handshakes at the TLS-fingerprint leveluse Chromium
- Ten-minute logged-in sessions that need persistent stateuse Chromium
Their positioning line is worth quoting: think of Kitesurf as a short-lived, fully isolated, stateless engine that exists only for the duration of a single task — built for AI loads that arrive in bursts.
On site compatibility, things that render correctly right now include: the various TodoMVC versions (vanilla, React, Vue, Angular, Preact), Wikipedia, Hacker News, the Cloudflare blog, and most of the Cloudflare dashboard. The fastest way to check a specific site: type the URL into the public playground and see for yourself.
How to try it, and the open source plan
Free public beta: it's available for free testing inside Cloudflare's Browser Run product, with per-account rate limits. To use it, add one parameter to your API call:
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"
browser=kitesurf. Same deal for the CDP endpoint — add that one flag and you're switched over.Online Playground: they've published kitesurf.cloudflare.app — enter any URL and watch Kitesurf render it live, with full interactivity.
There's something in there you won't see elsewhere: they injected Chrome DevTools into the UI, and specifically implemented the CDP commands the Memory panel needs — so you can see the WebAssembly footprint of each isolated environment, including individual frames.
They list four things in active development: broader CDP coverage; rendering fidelity for screenshots and PDFs (their reasoning: AI often does better looking at pictures than text); more WPT coverage; and efficiency — CPU, memory, and wall-time benchmarks are continuously running.
Open source plan: they say they intend to open source Kitesurf, "ready when we're ready, hopefully soon." The goal: let customers deploy their own instance inside their own account.
Cloudflare built a browser just for AI agents — by cutting everything humans wanted out of it
Cloudflare spent 12 weeks writing Kitesurf from scratch: a browser made for agents to open pages, extract content, and take screenshots. One illustrated page on what got cut, and what was traded for it.
↓ Read in one page · One animated figure inside
Cloudflare is launching Kitesurf today in free public beta inside Browser Run. It's a browser written from zero, purpose-built for AI agents, running on its own cloud platform Workers. It speaks standard CDP (the protocol Chrome DevTools uses to drive a browser), so Puppeteer and Playwright code doesn't change — add one parameter to your API call and you're switched over.
Browsers were built for people: tabs, themes, extensions, 60fps smooth scrolling. Agents don't use any of that, yet you still had to give each agent a full instance at human-browser cost. Kitesurf trades away that half and keeps what agents care about: token count, context window, machine-readable content, and a security boundary against prompt injection.
The first version came from an AI agent porting the open source engine obscura. Early attempts failed; only after the team handed it a solid plan and a success criterion detailed enough to keep looping did a working prototype appear. So how do you let an AI write a project this complex without the quality spiraling? Give it a target that scores itself.
That target was the Web Platform Tests — a public suite that checks whether a browser implements web standards correctly. The AI edits code, runs the tests, gets scores, edits again. Humans only pick which features to hand over and watch the architecture and approach. But tests can't tell you whether real sites actually work, so they added a layer: run Chromium and Kitesurf on the same site side by side, comparing the rendered output frame by frame.
The numbers below are Cloudflare's own benchmarks: screenshots and content extraction, measured against a warm-pool Chromium. No third-party reproduction yet. On both tasks, Kitesurf's CPU and memory usage drop dramatically — but wall time goes up.
Kitesurf is positioned as a short-lived, fully isolated, stateless engine that exists only for the duration of one task — built for AI loads arriving in bursts, and giving you a cheaper tier next to Chromium.
✔ One-shot text extraction, PDF generation, screenshots
✘ Bot-challenge handshakes at the TLS-fingerprint level
✘ Ten-minute sessions that need persistent login state
Right now it renders Wikipedia, Hacker News, the Cloudflare blog and dashboard, and all the TodoMVC framework versions. The fastest way to check a specific site: type it into kitesurf.cloudflare.app. The beta is free with per-account rate limits, and open sourcing is on the roadmap — the goal is letting customers deploy their own instance in their own account.
- × Tabs
- × Theme skins
- × Browser extensions
- × 60fps smooth scrolling
- × Video playback
- × Persistent login
