商业产业 Hacker News Agent 2026-08-06T13:09 正文 ok 3318 words

Kitesurf:运行在 Cloudflare Workers V8 isolates 上、面向 Agent 的浏览器

英文标题:🔶 Kitesurf: The agent-first browser that runs in V8 isolates on Cloudflare Workers

Cloudflare 发布了 Kitesurf,这是一款完全构建在 Workers 之上、专为 AI Agent 设计的浏览器,目前在 Browser Run Beta 期间免费提供。相较 Chromium,Kitesurf 在截图和 HTML 提取等常见 Agent 任务中显著降低了 CPU 与内存消耗,并通过 CDP 兼容 Puppeteer、Playwright 等现有工具。其架构由 Engine、PageScript 和 PageRenderer 组成,结合 Dynamic Workers、Wasm、Rust、Durable Objects 等能力,将页面会话、网络访问和渲染流程隔离开来。该项目反映出浏览器正从面向人类交互的软件,演变为面向大规模 Agent 自动化、成本控制与工具安全的新型基础设施。
打开原文相关 3 · 机会 1
media1.2 KB media3.0 KB media704 B media1.7 KB media946 B media2.2 KB media1.5 KB media4.4 KB media19.0 KB media19.0 KB media16.8 KB media40.0 KB media6.6 KB media14.0 KB media20.0 KB media45.0 KB media14.9 KB media33.4 KB media16.9 KB media40.0 KB

中文

我们是否应该自己造一款浏览器?多年来,这个问题每隔几个月就会在 Cloudflare 内部浮现一次。毫不意外,它总会引发长篇讨论:人们会提出许多理由,并给出极具说服力的论据,说明我们为什么应该这样做。浏览器显然是我们每天在电脑上使用的最重要软件;也可以说,它是互联网的操作系统。我们是一家致力于帮助构建更好的互联网的公司——谁会不想迎接打造一款新浏览器的挑战?

但我们始终未能在这项事业的技术难度与我们借此能够解决的独特问题之间找到平衡。因此,这个想法一次又一次被搁置。直到现在。

一件奇妙的事发生了:我们到了一个临界点。Developer Platform 上一系列强大的技术进步成为现实;与此同时,AI Agent 的兴起以及对于新型浏览器的需求,也在同一时刻变得至关重要。

在 Workers 中运行 WebAssembly (Wasm)如今已经非常成熟。dynamic workers、基于 SQLite 的 Durable Objects、Worker-to-worker RPC、service bindings、更高的 NodeJS 兼容性以及更高的资源限制,为构建此前根本无法实现、更具雄心且更复杂的应用打开了大门。

随着 AI 的兴起,我们的无头浏览器自动化 API 产品 Browser Run 实现了大幅增长。Agent 需要浏览器来完成许多任务,而且在不少情况下,没有浏览器便无法成功。

但这里有一个问题——Chromium 这样的浏览器引擎是为人类而非 Agent 构建的,因此附带了 AI 模型根本不需要的开销。它们消耗大量内存和算力,以至于为每个 Agent 单独提供一个实例的成本高得令人难以承受。这使得网络的大部分内容只对那些最复杂、成本最高、具有更高参数化知识的 AI 模型开放,同时将许多其他 Agent 应用排除在外。

我们应该为_所有_ Agent 提供浏览器:它应在 AI 模型真正重视的方面表现出色,即便这意味着减少那些只对人类有用的功能。例如:

  • AI 不关心标签页、主题、浏览器扩展,或跨设备同步。它关心的是 token 数量、上下文窗口、可扩展性、性能和成本。
  • 结构化、机器可读的内容很重要,但视觉上的完美、流畅的 60 fps 滚动并不重要。即使 CSS 解析稍有偏差,或渲染无法做到像素级精准,Agent 也完全可以正常工作。
  • 在 AI 使用浏览器的场景中,威胁模型不同。提示注入和工具安全等新问题成为最优先事项。

面对这些认识,12 周前我们再次提出了那个问题:我们是否应该自己造一款浏览器?这一次,答案一致是:应该!

