Introduction
"Not a Chromium fork. Not a WebKit patch."
This is the 252nd article in the "One Open Source Project a Day" series. Today's project is Lightpanda, a headless browser built specifically for AI agents and automation.
Most of the web is now driven by JavaScript: SPAs, Ajax, React/Vue/Angular everywhere. Plain HTTP requests often don't return the real content, so people spin up Headless Chrome for crawlers and agents. But Chrome was designed for humans looking at pages. It carries a rendering pipeline, GPU handling, and user-facing features that headless work never touches. At scale, memory, startup time, and deployment cost become the problem.
Lightpanda's answer is to skip modifying Chrome and write a new browser in Zig instead. It keeps what you need to get page content: HTML parsing, the DOM, JavaScript execution through V8, and networking. It drops graphical rendering. The price is that Web compatibility has to be earned piece by piece; the payoff is an order-of-magnitude drop in resource use.
What You Will Learn
- Why skipping rendering makes such a large difference in memory and speed
- Lightpanda's building blocks: Zig + V8 + libcurl + html5ever
- What
fetch,serve,mcp, andagentare each good for - PandaScript: freezing an agent session into a deterministic, token-free script
- Its current limits: compatibility, platform support, and licensing
Prerequisites
- Familiarity with headless browsers (Headless Chrome, Puppeteer, Playwright)
- Knowing what CDP (Chrome DevTools Protocol) is
- Optional: some background on MCP (Model Context Protocol)
Project Background
What It Is
The project positions itself as a headless browser for AI agents and automation, a new browser written in Zig. Three explicit design choices:
- Not built on Chromium, Blink, or WebKit
- Zig, for explicit control over memory
- No graphical rendering engine
Project Stats
- ⭐ GitHub Stars: about 40,700
- 🍴 Forks: about 1,990
- 💻 Main language: Zig
- 📅 Created: 2023-02-07
- 📄 License: AGPL-3.0 (read the terms before using it commercially or inside a closed-source product)
- 💬 Community: Discord; contributions require signing a CLA
What It Does
The Problem It Solves
Running agents / crawlers on Headless Chrome:
A full browser process → heavy memory, slow startup, heavy deployment
↑ at high concurrency, cost goes to rendering you never use
Lightpanda's approach:
Keep only HTTP loading + HTML parsing + DOM + V8 for JS
↓ no painting
↑ same pages, much less memory and timeThe Official Benchmark
Run on an AWS EC2 m5.large, requesting 933 real pages:
| Metric | Lightpanda | Headless Chrome | Difference |
|---|---|---|---|
| Peak memory (100 pages) | 123MB | 2GB | about 16x less |
| Execution time (100 pages) | 5s | 46s | about 9x faster |
This is the project's own data, measuring content-fetching tasks. It doesn't transfer directly to workloads that need screenshot-grade rendering or heavy interaction.
Use Cases
- Large-scale page fetching: JS must run to get the content, but you don't want to pay for a Chrome per page
- Giving AI agents browsing ability: connect via the MCP server or CDP
- Swapping the backend of existing Puppeteer/Playwright scripts: change the connection endpoint, leave the script mostly alone
- Freezing what an agent discovered: replay it with PandaScript and stop spending tokens
Quick Start
Install
# macOS / Linux (Homebrew)
brew install lightpanda-io/browser/lightpanda
# Arch Linux
yay -S lightpanda-nightly-bin
# Nix
nix run github:lightpanda-io/browser -- --helpYou can also grab nightly binaries for Linux and macOS (x86_64 and aarch64), or use the official Docker image lightpanda/browser (amd64/arm64, CDP on port 9222). There is no native Windows build; use WSL2.
Fetch a page
# Output as html / markdown / png / pdf / structured_data, etc.
lightpanda fetch --dump markdown https://example.comControl timing with --wait-until, --wait-ms, --wait-selector, and --wait-script; --obey-robots respects robots.txt. The structured_data format extracts JSON-LD, OpenGraph, and similar data.
Run as a CDP server for Puppeteer
lightpanda serve --host 127.0.0.1 --port 9222import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://127.0.0.1:9222',
});
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await browser.disconnect();Besides CDP, serve supports a Unix socket and WebDriver BiDi (--protocol webdriver, or both protocols together).
Core Features
- Protocols: CDP over WebSocket, WebDriver BiDi
- Web capabilities: HTTP loader (libcurl), HTML parser (html5ever), DOM, JavaScript (V8), XHR and Fetch, CORS, cookies, custom headers, proxy, network interception, click and form input
- Other: robots.txt support, ad blocking
- MCP server:
lightpanda mcp, JSON-RPC 2.0 over stdio, or HTTP at/mcpwith--port - Native agent:
lightpanda agent, driven by plain English or slash commands; supports Anthropic, OpenAI, Gemini, Vertex AI, Mistral, Hugging Face, OpenRouter, any OpenAI-compatible endpoint, and local models such as Ollama and llama.cpp
A Deeper Look
Where the Savings Come From
Much of a browser's cost is rendering: style calculation, layout, painting, compositing, the GPU process. For an agent that only wants the DOM after JavaScript has run, all of that is wasted. Lightpanda keeps a lean pipeline:
URL → libcurl load → html5ever parse → DOM tree → V8 runs scripts
→ output HTML / Markdown / structured data / CDP eventsWith no painting step, there are no memory structures built for it either. Add Zig's explicit memory management, and that explains the 16x memory gap in the official numbers. One caveat: the fetch command lists png and pdf outputs, and how well they work is something to check in the docs and on your own pages. The primary purpose remains content extraction, not pixel-accurate rendering.
Component Choices: Not Reinventing Everything
Lightpanda writes the browser skeleton and Web API layer itself, and uses mature libraries for the heaviest parts:
| Part | Choice |
|---|---|
| Language | Zig |
| JavaScript engine | V8 |
| Networking | libcurl |
| HTML parsing | html5ever (Rust) |
A pragmatic call: JS engines and the HTML5 parsing spec are enormous, and rewriting them would be neither realistic nor useful. The cost is heavier build requirements: Zig 0.17.0, V8, libcurl, and a Rust toolchain, so building from source isn't trivial.
Four Entry Points for Four Needs
| Command | Good for |
|---|---|
fetch | One-off fetches, calling from scripts, CI |
serve | Existing Puppeteer/Playwright code, swapping the backend |
mcp | Giving MCP clients like Claude a browser directly |
agent | Exploring pages interactively in natural language |
In MCP mode, sessions are isolated by default; clients that share an Mcp-Session-Id share a browsing context, and session_new, session_list, and session_close manage sessions. The run tool executes PandaScript with a default timeout of 60000 ms.
PandaScript: Turning Agent Exploration Into a Deterministic Script
This is the design I find most interesting. Having an LLM look at the page and decide where to click every time is slow and burns tokens. A Lightpanda agent session can be saved with /save as JavaScript using built-in browser primitives, then replayed with lightpanda run script.js, with no model and no tokens.
First time: agent explores → finds a working path → /save as a script
After that: lightpanda run script.js → deterministic replay, zero tokensThis builds "LLM as scout, script as executor" into the tool itself. When a site redesign breaks the script, let the agent explore again.
Compatibility: Let WPT Speak
The biggest risk with a new browser is "this page doesn't work." The project publishes Web Platform Tests results daily (perf.lightpanda.io/wpt), so coverage isn't a matter of marketing; you can check it. Before committing, test the sites you actually need rather than relying on the benchmark alone.
Limits to Know
- AGPL-3.0 license: evaluate the network-use obligations before putting it in a public-facing service or closed-source product
- Platforms: no native Windows build; Linux binaries need glibc (2.35 on x86_64, 2.38 on arm64), so Alpine/musl won't work; no Android/Termux build
- Telemetry is on by default: disable it with
LIGHTPANDA_DISABLE_TELEMETRY=true - The README doesn't enumerate unsupported Web APIs: whether it fits your target sites is something to test yourself
Project Links and Resources
- 🌟 GitHub: https://github.com/lightpanda-io/browser
- 📊 WPT results: perf.lightpanda.io/wpt
- 🐳 Docker image:
lightpanda/browser - 🧩 Agent skill: lightpanda-io/agent-skill
- 💬 Community: the Discord link in the project README
Summary
Key Takeaways
- Idea: design a browser for getting content, not for human viewing, and drop rendering
- Numbers: in the official test, 100 pages took 123MB vs 2GB and 5s vs 46s
- Compatibility: CDP and WebDriver BiDi, so Puppeteer/Playwright connect directly
- AI-native: built-in MCP server, a multi-model agent, and PandaScript for zero-token replay
- Limits: AGPL-3.0, platform restrictions, and Web compatibility you need to verify yourself
Who This Is For
- Teams fetching dynamic pages at scale and weighed down by Chrome's resource use
- Developers building browsing capability for AI agents
- Anyone who wants to freeze agent exploration and cut token cost
Suggested First Steps
Start with fetch on a few pages you care about and compare the output with Chrome. Then use serve to point a small existing Puppeteer script at it and check compatibility and resource use. Only after that, consider scaling up.
Check out PrimeSkills — a curated marketplace of AI agents and skills that have been validated in real-world, enterprise-grade workflows. No fluff, just what actually works.
Find more useful knowledge and interesting products on my Homepage