Lightpanda Builds a Headless Browser in Zig: 123MB for 100 Pages, and It's Not a Fork of Chrome
A Headless Browser Without Forking Chrome: Lightpanda Builds from Scratch in Zig, 100 Pages Only 123MB Memory
Suppose you need to give a batch of AI agents browsing capabilities: fifty concurrent instances, each opening real web pages, executing JavaScript, filling forms, and reading the DOM. With headless Chrome, the memory bill gets ugly. A single instance easily eats several hundred MB, fifty instances start at tens of GB, before counting CPU usage and the few seconds of every cold start. Teams doing scraping and automation have long been numb to this pain, so numb that few stop to ask: why should a browser meant for machines carry an entire rendering engine built for human eyes? Lightpanda is a direct answer to that question. It doesn't fork Chromium, doesn't patch WebKit, and writes a headless browser from scratch in Zig, existing only for AI agents and automation. Over 41,000 stars on GitHub show that many teams are suffering from this problem.
A Browser That Doesn't Render Pixels for Humans
Lightpanda's self-introduction is one sentence: a headless browser designed for AI and automation. The key isn't headless; headless Chrome is also headless. The key is designed for AI. Today's web pages barely work without JavaScript. Ajax, single-page apps, infinite scroll, instant search; frameworks like React, Vue, and Angular turn pages into programs that need real script execution to show content. So scraping approaches that give up rendering early and only send HTTP requests no longer work on most modern sites. Automation tools must have a JavaScript-capable kernel.
The problem is that the only ready-made option is Chrome. Chrome's design goal is to draw smooth, pretty, animated pages on a screen for humans, so it carries the full rendering pipeline, compositor, GPU processes, font layout, and media decoding. None of these are needed in automation scenarios, but you pay for every megabyte and every CPU cycle. Some might ask: just add a few startup flags to Chrome? The answer is no. Chrome's headless mode only turns off the window; the rendering pipeline, compositor, and GPU processes still run in the background, and the big memory costs don't shrink. This isn't a switch problem; it's an architecture problem.
Lightpanda's judgment is straightforward: rather than trimming down Chromium, build a browser from scratch that keeps only the automation-required capabilities. No graphics rendering engine, not a single pixel meant for humans. Memory is explicitly managed in Zig. The project started in February 2023, is open-sourced under AGPL-3.0, and at the time of writing had 41,130 stars and 2,021 forks, with the last code push being yesterday. The team behind the project also maintains a hosted cloud service; the open-source version is a complete self-hosted option, and both lines share the same kernel.
123MB vs 2GB: The Official Benchmark Account
Speaking of lightness without numbers is meaningless. Lightpanda includes a reproducible benchmark in the README: on an AWS EC2 m5.large instance, against 933 real web pages via real network requests, then comparing data from 100 of those pages.
| Metric | Lightpanda | Headless Chrome | Gap |
|---|---|---|---|
| Peak memory (100 pages) | 123MB | 2GB | About 16x |
| Execution time (100 pages) | 5 seconds | 46 seconds | About 9x |
| Graphics rendering engine | None | Full Blink | Architectural difference |
| Implementation language | Zig | Mostly C++ | — |
| Native Windows version | None, via WSL2 | Yes | — |
| License | AGPL-3.0 | BSD and other permissive licenses | — |
The test method itself is also worth explaining. This isn't a marketing number picked from a few static pages; it's a public crawler benchmark from the official demo repo, with real network requests to 933 sites. Anyone can spin up an m5.large and rerun it. The m5.large has 2 vCPUs and 8GB RAM, an entry-level machine, and choosing that configuration itself shows the goal is simulating a cost-sensitive production environment, not piling on hardware to inflate scores.
First, a cold splash: these are official self-test figures, and your site mix, network conditions, and concurrency model will change the numbers. But the magnitude of this gap is structural, not something tuned away. A browser that doesn't maintain a render tree, doesn't do layout compositing, and never touches the GPU, compared to one carrying a full graphics stack, expecting an order-of-magnitude memory difference is reasonable. Look at the peak memory row again: 100 pages open simultaneously only use 123MB, meaning per-page resident overhead is around one or two MB, while Chrome's side is roughly 20MB per page. Converted to cost language: a 64GB machine that could barely breathe with thirty Chrome instances, with Lightpanda the same machine supports hundreds of sessions and then some. For cloud agent platforms that bill per instance, this isn't optimization; it's a rewrite of the pricing model.
Skeleton is Zig, Heart is Still V8
Building a browser from scratch sounds like a foolhardy toy project. Lightpanda works because it doesn't build everything itself. The JavaScript engine is embedded V8, the same as Chrome, so ES features and various clever site scripts execute as-is. HTTP loading uses Libcurl; HTML parsing uses html5ever, a parser honed by the Servo project. Zig glues these mature C and Rust components into a memory-controllable whole, with a build requirement of Zig 0.17.0.
Why not fork Chromium and modify? Because Chromium is a monster of tens of millions of lines, and after forking, you'd have to track upstream security patches and architecture evolution daily; a small team can't keep up. Lightpanda's component strategy is to borrow only the time-verified parsing and execution layers, writing its own scheduling and memory management, so upstream upgrades only require swapping component versions, not merging a whole forest. V8 also has a detail: the build can embed the V8 snapshot into the binary, saving per-start snapshot generation overhead and making cold starts faster, which is practical for scenarios that launch browsers per task.
The feature list also shows its focus on automation rather than browsing: CORS, DOM tree and DOM API, XHR and Fetch, cookies, custom HTTP headers, proxy support, network interception, built-in ad blocking, plus a switch that respects robots.txt, which when set will crawl according to site rules. Another noteworthy signal is the testing attitude: the project publishes Web Platform Tests pass results daily at perf.lightpanda.io, with pass rate and failures made transparent. Projects willing to show their test scores every day are usually more credible than those that only display scores in launch presentation slides.
CDP as Usual, Existing Scripts Unchanged
Switching browsers carries the hidden cost of rewriting automation code. Lightpanda pushes that cost close to zero. It natively implements the Chrome DevTools Protocol and also supports WebDriver BiDi, so Puppeteer and Playwright scripts only need to point the connection address at it. Running a CDP service takes one command:
docker run -d --name lightpanda -p 127.0.0.1:9222:9222 lightpanda/browser:latest
./lightpanda serve --obey-robots --host 127.0.0.1 --port 9222
./lightpanda fetch --dump markdown https://demo-browser.lightpanda.io/campfire-commerce/
On the Puppeteer side, it looks like this; apart from the connect line, everything else stays the same:
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://127.0.0.1:9222',
});
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto('https://demo-browser.lightpanda.io/amiibo/', { waitUntil: 'networkidle0' });
const links = await page.evaluate(() =>
Array.from(document.querySelectorAll('a')).map(a => a.getAttribute('href'))
);
console.log(links);
await browser.disconnect();
Incidentally, the fetch subcommand itself is a handy Swiss Army knife. It can export pages directly as HTML, Markdown, PNG, PDF, or use structured data mode to bundle JSON-LD, OpenGraph, Twitter Card, and meta tags into a single JSON, so you don't have to write a parser again for content cleaning and SEO checks. For pages with async rendering, fetch provides wait parameters: wait a fixed number of milliseconds, wait for a selector to appear, or wait until a custom script returns a truthy value before exporting. No need to drag in a full Puppeteer just to wait for a lazy load. PNG export needs a note: it's a text-level rendering snapshot, suitable for quickly confirming page structure, not a pixel-accurate screenshot. For visual regression, real Chrome remains necessary.
Two more production-oriented designs deserve mention. The CDP service can listen not only on a TCP port but also on a Unix domain socket, with file permissions set to owner read/write only, which is safer than open ports in same-host multi-tenant scenarios. BiDi protocol support can run alongside CDP, meaning clients of the new standard and scripts from the old ecosystem can coexist on the same instance, so you don't have to choose during migration. For Playwright users, the entry point is connectOverCDP, again changing only the connection parameter; page objects, locators, and assertion syntax remain unchanged, and existing test suites don't need to switch with the browser.
Agent Mode and PandaScript: LLM for Prototyping, Bare-Machine Replay
A browser with a built-in agent is the default for this year's new projects. Lightpanda's approach has a rare pragmatic design. Its agent subcommand accepts natural-language tasks and controls the browser for navigation, clicking, form filling, and structured data extraction. Model providers cover Anthropic, OpenAI, Gemini, Vertex, Mistral, Hugging Face, and aggregator gateways like Vercel AI Gateway and OpenRouter. Local models run via Ollama or llama.cpp, and you can even log into a ChatGPT subscription and use Codex directly without buying a separate API key. One engineering detail: the agent and browser run in the same process, so each tool call is a direct in-process operation, unlike common approaches where the agent process exchanges messages with an external Chrome via CDP. This eliminates a whole layer of IPC serialization overhead, and the speed and memory advantages hold in agent mode.
The real cleverness is at the output end. The artifact of an agent session is a PandaScript, essentially vanilla JavaScript plus a set of browser primitives built into Lightpanda. During the session, an export command saves the script, and later the run subcommand replays it offline; script execution is deterministic and consumes zero tokens. In other words, during development you let the LLM iterate and get the flow working, and production runs a deterministic script without any model. The LLM handles exploration, the script handles execution, and the cost models of the two phases are completely separated. PandaScript being ordinary JavaScript is also key: it can go into git, be code-reviewed, and be diffed. When something goes wrong in production, you have records to inspect rather than guessing from a pile of model sampling logs. For manual operation there's also a model-free REPL mode for trying commands one by one during debugging. Common subcommands are complete: run with a task argument exits after one execution, suitable for scripted calls; the subcommand listing models available from current providers avoids awkward model-name guessing.
MCP Service Session Isolation is Finer Than Most Frameworks
Lightpanda has a built-in MCP server. stdio mode follows standard JSON-RPC 2.0 and can be pulled up directly by clients like Claude Code via MCP config. More noteworthy is HTTP mode: one command starts a service on port 9223, and multiple agent clients can POST to the same endpoint simultaneously without interfering. The isolation mechanism relies on the Mcp-Session-Id header: clients that initialize without this header get a fresh session with a session ID in the response, and subsequent requests carrying it stay in their own session. Two agents deliberately sending the same ID share the same browsing context, suitable for workflows where multiple agents collaborate on one page.
Sessions have explicit management interfaces: new, list, and close all have corresponding tools, and a DELETE request to a session destroys it. The run tool executes PandaScript directly in the caller's session, with a default 60-second timeout to prevent scripts from hanging. Pages opened by the script close automatically at the end, but cookies and storage persist, so login state can carry across multiple runs, which is very friendly for crawl flows that need to log in first. Script parameters can be a source string or a path to a previously saved file, and the return value comes back with console output. For backend engineers, the integration shape is an HTTP endpoint, one request completes one browsing task, and the process lifecycle isn't something you manage yourself. The official repo also maintains a separate Agent skill repository that coding agents can install and call directly. A single curl from the backend drives the browser:
lightpanda mcp --port 9223
curl -s http://127.0.0.1:9223/mcp -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"run","arguments":{"script":"const page = new Page(); await page.goto(\"https://example.com\"); return page.title();"}}}'
Many MCP browser servers on the market use a single-page global state. When two agents run concurrently, they navigate each other's pages into chaos. Lightpanda's design, which isolates pages, cookies, and memory per session, directly hits the most painful point in multi-agent production environments.
When Not to Switch
We've talked about many strengths; now we should draw the boundaries clearly, otherwise it's misleading. The first cut is the license: AGPL-3.0 is strong copyleft. If you embed Lightpanda into a closed-source commercial product and offer it as a service, legal must clear that first. Internal use is largely unaffected. The second cut is platform support: there's no native Windows binary. Windows users must use WSL2 or Docker. If your team is all Windows machines, factor in the integration cost. The third is compatibility ceiling: its daily WPT scores show many web platform features are still missing. Sites that heavily rely on complex visual rendering, WebGL, Canvas fingerprinting, or media playback may behave differently from real Chrome. You need to test with target sites; you can't assume it'll work.
Two other small pitfalls: telemetry is on by default; turn it off with an environment variable if you care. The nightly binaries require specific glibc versions for Linux distributions: x86_64 needs 2.35 or above, arm64 needs 2.38 or above. Old images will report a loader-missing error. Before migrating, suggest a small validation checklist: take five to ten representative pages from target sites, run fetch with Markdown export, manually check whether extracted results are complete, then sample-compare against Chrome. Half a day will reveal the compatibility baseline. My advice is to split by scenario: crawling, form automation, and structured data extraction tasks that don't need visual fidelity should switch to Lightpanda first; the memory and speed gains are visible the same day. Tasks that need pixel-perfect reproduction of what the user sees, or run regression screenshot comparisons, should stay in the Chrome family. Three decades old, the browser product category has for the first time had a project openly admit its users are not human, which alone deserves a second look beyond the 40,000 stars.
Top 2 of 3 from juejin.cn, machine-translated. The original thread is authoritative.
How do you use it with Java?
If you're using Playwright for Java, first run `lightpanda serve --host 127.0.0.1 --port 9222`, then replace your original `launch()` with `playwright.chromium().connectOverCDP("ws://127.0.0.1:9222")`. Start with a simple page to test opening and locating elements. Are you currently using Playwright or Selenium?
Awesome.