今天,我们宣布推出 Kitesurf:一款完全运行在 Workers 之上、专为 Agent 构建的新浏览器。目前它已在 Browser Run 中以 Beta 形式免费提供。

对于截图和 HTML 提取等常见 Agent 任务,Kitesurf 的 CPU 和内存消耗显著低于 Chromium。接下来,我们将讲述它的构建过程。系好安全带,内容会变得很技术化——但我们保证会尽量保持有趣。

起点

Kitesurf 的起步方式,与许多其他诞生于 Cloudflare 的伟大创意一样。有人发现了一件有意思的东西,接下来你会发现,他们用一个看似不可能、却极具吸引力的想法对团队其他人实施了“nerd sniping”。

我们的最初灵感来自 obscura:这是一个为 AI 自动化而编写的 Rust 无头引擎,特点是“没有 Chrome、没有 Node.js、没有依赖”。

随后,在 AI Agent 的帮助下,我们尝试将它移植到 Workers。起初效果并不理想。但当我们为 AI 提供一份扎实的计划和清晰的成功定义——细致到足以让 Agent 持续循环并在需要时提出问题——它最终成功了。
这个勉强能够运行的概念验证令我们震撼,于是我们决定让团队放手去做。

设计决策

以下是我们在启动项目之前作出的一些设计决策。

测试、测试、还是测试

我们知道,要从原型发展为一款能够在生产环境中大规模执行实际任务的完整浏览器,需要大量工作和迭代。我们不讳言:使用 AI 加速这一过程至关重要。但在如此复杂的项目中,如何使用 AI,既控制代码和结果的质量,又不牺牲开发速度?答案是:提供尽可能多的测试。

Web Platform Tests(WPT)正是理想方案:这是一套广泛的成功标准,为 AI Agent 评估功能是否符合规范提供了清晰目标。我们精心筛选并安排了要交给 Agent 的功能顺序,让人类能够专注于架构工作,以及审查 Agent 的实现方式。

不过,WPT 测试的覆盖范围有限:它们衡量的是对 W3C 标准的符合程度,而不是浏览器渲染和交互真实世界网站的能力。为了弥合这一差距,我们实现了集成测试与视觉回归测试的结合——它会在真实网站上针对 Chromium 和 Kitesurf 运行多步骤 Puppeteer 测试;不仅比较测试断言,还会在每一步渲染输出,以突出显示任何不希望出现的差异。

尽可能使用 Rust

Cloudflare 长期以来一直在为 Workers 中的 WebAssembly (Wasm) 提供出色支持。这很重要,因为我们可以使用高性能的 C、C++ 和 Rust 包,并将其编译为 Wasm。如果使用 Emscripten(举例来说)及其众多模拟依赖层,编译后的二进制文件可能会变得臃肿且缓慢。

因此,我们尽可能选择原生 Rust,并借助 wasm-bindgen 直接编译为 WebAssembly,从而避免不必要的模拟层,并尽可能贴近底层、可靠地运行。

异常处理

浏览器必须渲染整个不可靠、有时甚至带有恶意的网络,同时绝不能丢失当前承载的页面。因此,异常处理不只是良好的工程习惯——它是应用在面对错误输入时避免直接崩溃的生存方式。

因此,我们从一开始就确立了一条规则:任何故障都应降级为一个空白帧或缺失元素,绝不能导致会话终止。在每一个边界捕获错误,默认回退到安全且为空的状态,并记录足够的信息以供诊断。

隔离

在你的笔记本电脑上运行浏览器时,你访问的是自己信任的网站,并且可以接受它们之间共享某些资源;但 Agent 会被指向任务所需的任何内容:来自任意来源的任意代码。

因此,我们构建这款浏览器时假定:每一次页面加载都是不可信输入,每个会话都从全新状态开始。每个组件都被隔离,并且只能访问其功能严格所需的资源。

这看起来非常适合 Cloudflare Workers:其安全模型从设计之初便围绕隔离构建。但平台提供的只是 isolates 之间的边界。我们仍必须在应用层落实相同原则,决定每个组件可以接触什么,并确保不会发生跨越不应跨越页面的数据泄漏。

