using-lightpanda
Operates Lightpanda, a Zig-based headless browser with no rendering pipeline, as an AI agent's browser tool via native MCP or CDP. Covers MCP tool selection (goto, markdown, semantic_tree, interactiveElements, structuredData, click, fill), output mode strategy, the observe-decide-act loop, actions grounded in node IDs, token-efficient page reading, and Chrome fallback triggers. Use when tasks require interactive or stateful web navigation on JS-heavy sites (multi-step flows, form fill/click actions, DOM-aware extraction by node ID), or when the user explicitly asks to use Lightpanda.
Using Lightpanda
What Lightpanda is
Lightpanda is a headless browser written in Zig with V8 for JavaScript and html5ever for HTML parsing. It is not a Chromium fork. It deliberately omits the entire rendering pipeline (layout, paint, compositing, GPU, font and image decoding).
Three modes of operation:
lightpanda fetch <URL>— one-shot CLI, dumps HTML or markdown to stdout.lightpanda serve— CDP WebSocket server; target for Puppeteer/Playwright.lightpanda mcp— native MCP stdio server exposing browser actions as tools.
Sub-100ms cold start. ~9–11× faster and ~9–16× less memory than headless Chrome on equivalent workloads. Beta maturity — ~95% site compatibility.
Scope
- Interactive, stateful browsing flows where the agent must
goto,click, andfillover multiple steps. - JS-dependent pages where static HTTP fetches miss important content.
- Targeted extraction from rendered page state using
markdown,structuredData, or a scoped node subtree.
Non-goals
- Open-web source discovery or ranking.
- Bulk multi-URL research extraction tasks.
- Generic URL-to-markdown conversion when no page interaction is needed.
- Non-HTML document conversion (PDF/DOCX/PPTX/audio/image workflows).
When Lightpanda won't work
Stop and use Chrome (or tell the user to) when:
- Screenshots, PDF export, or pixel inspection are needed — no renderer.
- Bot-protected sites (Cloudflare managed challenge, DataDome, Akamai, PerimeterX) — Lightpanda's fingerprint is trivially detectable.
- Complex SPAs crash or stall — ~5% failure tail on heavy React/Angular/Vue apps. Fall back rather than retrying.
- Layout-dependent APIs are required (
getBoundingClientRectreturns meaningless values,IntersectionObservergeometry is fake,CanvasRenderingContext2D.getImageDatareturns no real pixels).
Starting Lightpanda
MCP mode (preferred for agents)
LIGHTPANDA_DISABLE_TELEMETRY=true lightpanda mcp
Configure in an MCP client (e.g. Claude Desktop claude_desktop_config.json):
{
"mcpServers": {
"lightpanda": {
"command": "lightpanda",
"args": ["mcp"],
"env": { "LIGHTPANDA_DISABLE_TELEMETRY": "true" }
}
}
}
CDP mode (for Puppeteer/Playwright escape hatch)
LIGHTPANDA_DISABLE_TELEMETRY=true lightpanda serve --host 127.0.0.1 --port 9222
Connect via puppeteer-core. See
references/01-cdp-and-configuration.md
for connection details, LP.* extensions, cookies, and proxies.
Key flags
| Flag | Meaning | Default |
|---|---|---|
--log-level | debug, info, warn, error | info |
--http_timeout | Max HTTP transfer time in ms (0 = never) | 10000 |
--http_proxy | Proxy URL (supports basic auth inline) | — |
--proxy_bearer_token | Bearer token for Proxy-Authorization | — |
--obey-robots | Respect robots.txt | off |
--wait-until | Lifecycle event (networkidle) — fetch only | — |
--dump | html or markdown — fetch only | — |
Always set LIGHTPANDA_DISABLE_TELEMETRY=true when starting Lightpanda.
Pass it as an environment variable in every invocation — serve, mcp,
and fetch.
Core workflow: observe → decide → act
Every browser interaction follows three steps:
- Observe — read the page with
markdown,semantic_tree, orinteractiveElements. - Decide — reason over the compact observation; plan the next action.
- Act — call
goto,click(node ID),fill(node ID, value).
After every goto, re-observe. Do not carry stale observations forward —
the page changed.
MCP tools
| Tool | Purpose |
|---|---|
goto | Navigate to a URL. Specify a wait strategy. |
markdown | Page content as CommonMark. Optional target node ID for scoping. |
semantic_tree | Semantic outline with stable node IDs. |
interactiveElements | Only clickable/fillable elements with node IDs. |
structuredData | JSON-LD, OpenGraph, schema.org metadata. |
click | Click by node ID (not CSS selector). |
fill | Fill a form field by node ID. |
evaluate | Run arbitrary JS. Escape hatch for unusual cases. |
waitForSelector | Wait until a CSS selector appears. |
Choosing the right output
| Goal | Tool | Typical tokens |
|---|---|---|
| Read an article or long text | markdown | 200–800 |
| Understand page structure to plan actions | semantic_tree | 400–1200 |
| Pick an element to click or fill | interactiveElements | 100–300 |
| Extract product/article metadata | structuredData | 100–400 |
| Custom extraction not covered above | evaluate | varies |
Output selection rules
- Start with
markdownfor read-only research. Do not pull the semantic tree unless planning to act on the page. - Call
interactiveElementsbefore anyclickorfill. It is cheaper thansemantic_treeand returns exactly the node IDs needed for action. - Use
semantic_treefor structural reasoning — "find the section titled X and extract the table under it." - Use
structuredDatafirst on product/article pages — JSON-LD and OpenGraph are richer and more reliable than DOM extraction. - Scope
markdownto a node ID (fromsemantic_tree) for long pages. A fullmarkdownon a dense page can consume thousands of tokens.
Interaction rules
- Ground actions in node IDs. MCP
clickandfilltake node IDs returned bysemantic_treeorinteractiveElements— never hallucinate CSS selectors. - Wait before acting. After
goto, verify expected content is present (callmarkdownorwaitForSelector) before clicking. Networks are real, JS is async. - Re-observe after navigation. Every
gotoorclickthat triggers navigation invalidates prior observations. - Abort on repeated failures. If three consecutive actions fail on the same URL, stop and trigger fallback guidance. If five consecutive tool calls fail overall, stop and report the problem. Do not loop on broken selectors or crashed pages.
- Budget context. Prefer
interactiveElements(small) oversemantic_tree(medium) over fullmarkdown(large). Scope to a subtree via node ID when possible. - Treat
evaluateas a last resort. Prefer the typed MCP tools; raw JS is harder to debug and easier to get wrong.
Anti-patterns
- Expecting screenshots or PDF export. The rendering pipeline does not
exist. Do not attempt
screenshot— the tool is absent. - Using CSS selectors from LLM reasoning for
click/fill. Always use node IDs frominteractiveElementsorsemantic_tree. - Carrying stale observations across navigations. Re-observe after every page change.
- Dumping full-page
markdownon every turn. Scope to a section or usestructuredDatawhen structured data is the goal. - Retrying endlessly on a failing page. Lightpanda has a ~5% SPA incompatibility tail. After 3 consecutive failures on the same URL, report the issue and suggest a Chrome fallback.
Chrome fallback
When a page fails (navigation timeout, JS crash, repeated empty output, or 3 consecutive failures on the same URL):
- Report the failure to the user with the URL and error.
- Suggest retrying with Chrome/Chromium if available.
- Do not silently retry indefinitely — the failure is likely a compatibility gap, not a transient error.
Example: multi-step form submission
Task: Navigate to a site, find and fill a search form, read results.
Tool sequence:
goto→https://example.com(wait:networkidle)interactiveElements→ returns list including{id: 42, label: "Search", type: "input"}and{id: 43, label: "Submit", type: "button"}fill→ node ID 42, value"headless browser"click→ node ID 43markdown→ returns rendered search results as CommonMark
Key points: step 2 grounds the action in real node IDs before step 3–4 attempt interaction. Step 5 re-observes after the navigation triggered by the form submission.
Reference material
- CDP escape hatch, cookies, headers, proxies: references/01-cdp-and-configuration.md
- Troubleshooting and limitations: references/02-troubleshooting-and-limitations.md