Cloudflare Kitesurf vs Chromium: What We Measured
We earn commissions when you shop through the links below, at no extra cost to you. We only link products we would use ourselves.
Cloudflare announced Kitesurf on 6 August 2026: a browser written for agents that runs in V8 isolates on Workers instead of shipping a whole Chromium process. You opt in by adding one query parameter to a Browser Run request. The pitch is 3 to 7 times less CPU and memory than Chromium for agentic work like screenshots and HTML extraction.
We render screenshots, PDFs, and OG images on Browser Run every day, so the question was not whether the architecture is clever. It is whether flipping browser=kitesurf in production would be free money or a quiet outage. We measured it on 24 August 2026 against our own Cloudflare account.
Short answer: Kitesurf is a real drop-in for text extraction on server-rendered pages, it is genuinely free while in beta, and it will break you in three specific places if you flip the flag without reading the rest of this page. In our sample it also billed more browser time than Chromium in most cases, which is the opposite of what the resource-efficiency headline suggests, and consistent with Cloudflare's own numbers once you read them closely.
Turning it on
One parameter, on any Quick Action or CDP endpoint:
curl -X POST 'https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-run/screenshot?browser=kitesurf' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{"url": "https://example.com"}' \
--output screenshot.png
For Puppeteer, Playwright, or an MCP client, the same parameter goes on the CDP WebSocket URL:
wss://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-run/devtools/browser?browser=kitesurf
Nothing else changes. Same auth, same request bodies, same response shapes. That part of the promise holds.
How we measured
Quick Actions against api.cloudflare.com, one account, one client location, sequential requests with 800 ms between them. Three trials per cell, each with a unique cache-busting query parameter on the target URL so nothing came back from a previous render. Wall time is client-observed round trip. Billed time is read from the X-Browser-Ms-Used response header, which Browser Run returns on every request and is the number your invoice is built from.
Three trials is directional, not benchmark-grade. Treat the ratios as real and the exact milliseconds as noisy.
Median wall time and median billed browser time
| Action and page | Chromium wall | Kitesurf wall | Chromium billed | Kitesurf billed |
|---|---|---|---|---|
| screenshot, example.com | 794 ms | 1,183 ms | 533 ms | 946 ms |
| screenshot, Wikipedia "Hypertext" | 1,694 ms | 4,570 ms | 1,399 ms | 3,943 ms |
| screenshot, news.ycombinator.com | 1,580 ms | 1,619 ms | 796 ms | 1,364 ms |
| markdown, example.com | 518 ms | 579 ms | 264 ms | 407 ms |
| markdown, Wikipedia "Hypertext" | 1,243 ms | 2,267 ms | 997 ms | 1,700 ms |
| markdown, news.ycombinator.com | 1,457 ms | 836 ms | 1,135 ms | 650 ms |
Kitesurf was slower on wall time in five of six cells and billed more browser time in five of six. The one clear win, markdown extraction on Hacker News, was a 43 percent cut in billed time.
This is not a contradiction of Cloudflare's claim, it is a different metric. The blog post's own table reports Kitesurf using 3.1 times less CPU on screenshots and 3.8 times less on HTML extraction, and in the same table reports wall time 1.8 times and 1.7 times slower than warm Chromium. Less CPU and memory per page is Cloudflare's cost structure improving. Browser Run bills you for browser time, so the number on your invoice is the one that moved the wrong way in our sample.
What that would cost after the beta
Kitesurf is free while in beta, so today the honest cost comparison is zero against $0.09 per browser hour. The interesting version is what these same medians would cost if beta pricing ended and Kitesurf billed like everything else, per 10,000 renders:
| Action and page | Chromium | Kitesurf |
|---|---|---|
| screenshot, example.com | $0.13 | $0.24 |
| screenshot, Wikipedia | $0.35 | $0.99 |
| screenshot, Hacker News | $0.20 | $0.34 |
| markdown, example.com | $0.07 | $0.10 |
| markdown, Wikipedia | $0.25 | $0.43 |
| markdown, Hacker News | $0.28 | $0.16 |
These are cents either way, which is the actual point: at Browser Run prices the engine choice is not where your money goes. Concurrency and plan floors are. The Paid plan includes 10 browser hours a month and 10 concurrent browsers, then $0.09 per extra hour and $2.00 per extra averaged concurrent browser. We worked that math out against renting a box in screenshot API or self-hosted droplet.
Three things that change when you flip the flag
1. The response meta object shrinks
This is the one that will break code silently. On the default Chromium path, /markdown returns:
{"success":true,"result":"---\ntitle: \"Example Domain\"\n---\n\n# Example Domain\n...",
"meta":{"status":200,"title":"Example Domain",
"headers":{"cf-ray":"a302b555aff9df44-MIA","content-type":"text/html",
"date":"Mon, 24 Aug 2026 13:29:52 GMT","server":"cloudflare",
"allow":"GET, HEAD","cf-cache-status":"MISS",
"last-modified":"Tue, 18 Aug 2026 20:06:42 GMT"},
"finalUrl":"https://example.com/?d=1"}}
The same request with browser=kitesurf returns the identical result string and this meta:
"meta":{"status":200,"title":"Example Domain"}
No headers. No finalUrl. If you use meta.finalUrl to follow redirects, or read last-modified or cf-cache-status to decide whether to re-render, that logic goes quiet rather than failing. We saw the same reduction on /markdown, /accessibilityTree, and /json. Check your parsers before switching.
Small consolation in the other direction: Kitesurf's /accessibilityTree included a value field carrying the page URL on the RootWebArea node, which the Chromium path did not.
2. The default wait returns the page before your SPA renders
We asked /content for the React build of TodoMVC, a client-rendered app where the interesting DOM only exists after the bundle runs.
Chromium, default options: 1,591 characters, including todo-list and the "What needs to be done" input.
Kitesurf, default options: 695 characters, ending in <section class="todoapp" id="root"></section>. An empty mount point.
That looks like "Kitesurf does not run JavaScript", and it is not. Retested with an explicit wait, Kitesurf hydrated correctly every time:
| Request | Hydrated | Billed |
|---|---|---|
Kitesurf, gotoOptions.waitUntil: networkidle0 | yes | 1,992 ms |
Kitesurf, waitForSelector: .todo-list | yes | 1,375 ms |
Kitesurf, waitForTimeout: 5000 | yes | 5,390 ms |
Chromium, gotoOptions.waitUntil: networkidle0 | yes | 4,547 ms |
So Kitesurf executes the bundle, it just returns earlier than Chromium does on default settings. With the same explicit wait, it was the cheaper of the two on this page by a wide margin: 1,375 ms of billed time against 4,547 ms. The rule is simple. If you switch engines, set your waits explicitly, and prefer waitForSelector over a fixed timeout.
3. Pixels differ, and WebGL is not quietly filled in
Same URL, same day, screenshot bytes: 22,268 for Chromium and 25,555 for Kitesurf on example.com, 45,691 and 47,923 on get.webgl.org. Kitesurf shapes text with Parley rather than Chromium's stack, so glyph rasterization is not identical. You cannot mix engines inside one visual-regression baseline set.
The clearer demonstration is get.webgl.org, a page that branches on WebGL support. Chromium rendered "Your browser supports WebGL" and the wireframe cube. Kitesurf rendered the failure branch: "While your browser seems to support WebGL, it is disabled or unavailable", no cube.
That is exactly what Cloudflare's docs say to expect ("cannot play video or render WebGL"), and it is worth stating plainly because some of the launch coverage described unsupported features as falling back to Chromium. In our test nothing fell back. The request succeeded with 200 and gave us the degraded page. A silent 200 is worse than an error if you are screenshotting canvas-heavy pages, so check your corpus before switching.
Which Quick Actions Kitesurf accepts
Not all of them, and the unsupported ones fail loudly, which is good design. Tested on 24 August 2026:
| Quick Action | browser=kitesurf |
|---|---|
/content | works |
/screenshot | works |
/pdf | works |
/markdown | works |
/accessibilityTree | works |
/json | works, same extraction as Chromium in our test |
/links | HTTP 400 |
/scrape | HTTP 400 |
/snapshot | HTTP 400 |
The rejection is explicit and costs nothing (X-Browser-Ms-Used: 0):
{"success":false,"errors":[{"message":"Action \"links\" is not supported by the kitesurf browser","code":2000}]}
We did not test /crawl. If your pipeline leans on /scrape selectors or /snapshot multi-format output, Kitesurf is not a drop-in today, and you get a 400 rather than a surprise.
One more difference worth knowing if you generate documents: /pdf works on both engines but produces a different file. Chromium emitted a 16,619 byte %PDF-1.4 for example.com, Kitesurf a 9,332 byte %PDF-1.7. Different producer, different output. If you care about print CSS fidelity, retest your templates rather than assuming, the same way we had to when we compared HTML to PDF APIs.
When we would switch, and when we would not
Switch for bulk text work on server-rendered pages: markdown extraction, /content, accessibility trees, the read loop of an agent that wants the DOM rather than a picture. It is free during the beta, the response shape matches, and on the pages where it wins it wins meaningfully.
Stay on Chromium for anything visual you will diff or ship to a customer, for WebGL, video, and canvas, for bot-challenged sites where TLS fingerprints matter, for authenticated sessions that need to persist, and for any code path reading meta.headers or meta.finalUrl.
If you are not on Workers at all, the calculus is different and the engine is the least of it. A DigitalOcean droplet from $4 a month running your own headless browser is still the cheapest way to do high steady volume, and you take on Chromium patching, memory watching, and URL filtering in exchange. We wrote that comparison up in screenshot APIs without a subscription.
One number in the coverage does not agree with itself
Cloudflare's blog post says Kitesurf passes "around 215,000+ WPT tests". The Kitesurf docs page says "over 235,000 subtests", with per-area figures (DOM 97 percent, HTML 96 percent, Selection 99 percent). Those are probably tests versus subtests rather than a contradiction, but syndicated coverage has been quoting 235,000 as a test count and attributing it to the blog post, which is not what the blog post says. If the number matters for a decision you are making, use the docs page figure and call it subtests.
FAQ
Is Kitesurf free? It is free while in beta, behind per-account limits, per Cloudflare's docs. The docs do not state post-beta pricing. Everything else on Browser Run bills at $0.09 per browser hour with 10 hours a month included on the Paid plan.
Does it work with Playwright and Puppeteer? Yes. It speaks the Chrome DevTools Protocol, so existing clients drive it unchanged once you add browser=kitesurf to the CDP endpoint. That includes MCP clients that connect over CDP.
Does it run JavaScript? Yes. It parses HTML with Blitz, CSS with Stylo from Firefox, and runs page scripts in a Dynamic Workers isolate. Our TodoMVC test above shows a React app hydrating under Kitesurf once an explicit wait is set.
Is it a Chromium fork? No. It is built on Blitz, a modular open-source browser engine, compiled to WebAssembly and Rust, with Cloudflare saying they intend to open source their work. Chromium remains the default engine on Browser Run.
Will unsupported features fall back to Chromium automatically? Not in our testing. Unsupported actions return HTTP 400. Unsupported page features like WebGL render the page's own no-support branch and return 200.
What does it change for bot detection? Cloudflare's docs say Kitesurf cannot negotiate a bot-challenge handshake that requires real TLS fingerprints. We did not test this, because testing it means firing challenges at sites that did not ask for our traffic.
Everything above was measured against the live Browser Run API on 24 August 2026, three trials per cell unless stated. Kitesurf is in beta and moving weekly, so if you are reading this much later, rerun the two tests that matter for you: the meta shape and your own worst page.