尽可能无状态

状态会让故障变得昂贵——如果没有需要重建的内容,从崩溃中恢复就只是启动一个新实例并重放请求。无状态组件天生可被丢弃和并行化:一旦卡住便可立即终止,同时运行一千个实例,并根据需求调整规模,而不必持续维持预热状态。这完美契合自动化场景:负载会突发到来,而最经济的做法是启动只消耗其实际使用资源、完成后立即消失的工作。简而言之,只要一个组件可以无状态,它就应当无状态。

我们如何构建它

凭借完善的计划、大量测试和良好的工具环境,我们已经准备好在最初的概念验证之外正式推进。以下是 Kitesurf 至今仍然适用的、请求生命周期的高度概括:

接下来,让我们深入了解让 Kitesurf 运作起来的三个主要组件:Engine、PageScript 和 PageRenderer。

从源站获取资源

为了渲染一个不受信任的网页,浏览器必须从互联网获取任意资源——图片、字体、CSS、JavaScript 和 Wasm 文件。这是浏览器能够执行的最危险操作之一。

Kitesurf 通过唯一的一个组件 SandboxOutbound worker 来完成这件事;除此之外,没有任何组件能直接访问网络——这由 Dynamic Workers 强制执行。Engine 使用它来引导页面,获取主文档及其脚本;PageScript 则通过它获取其他所有内容:样式表、图片、字体,以及页面自身的 fetch() 调用。

我们使用 SandboxOutbound 来强制执行 CORS、注入符合浏览器特征的请求头、过滤响应,并将每个页面的 Cookie 保存在独立的 Cookie jar 中。任何不符合我们策略的请求都会收到 403——每个组件只能获得其所需的精确网络访问权限,绝无额外权限。

Engine

Engine 是 Kitesurf 唯一面向公众的组件。它处理 Chrome DevTools Protocol(CDP)WebSocket 和 HTTP REST API,提供一个可用于内部测试的落地页,并且最重要的是,它存储每个会话的状态。其他所有组件均为无状态。

使用 CDP 的优势是客户端兼容性:Puppeteer、Playwright、chrome-remote-interface,以及真正的 Chrome DevTools 前端。只要让它们指向 Kitesurf,它们都会直接正常运行。这也是 Browser Run 工作的方式(稍后会解释为什么这很重要)。

与其名称暗示的不同,Engine 实际上是 Kitesurf 各组件中最简单的一个。真正有趣的部分接下来才开始。

PageScript

PageScript 很好地展示了我们新 Workers 功能的能力:这里指的是 Dynamic Workers。没有它,Kitesurf 根本不可能实现。

下面是一张 PageScript 内部工作方式的简化示意图。

每个后续页面或进程外 iframe(OOPIF)都会利用 Dynamic Workers 启动一个长生命周期的 PageScript isolate,用于处理由全新的 globalThis 和 DOM document 对象组成的页面会话。

随后,DOM 对象会根据 HTML 文档解析结果以及所有 JavaScript 脚本的运行结果进行填充。对于 HTML 和 CSS 的解析,我们使用了 Blitz 的部分能力——它是一个模块化渲染引擎;以及 Firefox 的高性能 CSS 解析器 Stylo。两者都以 Rust 编写。

对于每一个发现的 <script> 标签或 .wasm 文件,我们都会在同一个 isolate 内运行其 JavaScript 和 WebAssembly 代码。

没错,但 eval 怎么办?

你可能会问,eval 怎么处理?eval 更难处理,因为出于安全原因,Workers 目前仍不原生支持 eval。我们也无法启动另一个 isolate 来处理它们,因为后者无法访问 globalThis。

我们的解决方案是使用以 Rust 编写的 ECMAScript 引擎 Boa JS,将其编译后运行在 Workers 中。我们本质上是在一个运行时之上执行另一个运行时,这看上去并不理想,事实也确实如此;但它已经足以处理我们在代码中偶尔遇到的 eval。未来,当 Workers 支持原生 eval 时,我们将从 Boa 迁移出去。

