Kitesurf now open source – Cloudflare's agentic browser on Dioxus Blitz Cloudflare has open-sourced Kitesurf, an experimental browser engine that runs on Cloudflare Workers and parses HTML, applies CSS, executes page JavaScript and renders screenshots without Chrome or a browser container. Kitesurf speaks the Chrome DevTools Protocol, so CDP clients such as Puppeteer can connect to it at ws://127.0.0.1:8787/devtools/browser, but running it on Cloudflare requires Dynamic Workers, which are part of the Workers Paid plan. The repository builds with Bazel and requires Node.js 22 or newer and pnpm 9.15.4, with local development started via pnpm run dev on port 8787. Kitesurf is an experimental browser engine that runs on Cloudflare Workers. It parses HTML, applies CSS, runs page JavaScript, and renders screenshots without Chrome or a browser container. Kitesurf speaks the Chrome DevTools Protocol CDP https://chromedevtools.github.io/devtools-protocol/ , so you can use it with CDP clients such as Puppeteer. Important Kitesurf requires Cloudflare Dynamic Workers to create isolated workers for pages. Dynamic Workers are part of the Workers Paid plan https://developers.cloudflare.com/dynamic-workers/pricing/ . Local development uses wrangler dev . A Cloudflare Workers Paid plan is required to run Kitesurf on Cloudflare. - Bazelisk https://github.com/bazelbuild/bazelisk , installed as bazel . Bazel builds everything. It downloads the pinned Bazel, Rust toolchains, wasm-bindgen, and binaryen itself. - Node.js 22 or newer - pnpm 9.15.4, which the repository pins in package.json - On macOS, GNU tar brew install gnu-tar - Rust through rustup https://rustup.rs/ , only for editing the vendored crate patches. rust-toolchain.toml pins the same nightly that Bazel uses. Install pnpm separately if it is not already available: npm install --global pnpm@9.15.4 Clone the repository and install its dependencies: git clone https://github.com/cloudflare/kitesurf.git cd kitesurf pnpm install --frozen-lockfile Build and start the local engine: pnpm run dev The engine listens on http://127.0.0.1:8787 . Visit http://127.0.0.1:8787/health to confirm that it is running. The root URL shows the landing page. It has a form to open a URL in Chrome DevTools, example pages, and the CDP endpoints for agents and other clients. See Use Chrome DevTools use-chrome-devtools . pnpm run dev builds the WebAssembly modules and the page and renderer bundles with Bazel, then starts wrangler dev . The first build compiles the Rust core and its vendored crates, which takes a while; later builds reuse Bazel's cache. Set KITESURF PORT when port 8787 is already in use: KITESURF PORT=8799 pnpm run dev Install puppeteer-core in the project that will control Kitesurf. Then connect to the browser WebSocket endpoint: python import puppeteer from "puppeteer-core"; const browser = await puppeteer.connect { browserWSEndpoint: "ws://127.0.0.1:8787/devtools/browser", } ; const page = await browser.newPage ; await page.goto "https://example.com/" ; await page.screenshot { path: "page.png" } ; await browser.disconnect ; Use the port from KITESURF PORT if you selected a different port. HTTP discovery is available at http://127.0.0.1:8787/json/version . With pnpm run dev , open http://127.0.0.1:8787/ in Chrome. Enter a URL to inspect, or select one of the example pages. DevTools opens in the tab on that page. To go to DevTools directly, open http://127.0.0.1:8787/?url=https://example.com , or http://127.0.0.1:8787/?inspect=1 for a blank page. If you built the bundled frontend, pnpm run dev serves it from the engine's own origin. See Use the bundled DevTools frontend use-the-bundled-devtools-frontend . Otherwise, the DevTools frontend comes from chrome-devtools-frontend.appspot.com , the build that Google hosts for Chrome. The hosted frontend has these limits: - The first time it connects, Chrome asks whether chrome-devtools-frontend.appspot.com can access apps on this device. Select Allow . - If you block this access, DevTools says that the WebSocket disconnected. To allow it again, click the site information icon to the left of the address. Then allow the access and reconnect DevTools. - The frontend can connect only to 127.0.0.1 . Thus it does not work with a deployed engine. You can also use chrome://inspect : 1. Open chrome://inspect/ devices in Chrome. Type or paste it into the address bar because web pages cannot link to it. 2. Select Discover network targets . 3. Select Configure... and add 127.0.0.1:8787 . 4. Under Remote Target , select inspect next to kitesurf . 5. Enter a page URL in the address bar above the screencast. Use the port from KITESURF PORT when you select a different local port. Chrome discovers targets with plain HTTP and WebSocket connections. The chrome://inspect workflow cannot reach an HTTPS engine. Use it with a local engine instead. Kitesurf provides a CDP endpoint, not a full Chrome implementation. Some Chrome DevTools features do not work yet. We are working to add more support over time. Puppeteer and other CDP clients can connect to ws://127.0.0.1:8787/devtools/browser . Kitesurf can serve the Chrome DevTools frontend from its own origin. Then DevTools works without the hosted frontend, its permission prompt and the 127.0.0.1 limit. A deployed engine always uses this copy. The frontend is the prebuilt build that Google publishes for Chromium. The default build does not include it. The --config=devtools Bazel option adds the frontend to the build. The first build with it downloads the frontend about 250 MB . Bazel keeps the download in its cache for later builds. To build the frontend once, run this command from the repository root: bazel run --config=devtools //packages/engine:dev build To include the frontend in every local build, add the option to .bazelrc.user . Git ignores this file. Then pnpm run build and pnpm run dev include the frontend. echo 'common --config=devtools' .bazelrc.user The build copies the frontend to packages/engine/public/inspector/ . Git ignores this directory. A build without the option removes it. To turn the frontend off, remove the line from .bazelrc.user . 1. Build the frontend as described above. 2. Start the engine with pnpm run dev . The engine serves the bundled frontend when the build includes it, and the hosted frontend when it does not. 3. Open http://127.0.0.1:8787/ in Chrome. Enter a URL to inspect, or select one of the example pages. DevTools opens in the tab on that page. To start on a page, open http://127.0.0.1:8787/?url=https://example.com . Use the smallest step that fixes the problem: - To copy the frontend files again, delete the copy and build again: rm -rf packages/engine/public/inspector bazel run --config=devtools //packages/engine:dev build - To extract the archive again, for example after you change bazel/devtools frontend.BUILD , fetch it again and then build: bazel fetch --force --repo=@devtools frontend --config=devtools bazel run --config=devtools //packages/engine:dev build Bazel extracts the archive from its cache. To download the archive again from Google, add --repository cache= to the bazel fetch command. Do not use bazel clean --expunge for this. It also removes the WebAssembly build and the rest of the Bazel cache. Two pins select the frontend version: - DEVTOOLS FRONTEND REV and the values after it in MODULE.bazel select the bundled frontend. The comment above them tells you how to select a new snapshot. - KITESURF INSPECTOR FALLBACK URL in the local environment of packages/engine/wrangler.jsonc selects the hosted frontend. Use the Chrome commit that https://chromiumdash.appspot.com/fetch version?version=