Introductie van Kitesurf: De 'agent-first' browser die draait in V8-isolaten op Cloudflare Workers
Moeten we onze eigen browser bouwen?
Dit is een vraag die intern bij Cloudflare al jaren elke paar maanden naar voren komt. Het is het soort vraag dat leidt tot lange discussies met talloze argumenten waarom we dit zouden moeten doen. De browser is overduidelijk de belangrijkste software die we dagelijks op onze computers gebruiken; het is in feite het besturingssysteem van het internet. Als bedrijf met de missie om te helpen een beter internet te bouwen, wie zou dan niet de uitdaging willen aangaan om een nieuwe browser te maken?
We vonden echter nooit de juiste balans tussen de technische moeilijkheidsgraad van zo'n onderneming en de unieke problemen die we ermee zouden oplossen. Daarom werd het idee herhaaldelijk geparkeerd. Tot nu.
Er is een omslagpunt bereikt waarbij een reeks krachtige technische vooruitschriften in ons Developer Platform werkelijkheid zijn geworden, terwijl tegelijkertijd de komst van AI-agents en de vraag naar een nieuw soort browser cruciaal werden.
Het draaien van WebAssembly (Wasm) in Workers is nu zeer volwassen. Primitieven zoals dynamische workers, SQLite-gebaseerde Durable Objects, Worker-to-worker RPC, service bindings, hogere NodeJS-compatibiliteit en hogere limieten openen de deur naar veel ambitieuzere en complexere applicaties die voorheen simpelweg onmogelijk waren.
Browser Run, ons headless browser automation API-product, heeft een enorme groei doorgemaakt door de opkomst van AI. Agents hebben browsers nodig om veel taken uit te voeren, en in veel gevallen kunnen ze zonder deze browsers niet slagen.
Er is echter een probleem: browserengines zoals Chromium zijn gebouwd voor mensen, niet voor agents, en ze brengen overhead met zich mee die AI-modellen simpelweg niet nodig hebben. Ze verbruiken zoveel geheugen en rekenkracht dat het prohibitief duur is om elke agent van een eigen instantie te voorzien. Dit beperkt grote delen van het web tot alleen de meest geavanceerde en kostbare AI-modellen met hogere parametrische kennis, terwijl veel andere agentische applicaties worden buitengesloten.
We zouden alle agents een browser moeten geven die uitblinkt in wat belangrijk is voor een AI-model, zelfs als dat betekent dat zaken die alleen nuttig zijn voor mensen, worden weggelaten. Bijvoorbeeld:
- AI geeft niet om tabbladen, thema's, browserextensies of synchronisatie tussen apparaten. Het geeft om token-aantal, contextvensters, schaalbaarheid, prestaties en kosten.
- Gestructureerde, machineleesbare inhoud is belangrijk, maar visuele perfectie en vloeiend 60-fps scrollen niet. Agents redden zich prima als de CSS-parsing enigszins afwijkt of de rendering niet pixel-perfect is.
- Het dreigingsmodel in de context van AI die een browser gebruikt, is anders. Nieuwe problemen zoals prompt-injectie en tool-veiligheid hebben topprioriteit.
Voor deze realisaties inziend, stelden we twaalf weken geleden de vraag opnieuw: moeten we onze eigen browser bouwen? Deze keer was het antwoord unaniem: Ja!
Vandaag kondigen we Kitesurf aan, een nieuwe browser die volledig bovenop Workers draait en specifiek is gebouwd voor agents. Tijdens de bètafase is deze gratis beschikbaar in Browser Run.
Kitesurf is aanzienlijk efficiënter in CPU- en geheugengebruik dan Chromium voor veelvoorkomende agentische taken zoals screenshots en HTML-extractie. Hieronder volgt het verhaal van hoe we het hebben gebouwd.
Hoe het begon
Kitesurf begon zoals veel andere goede ideeën bij Cloudflare: iemand vond iets interessants en voordat men het wist, was het hele team "nerd-sniped" door een schijnbaar onmogelijk maar zeer aantrekkelijk idee.
De initiële inspiratie kwam van obscura, een headless engine geschreven in Rust voor AI-automatisering die "geen Chrome, geen Node.js en geen afhankelijkheden" heeft. Met behulp van een AI-agent probeerden we dit te porteren naar Workers. In het begin werkte dat niet erg goed, maar zodra we de AI een solide plan gaven en een duidelijke definitie van succes — gedetailleerd genoeg zodat de agent oneindig kon loopen en vragen kon stellen wanneer nodig — werkte het wel.
Verbluffd door dit (nauwelijks) werkende bewijs van concept, besloten we het team hun gang te laten gaan.
Ontwerpbeslissingen
Hier zijn enkele van de ontwerpbeslissingen die we maakten voordat we begonnen.
Tests, tests, tests
We wisten dat de overgang van een prototype naar een volledige browser die op productieschaal nuttig zou zijn, veel werk en iteratie zou kosten. Het gebruik van AI om dit proces te versnellen was essentieel. Om de kwaliteit van zowel de code als de resultaten onder controle te houden zonder snelheid te verliezen, boden we zoveel mogelijk tests aan.
We maakten gebruik van de Web Platform Tests (WPT), een uitgebreide suite van succescriteria die de AI-agents duidelijke doelpalen gaven voor het beoordelen van feature-conformiteit. Mensen konden zich hierdoor concentreren op architecturaal werk en het beoordelen van de benaderingen van de agents.
Omdat WPT-tests alleen conformiteit aan W3C-standaarden meten en niet het vermogen om echte websites te renderen, implementeerden we een combinatie van integratietesten en visuele regressietesten. Dit draait meerstaps Puppeteer-tests op echte websites tegen zowel Chromium als Kitesurf, waarbij niet alleen beweringen worden vergeleken, maar ook de rendering-outputs per stap worden geanalyseerd om ongewenste verschillen te highlighten.
Rust gebruiken waar mogelijk
Cloudflare biedt al geruime tijd uitstekende ondersteuning voor WebAssembly (Wasm) in Workers. Hierdoor kunnen we high-performance C, C++ en Rust packages gebruiken en deze compileren naar Wasm. Om onnodige emulatielagen te vermijden en zo betrouwbaar mogelijk dicht bij de hardware ("close to the metal") te draaien, kozen we waar mogelijk voor native Rust en compileerden we direct naar WebAssembly met wasm-bindgen.
Exception handling
Een browser moet het onbetrouwbare en soms vijandige web kunnen renderen zonder ooit de pagina te verliezen. Daarom hanteerden we één strikte regel: elke fout leidt tot een leeg frame of een ontbrekend element, maar nooit tot een dode sessie. We vangen fouten op bij elke grens, vallen terug op iets veiligs en leegs, en loggen voldoende om de diagnose te kunnen stellen.
Isolatie
In tegenstelling tot het draaien van een browser op een laptop (waar je sites bezoekt die je vertrouwt), wordt een agent gestuurd naar willekeurige code van willekeurige oorsprongen. We hebben deze browser gebouwd vanuit de aanname dat elke paginalading onvertrouwde input is en elke sessie opnieuw begint. Elk component is geïsoleerd en heeft alleen toegang tot de resources die strikt noodzakelijk zijn voor zijn functie.
Dit past perfect bij het beveiligingsmodel van Cloudflare Workers, dat is gebouwd rond isolatie-by-design. We hebben dit principe ook op applicatieniveau afgedwongen om te zorgen dat er niets lekt tussen pagina's.
Stateless waar mogelijk
State (toestand) maakt falen duur — als er niets gereconstrueerd hoeft te worden, is herstel na een crash simpelweg het starten van een nieuwe sessie en het opnieuw afspelen van het verzoek. Een stateless component is vervangbaar en parallel van aard. Dit past perfect bij automatisering, waarbij belasting in bursts arriveert en de goedkoopste optie is om werk op te spinnen dat alleen kost wat het verbruikt en verdwijnt als het klaar is.
Hoe we het hebben gebouwd
Met een goed plan, uitgebreide tests en een goede tooling-omgeving konden we verder gaan dan het initiële bewijs van concept. De levenscyclus van een verzoek in Kitesurf ziet er als volgt uit:
- Fetching: Assets (afbeeldingen, fonts, CSS, JS) worden opgehaald via de
SandboxOutboundworker. - Engine: Verwerkt het Chrome DevTools Protocol (CDP) en beheert de sessiestatus.
- PageScript: Parseert HTML/CSS en voert JavaScript uit in een geïsoleerde omgeving.
- PageRenderer: Genereert pixels op basis van de berekende paginagegevens.
Fetching from origins
Om een onvertrouwde webpagina te renderen, moet een browser willekeurige assets ophalen van het internet. Kitesurf doet dit via één enkel component: de SandboxOutbound worker. Niets anders kan direct contact hebben met het netwerk; dit wordt afgedwongen door Dynamic Workers.
We gebruiken SandboxOutbound om CORS af te dwingen, browser-specifieke headers te injecteren, responses te filteren en cookies per pagina gescheiden te houden. Alles wat niet aan ons beleid voldoet, krijgt een 403-foutmelding.
The Engine
De Engine is het enige publiek toegankelijke component van Kitesurf. Het handelt de Chrome DevTools Protocol (CDP) WebSocket en HTTP REST API's af en slaat de status van elke sessie op. Alle andere componenten zijn stateless.
Het voordeel van CDP is client-compatibiliteit: Puppeteer, Playwright, chrome-remote-interface en de eigenlijke Chrome DevTools frontend werken direct met Kitesurf. Dit is ook hoe Browser Run functioneert.
PageScript
PageScript maakt gebruik van Dynamic Workers om voor elke nieuwe pagina of out-of-process iframe (OOPIF) een langdurig PageScript-isolaat op te spinnen. Dit isolaat bevat een schone globalThis en het DOM-document object.
Voor het parsen van HTML en CSS gebruiken we onderdelen van Blitz (een modulaire rendering engine) en Stylo (de high-performance CSS-parser van Firefox), beide geschreven in Rust. Voor elke gevonden <script> tag of .wasm bestand voeren we de code uit binnen hetzelfde isolaat.
Hoe zit het met evals?
Omdat we om veiligheidsredenen geen native eval ondersteunen in Workers, gebruiken we Boa JS (een ECMAScript-engine geschreven in Rust) om deze te compileren en uit te voeren. We draaien in feite een runtime bovenop een runtime. Zodra native eval-ondersteuning beschikbaar komt in Workers, zullen we overstappen.
PageRenderer
Dit component is verantwoordelijk voor het genereren van de daadwerkelijke pixels uit de berekende paginagegevens. De PageRenderer werkt in een loop met de Engine Worker: zodra er een frame nodig is, haalt de renderer het paginagegeven (de scene) op van PageScript, haalt interne fonts en afbeeldingen op via Static Assets, rasteriseert alles naar een image buffer en stuurt dit terug als JPEG/PNG of PDF.
Een groot deel hiervan wordt afgehandeld door blitz-paint, die op zijn beurt Parley gebruikt voor het vormen van tekens tot glyphs, het kiezen van fonts en het breken van tekst in regels.
Workers' ingebouwde RPC-systeem
Cloudflare Workers hebben een ingebouwd Remote Procedure Call (RPC) systeem waarmee methoden op andere Workers kunnen worden aangeroepen zonder dat men zich zorgen hoeft te maken over API-schema's of authenticatie.
Kitesurf gebruikt dit systeem: de Engine Worker roept renderFrame() aan bij de PageRenderer Worker via RPC en ontvangt een PNG als resultaat. Omdat de renderer geen paginastatus bevat, kan de engine deze veilig beëindigen en opnieuw lanceren bij elke mislukte of vastgelopen RPC-aanroep.
Resultaten: Kitesurf doorloopt 215.000+ WPT tests
Kitesurf werkt. Het doorloopt momenteel ruim 215.000 WPT-tests, en we voegen wekelijks honderden nieuwe tests toe. De onderdelen die cruciaal zijn voor agents (zoals CSS, DOM, HTML, selectie, SVG en XHR) hebben al een goede dekking.
Prestaties
Hieronder volgt een vergelijking van de medianen van vijf Browser Run quick-action runs over een corpus van 14 URL's tussen Chromium en Kitesurf:
| Metriek | Kitesurf | Chromium (warm pool) | Relatieve winst/verlies |
|---|---|---|---|
| CPU: screenshot | 380 ms | 1.173 ms | 3,1× minder CPU |
| CPU: HTML extractie | 229 ms | 877 ms | 3,8× minder CPU |
| Geheugen: screenshot | 57,8 MiB | 271,0 MiB | 4,7× minder geheugen |
| Geheugen: HTML extractie | 39,4 MiB | 273,7 MiB | 7,0× minder geheugen |
| Wall time: screenshot | 1.148 ms | 637 ms | 1,8× trager |
| Wall time: HTML extractie | 820 ms | 472 ms | 1,7× trager |
Chromium wint op snelheid (wall time) omdat een JIT die de pagina al kent altijd sneller is dan een cold software renderer. Het grootste deel van dit verschil komt door rasterisatie en JPEG/PNG-codering, waar we aan optimaliseren. Echter, Kitesurf wint op geheugen en CPU — de factoren die de kosten bepalen — met een factor 3 tot 7.
De ultieme test: Doom
Een project is pas echt compleet als Doom erop draait. Dat is gelukt: Kitesurf kan succesvol https://silentspacemarine.com/ renderen.
Probeer het vandaag in Browser Run
Kitesurf is gratis beschikbaar tijdens de bètafase in Browser Run (onderhevig aan per-account limieten). Omdat het CDP-endpoint van Browser Run Kitesurf ondersteunt, werken bestaande clients zoals Puppeteer, Playwright of AI-agents die MCP en CDP spreken direct. Voeg simpelweg de parameter browser=kitesurf toe aan de endpoints.
Voorbeeld: Gebruik met MCP-clients (CDP)
Gebruik deze configuratie voor Opencode:
{
"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
}
}
}
Voorbeeld: Quick Actions via CURL
Voor een snelle screenshot van bijvoorbeeld Wikipedia:
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"
Wanneer is Kitesurf de beste keuze?
Kitesurf rendert momenteel correct pagina's zoals TodoMVC, Wikipedia, Hacker News, de Cloudflare Blog en grote delen van het Cloudflare-dashboard.
Kitesurf is ideaal voor:
- AI-agents die pagina's moeten renderen maar acceptabel vinden dat het geen pixel-perfecte Chromium-browser is.
- Automatiseringen die vertrouwen op 'one-shot' Quick Actions, zoals het extraheren van inhoud of het genereren van PDF's en screenshots voor compatibele sites.
- Burst-gevoelige, AI-gestuurde workloads waar een efemere, volledig geïsoleerde en stateless engine nodig is.
Kitesurf is (nog) niet geschikt voor:
- Het afspelen van video of het renderen van WebGL.
- Het onderhandelen van bot-challenge handshakes met echte TLS-fingerprints.
- Lange geauthenticeerde sessies die persistente status vereisen. In deze gevallen is de standaard Chromium-optie in Browser Run de juiste keuze.
De toekomst van Kitesurf
Kitesurf is pas twaalf weken oud (eerste commit in mei). We werken momenteel aan:
- Betere CDP-dekking: Uitbreiding van de subset van het protocol om vollediger te zijn voor agents en automatiseringstools.
- Rendering fidelity: Verbeteren van screenshots en PDF's, omdat LLM's vaak beter werken met afbeeldingen dan met ruwe tekst.
- WPT-dekking: Versnelde iteraties om meer web API's toe te voegen.
- Efficiëntie: Continue optimalisatie van CPU-, geheugen- en wall time benchmarks.
Uiteindelijk is het doel om Kitesurf open source te maken, zodat klanten hun eigen versie kunnen implementeren op hun eigen accounts.
Groetjes,