PageRenderer

该组件本质上负责根据计算后的页面对象生成实际像素。其工作方式如下:

PageRenderer 与 Engine Worker 之间以循环方式协作。每当 Engine 需要一帧画面时,PageRenderer 就会从 PageScript 获取页面对象(也称为场景),从 Static Assets 获取内部字体和图片,将所有内容光栅化为图像缓冲区,然后以 JPEG/PNG 或 PDF 等客户端可显示的格式,把缓冲区返回给 Engine。

这里很大一部分魔法由另一个 Blitz 模块 blitz-paint 处理;该模块进一步使用 Parley 将字符塑形为字形、选择字体,并将文本拆分为

English / 原文

Should we build our own browser? This is one of those questions that has come up every few months internally at Cloudflare for years. Unsurprisingly, it’s the kind that triggers long threads with multiple reasons and persuasive arguments on why we should do it. The browser is obviously the most important software we use every day on our computers; it’s arguably the operating system of the Internet. We’re a company on a mission to help build a better Internet — who wouldn’t want to take on the challenge of building a new browser?

But we never quite found the balance between the technical difficulty of such an endeavour and the unique problems we’d be solving by doing it. And so, the idea was shelved, over and over again. Until now.

Something magical happened: we reached a tipping point where a series of powerful technical advancements in our Developer Platform became a reality, while the advent of AI agents and the demand for a new kind of browser became critical at the same time.

Running WebAssembly (Wasm) in Workers is now very mature. Primitives like dynamic workers, SQLite-based Durable Objects, Worker-to-worker RPC, service bindings, higher NodeJS compatibility and higher limits open doors to much more ambitious and complex applications that were simply not possible before.

Browser Run, our headless browser automation API product, has seen tremendous growth with the rise of AI. Agents need browsers in order to perform many tasks, and in many cases cannot succeed without them.

But there's a problem — browser engines like Chromium were built for humans, not agents, and they come with overhead that AI models simply do not need. They consume so much memory and compute that providing every agent with its own instance is prohibitively expensive, restricting large parts of the Web to only the most sophisticated and costly AI models with higher parametric knowledge, while locking out many other agentic applications.Â

We should be giving all agents a browser that excels at what’s important for an AI model, even if that means being light on what’s only useful for humans. For example:

  • AI doesn’t care about tabs, themes, browser extensions, or synchronization across devices. It cares about token count, context windows, scalability, performance, and costs.
  • Structured, machine-readable content is important, but visual perfection, smooth 60-fps scrolling is not. Agents will be just fine if the CSS parsing is slightly off or the rendering isn’t pixel perfect.
  • The threat model in the context of AI using a browser is different. New problems like prompt injection and tool safety are top priorities.

Faced with these realizations, 12 weeks ago we asked the question again: Should we build our own browser? This time the answer was unanimous: Yes!

Today we are announcing Kitesurf , a new browser that runs entirely on top of Workers that we built specifically for agents, 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. What follows is the story of how we built it. Buckle up, it’s going to get technical — but we promise to keep it interesting.

How it started

Kitesurf started as many other great ideas have started at Cloudflare. Someone found something interesting, and the next thing you know they end up “nerd sniping” the rest of the team with a seemingly impossible but very attractive idea.

We got the initial inspiration from obscura, a headless engine written in Rust for AI automation that has “no Chrome, no Node.js, no dependencies.”

Then, with the help of an AI agent, we tried to port it to Workers. It didn't work very well at first. 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 did work.
Blown away by this (barely) working proof of concept, we decided to let the team cook.

Design decisions

Here are some of the design decisions we made before we started.

Tests, tests, tests

We knew that moving from a prototype to a full-blown browser that could actually be useful for tasks at scale in production would take a lot of work and iteration. We won’t hide that using AI to accelerate the process was key. But how do you use AI in such a complex project, keeping the quality of both code and results under control without losing velocity? The answer is to provide as many tests as you can.

Enter the Web Platform Tests (WPT), the ideal setup: an extensive suite of success criteria that gave the AI agents clear goalposts for assessing feature conformance. We curated the selection and order of features to assign to the agents, allowing humans to focus on architectural work and reviewing the agents' approaches.

However, WPT tests only go so far: they measure conformance to W3C standards, not a browser's ability to render and interact with real-world websites. To bridge this gap, we implemented a __ combination of integration testing and visual regression testing — it runs multistep Puppeteer tests on real websites against both Chromium and Kitesurf not only by comparing the assertions that it makes, but also rendering outputs at every step to highlight any unwanted differences.

Use Rust when possible

Cloudflare has been working on providing great support for WebAssembly (Wasm) in Workers for quite some time. This is great because we can use high-performance C, C++, and Rust packages and compile them to Wasm. If we use Emscripten (for example) and its many layers of mocked dependencies, the compiled binary can get bulky and slow.

Instead, we opted for native Rust whenever possible and to compile directly to WebAssembly using wasm-bindgen, thus avoiding unnecessary emulation layers and running as close to the metal as possible, reliably.

Exception handling

A browser must render the whole unreliable and sometimes hostile web without ever dropping the page it's holding, so exception handling is more than just hygiene — it's how the application survives bad input without just crashing outright.

So we committed to one rule up front: any failure degrades to a blank frame or a missing element, never a dead session. Catch faults at every boundary, default to something safe and empty, and log enough to diagnose.

Isolation

Contrary to running a browser on your laptop (where you're visiting sites you trust, and it's acceptable to share some resources between them), an agent is pointed at whatever a task demands: arbitrary code from arbitrary origins.

So we built this browser on the assumption that every page load is untrusted input and every session starts fresh. Each component is isolated and has access only to the resources strictly necessary for its function.

This seems like a perfect fit for Cloudflare Workers, whose security model is built around isolation by design. But the platform only gets us the boundary between isolates. We still have to enforce the same principle at the application level, deciding what each component is allowed to touch and making sure nothing leaks across a page it shouldn't.

Stateless whenever possible

State is what makes failure expensive — if there's nothing to reconstruct, recovering from a crash is just starting a new one and replaying the request. A stateless component is disposable and parallel by nature: kill it the moment it stalls, run a thousand at once, and size them to demand instead of keeping things warm. That fits automation perfectly, where load arrives in bursts and the cheapest thing you can do is spin up work that costs only what it used and vanishes when it's done. In short, wherever a component can be stateless, it should be.

How we built it

Armed with a good plan, extensive tests, and a good tooling environment, we were ready to get started beyond the initial proof of concept. This is Kitesurf’s very high level life of a request that still holds today:

Let’s dive into the three main components that make Kitesurf work: the Engine, PageScript, and PageRenderer.

Fetching from origins

In order to render an untrusted web page, a browser has to fetch arbitrary assets — images, fonts, CSS, JavaScript, and Wasm files — off the Internet. This is one of the most dangerous operations a browser can do.

Kitesurf does it through one single component, the SandboxOutbound worker, and nothing else can touch the network directly — enforced by Dynamic Workers. The Engine uses it to bootstrap the page, fetching the main document and its scripts, and PageScript fetches everything else: stylesheets, images, fonts, and the page's own fetch() calls.

We use SandboxOutbound to enforce CORS, inject browser-shaped headers, filter responses, and keep each page's cookies in their own jar. Anything that fails our policy gets a 403 — each component gets precisely the network it needs and nothing more.

The Engine

The Engine is the only public-facing component of Kitesurf. It handles the Chrome DevTools Protocol (CDP) WebSocket and HTTP REST APIs, serves a landing page that is useful for internal testing purposes and, most importantly, stores each session state. All other components are stateless.

The advantage of using CDP is client compatibility: Puppeteer, Playwright, chrome-remote-interface, and the actual Chrome DevTools frontend. Point them at Kitesurf and they will all just work. This is also how Browser Run works (more on why this is important later).

Contrary to what the name suggests, the Engine is actually the simplest of the Kitesurf components. The fun parts come next.

PageScript

PageScript offers a good example of the power of our new Workers features: in this case, Dynamic Workers. Kitesurf simply wouldn’t have been possible before this.

Here’s a simplified diagram of how PageScript works internally.

Every next page or out-of-process iframe (OOPIF) uses Dynamic Workers to spin up a long-lived PageScript isolate that handles the page session, consisting of a clean globalThis and the DOM document object.Â

The DOM object is then populated with the results of parsing the HTML document and running all the JavaScript scripts. For parsing the HTML and the CSS we use parts of Blitz, a modular rendering engine, and Stylo, Firefox’s high-performance CSS parser, both written in Rust.Â

For each found tag or .wasm file we run the JavaScript and WebAssembly code inside the same isolate.

Yes, but evals

What about evals, you ask? Evals are trickier to handle because for security reasons we still don’t support eval natively in Workers. We can’t spin another isolate to handle them either, because it wouldn’t have access to globalThis.

Our solution is to use Boa JS, an ECMAScript engine written in Rust, to compile and run on Workers. We are basically executing a runtime on top of a runtime, which doesn’t seem optimal, and it isn’t, but it works well enough to handle the occasional evals we find in the code. In the future, when native eval support lands in Workers, we will migrate away from Boa.

PageRenderer

This component is essentially responsible for generating the actual pixels from the computed page objects. Here’s how it works:

PageRenderer works in a loop with the Engine Worker. Every time the engine needs a frame, PageRenderer gets the page object from PageScript (also known as the scene), fetches the internal fonts and images from Static Assets, rasterizes everything into an image buffer, and then returns the buffer to the engine in a format that the client can display like a JPEG/PNG or PDF.

A big part of the magic here is handled by another Blitz module, blitz-paint, which in turn uses Parley for shaping the characters into glyphs, choosing fonts, and breaking text into lines.

Workers’ built-in RPC system: same application, multiple isolatesÂ

Cloudflare Workers have a built-in remote procedure call (RPC) system that allows you to call methods on other Workers, pass objects between them, and call methods on those objects. You don’t have to worry about API schemas, types, or authentication, you just call remoteFunction(...params) and it works. You benefit from the isolation and the resources of the remote Worker without losing the convenience of accessing all of their functions locally using JavaScript.

Kitesurf uses this RPC system: the Engine Worker calls renderFrame() from the PageRenderer Worker over RPC using one single call and gets a PNG as the result. Because the renderer holds no page state (only a disposable cache), the engine can safely kill and relaunch it on any failed or stuck RPC call — making each render request self-contained, retryable, and its isolate cheap and throwaway.

Kitesurf passes 215,000+ WPT tests and growing

Kitesurf works. It already passes around 215,000+ WPT tests, and we are adding hundreds of passing tests every week. Here you can see the evolution over time, up to the latest version since we started the project:

It’s worth noting that the parts of a browser that are important to agents (e.g., CSS, DOM, HTML, selection, SVG, and XHR) have good coverage already. Even things that might not be particularly important in the context of agents, like streams, are now decently supported.

Performance-wise, Kitesurf is doing pretty well. Below are the medians of five Browser Run quick-action runs across a 14-URL corpus comparing Chromium with Kitesurf.

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

Chromium wins the stopwatch because a JIT that has already seen this page always beats a cold software renderer — and today it does, by about 1.7x. Most of that gap comes from rasterization and JPEG/PNG encoding, which we will keep optimizing.

But Kitesurf wins on memory and CPU, the things that actually drive your bill, by 3-7x compared to what Chromium uses. Less memory means we can run more sessions, scale better, and fundamentally lower both our costs and yours.Â

The most important test of all: Kitesurf runs Doom

We highlighted the importance of testing in our design decisions, but we all know that no matter how many tests you have, a project isn't truly complete until Doom runs on it. Here’s Kitesurf running https://silentspacemarine.com/ from our little Doom experiment a few years ago.

Try it today in Browser Run

You can try Kitesurf with Browser Run today, available for free while in beta , behind per-account limits.

The Browser Run CDP endpoint now supports Kitesurf as an option, so your existing client Puppeteer, Playwright, chrome-remote-interface, or any AI Agent that speaks MCP and CDP, already works. All you need to do is add the browser=kitesurf parameter to our endpoints.

For example, to use Kitesurf with Opencode see Using with MCP clients (CDP) in our developer documentation and use this configuration:

{
  "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
    }
  }
}

Another way to use Kitesurf is with Browser Run’s Quick Actions. Again, just add browser=kitesurf to the quick action endpoint and it will work. For example, if you need a quick screenshot from Wikipedia, this will work just fine:

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"

Use the Kitesurf Playground with Chrome DevTools

Another option to start exploring Kitesurf is to use our public playground here. You can type in any URL to see how Kitesurf renders the page and interact with it.

One interesting feature of the playground is that we inject Chrome DevTools in the UI, so you can inspect expanded DOM elements, read console messages, and watch network activity while Kitesurf renders pages. More interestingly, we implemented the necessary CDP instructions for the Memory panel to report the WebAssembly footprint of each isolate, including frames, so you can gain a clear understanding of the resources each page is consuming.

Check our Developer Documentation for all the details on how to use Kitesurf with Browser Run.

When is Kitesurf better?

As of today, Kitesurf correctly renders pages like TodoMVC (vanilla, React, Vue, Angular, Preact), Wikipedia, Hacker News, the Cloudflare Blog, and much of the Cloudflare dashboard. We will keep improving Kitesurf and increasing the percentage of WPT tests that pass, to improve compatibility for more complex web pages.

Kitesurf is great for AI agents that need to render pages but can accept the trade-offs of not using a full-featured, pixel-perfect Chromium browser. It is also excellent for automations and applications that rely on one-shot Quick Actions, such as extracting content from a page or generating PDFs or screenshots, for compatible sites.

Think of Kitesurf as an ephemeral, fully-isolated, stateless engine designed to exist only for the duration of a task, that scales well for bursty, AI-driven workloads.

What Kitesurf is not yet able to do

If you need to play video, render WebGL, negotiate a bot-challenge handshake with real TLS fingerprints, or start a ten-minute authenticated session that requires persistent state — Kitesurf isn’t yet the right option. Just use Browser Run’s default, which is powered by Chromium.

The best way to know if a specific site is compatible with Kitesurf is to try it. You can do this by using the APIs or, more quickly, try it in our public playground.

Explore the DevTools panels and see what’s happening behind the scenes, with particular attention to the console and the memory metrics.

Where it goes

Kitesurf is twelve weeks old. The first commit was in May. Here are some of the things we're actively working on:

  • Better CDP coverage. Kitesurf implements a subset of the CDP protocol — enough to cover the requirements of most agents and automation tools, including robust DOM and network inspection — and we continue to expand its capabilities to be as complete as possible.
  • Rendering fidelity for screenshots and PDFs, because we know that LLMs can often work better from an image than from the underlying text.
  • WPT coverage. We are iterating rapidly to add more web APIs and pass more WPT tests on the road to making Kitesurf production-ready.
  • Efficiency. We keep CPU, memory, and wall time benchmarks running all the time and are working hand-in-hand with other Developer Platform teams to make Kitesurf as cost-effective and efficient as possible.

Final notes

Thank you for making it all the way here — we know this was a long and technical blog post, but hopefully an interesting one. We went into detail because we don't take lightly how important, but also how complex, it is to build a new browser, even a very specific one.

Kitesurf is in its early stages, but we wanted to open it up to you as soon as possible and learn from your feedback. The team will be actively improving it with frequent updates focused on performance, efficiency, and compatibility.Â

One last thing: we're going to open source Kitesurf once we're ready — hopefully soon. Our goal is to let any customer deploy their own version of Kitesurf on their own accounts, if they want to.

So give it a try in the playground, keep an eye on our changelog, and come chat with the team on Discord. Share your experience and send us feedback; we’ll be listening.