---
summary: "Use an externally managed Lightpanda browser for JavaScript and DOM tasks"
title: "Lightweight browsers"
read_when:
  - You want browser tasks to use a lightweight engine instead of Chromium
  - You run OpenClaw or its browser in Docker
  - You need the limits of the Lightpanda browser profile
---

# Lightweight browsers

Lightpanda is an opt-in engine for text and DOM browser tasks. It uses the same
OpenClaw `browser` tool through an explicitly configured profile. It is not a
visual-browser replacement: keep a Chromium profile for screenshots, PDF output,
and applications that require unsupported browser features.

The examples pin Lightpanda **1.0.2**. They do not change your existing browser
profile, install a service, or migrate a logged-in Chrome profile.

## Browser plugin architecture

The bundled Browser plugin owns both engine adapters. Chromium and Lightpanda
use the same `browser` tool, profile selection, route admission, navigation
policy, and session lifecycle. The registered adapter selects capabilities,
CDP normalization, snapshot defaults, and connection lifetime; it does not add
a second browser tool or process manager.

Browser status reports `availableEngines` and the selected engine's
`sessionScope` and `screenshotFidelity`. Chromium keeps its managed,
existing-session, extension-relay, and remote-CDP profiles. Lightpanda remains
an explicitly selected, attach-only external engine with one page per
connection and no automatic read replay after session loss.

These are adapters inside the existing plugin, not separately installable
third-party plugins. Enabling the adapter does not download, launch, or bundle
the Lightpanda engine. Existing profiles and engine configuration are unchanged.

## Licensing and distribution

OpenClaw's adapter remains MIT-licensed. The optional Lightpanda engine is
**AGPL**, not MIT. Version 1.0.2 has inconsistent declarations: its
[licensing document](https://github.com/lightpanda-io/browser/blob/c5f7bb29b127040c899d4e181b5709f76fc71a6f/LICENSING.md)
says `AGPL-3.0-only`, while its
[pinned source notice](https://github.com/lightpanda-io/browser/blob/c5f7bb29b127040c899d4e181b5709f76fc71a6f/src/main.zig#L1)
allows later versions. Record that discrepancy during your SBOM review; neither
interpretation makes the engine permissively licensed.
The existing Playwright client is Apache-2.0; the existing `ws` client is MIT.
Their licenses and third-party notices still apply.

These examples connect over CDP to an independently installed, unmodified engine.
They do not bundle or relicense Lightpanda in OpenClaw's package or image.
The engine and its container dependencies are not an MIT-only distribution.
If your deployment excludes copyleft software, do not select this engine.

Mirroring or bundling the engine requires a separate redistribution review,
including license notices, Corresponding Source, and third-party obligations.
Modifying a network-served engine also requires reviewing AGPL section 13.
A separate process is not a blanket legal exemption, and checksum verification
does not establish license compliance. See the
[artifact and dependency review](https://github.com/openclaw/openclaw/blob/main/deploy/lightpanda/README.md)
for the verified pins and remaining limits.

## Alternatives reviewed

The following is a licensing comparison as of **2026-09-21**, not a claim that
these alternatives have passed OpenClaw integration or cross-platform tests.
An MIT-compatible application and an entirely permissive engine distribution
are different requirements.

| Option                  | Engine and licensing boundary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Chromium headless shell | An established CDP engine, not an all-permissive binary. The inspected 153.0.8010.12 distribution's `LICENSE.headless_shell` includes LGPL and MPL notices; its pinned sources identify [FFmpeg's LGPL terms](https://chromium.googlesource.com/chromium/third_party/ffmpeg/+/53fa34a23be9054d25ac2500dbdae9a0e570bb5c/README.chromium) and [mixed-license hyphenation data](https://chromium.googlesource.com/chromium/src/+/971a7443b0c9b0a9b2860529b33331b76077ec62/third_party/hyphenation-patterns/README.chromium). |
| Cloudflare Kitesurf     | A [hosted, stateless Browser Run engine](https://developers.cloudflare.com/browser-run/kitesurf/), not a downloadable replacement in this review. Cloudflare's [announcement](https://blog.cloudflare.com/kitesurf/#final-notes) describes open-sourcing as future work; a self-hosted engine release and its license were not available for this audit. Service terms are separate from client-library licenses.                                                                                                         |
| Obscura 0.2.3           | A standalone Rust engine with embedded Deno/V8 and an [Apache-2.0 root license](https://github.com/h4ckf0r0day/obscura/blob/1a3169da276d7720732c7b20535474942917fb83/LICENSE). It is the strongest standalone lightweight candidate reviewed for avoiding an AGPL engine, but has MPL dependencies and unresolved redistribution-notice work. It is not an all-permissive replacement.                                                                                                                                    |

Automation clients do not replace the engine. For example,
[Vercel's agent-browser](https://github.com/vercel-labs/agent-browser/blob/44583ac8385d814ab98cbf40feec97620376b50e/README.md)
offers Chrome and Lightpanda backends; its own Apache-2.0 license does not change
the selected engine's license. The same distinction applies to Playwright and
Puppeteer clients.

### Obscura audit boundary

[Release v0.2.3](https://github.com/h4ckf0r0day/obscura/releases/tag/v0.2.3)
was reviewed at commit `1a3169da276d7720732c7b20535474942917fb83`.
Its [lockfile](https://github.com/h4ckf0r0day/obscura/blob/1a3169da276d7720732c7b20535474942917fb83/Cargo.lock)
contains 471 registry packages. Their license declarations include no AGPL,
but five are MPL-2.0-only: `cooked-waker` 5.0.0, `cssparser` 0.34.0,
`cssparser-macros` 0.6.1, `dtoa-short` 0.3.5, and `selectors` 0.26.0.
These dependencies remain in the no-render engine's DOM/JavaScript paths.
[MPL's file-level obligations](https://www.mozilla.org/en-US/MPL/2.0/FAQ/)
do not require unrelated MIT adapter files to become MPL; they still apply to
the covered code and its distribution.

The downloaded Linux x86-64 no-render archive matched release SHA-256
`b5e55e8f2c97814127a521cd59af1a84b79dc40cf658fda04df04af81a2d89f3`.
It contained only `obscura` and `obscura-worker`, without license or notice files.
The pinned [release workflow](https://github.com/h4ckf0r0day/obscura/blob/1a3169da276d7720732c7b20535474942917fb83/.github/workflows/release.yml)
packages only those executables and does not use Cargo's `--locked` flag.
Consequently, source-lock metadata is not proof of the complete dependency set
inside each release binary. Full V8/third-party and platform-library review,
notices, source availability, and runtime compatibility remain to be verified
before bundling or recommending an integrated deployment.

## Choose where the engine runs

| OpenClaw location       | Lightpanda location                              | Profile CDP URL        |
| ----------------------- | ------------------------------------------------ | ---------------------- |
| Host, including Windows | Docker/Podman with a loopback-published port     | `ws://127.0.0.1:9222`  |
| Linux or macOS host     | Native binary on the same host                   | `ws://127.0.0.1:9222`  |
| Docker Compose          | Sidecar in the same Compose project              | `ws://lightpanda:9222` |
| WSL                     | Native Linux binary in the same WSL distribution | `ws://127.0.0.1:9222`  |

`localhost` inside an OpenClaw container means that container, not the host and
not the Lightpanda sidecar. Use the service name for container-to-container
connections. On Windows, run Docker Desktop in **Linux container** mode, or run
both OpenClaw and the Linux engine inside WSL. Lightpanda does not publish a native
Windows binary. macOS and Linux have official x86-64 and ARM64 release binaries;
the official container image has Linux amd64 and arm64 variants.
[Upstream installation information](https://github.com/lightpanda-io/browser#install).

## Docker with OpenClaw on the host

From the repository root:

```sh
docker compose -f deploy/lightpanda/compose.yaml -f deploy/lightpanda/compose.host.yaml up -d --wait
docker compose -f deploy/lightpanda/compose.yaml -f deploy/lightpanda/compose.host.yaml ps
docker compose -f deploy/lightpanda/compose.yaml -f deploy/lightpanda/compose.host.yaml exec lightpanda /bin/lightpanda version
```

The sample publishes CDP on `127.0.0.1:9222` only. Set `LIGHTPANDA_PORT` to select
another host port, and update the profile URL to match. The image is pinned by its
multi-platform digest, so Docker selects the host architecture without pulling a
moving `latest` or `nightly` version.

The healthcheck opens an independent local CDP WebSocket session and checks its
handshake. This proves listener readiness, not successful browsing or OpenClaw
integration. The sample leaves memory, CPU, and PID limits unset. Set limits for
your measured workload in your deployment's Compose configuration, or use
[`docker update`](https://docs.docker.com/reference/cli/docker/container/update/)
with `--memory`, `--cpus`, and `--pids-limit` for an existing container.
`restart: unless-stopped` restarts a crashed engine but does not restart a
still-running unhealthy container. Monitor unhealthy status and replace failed
workers through your deployment's supervisor. Restarting loses that worker's
page/login state; do not automatically replay clicks or submissions.

The stop signal is `SIGTERM`, with a 10-second grace period, overriding the
upstream image's immediate `SIGKILL`. This is a single-worker example, not a
high-availability service or transparent failover guarantee.

CDP gives a client control over the browser; the sample does not add CDP
authentication. Do not change the loopback binding to a public address. Use an
authenticated tunnel for access from another host.

To stop and remove only this sample's container and network:

```sh
docker compose -f deploy/lightpanda/compose.yaml -f deploy/lightpanda/compose.host.yaml down
```

## Docker Compose with OpenClaw in a container

Merge the sidecar into the repository's existing Compose project:

```sh
docker compose -f docker-compose.yml -f deploy/lightpanda/compose.yaml up -d --wait lightpanda
```

Configure the OpenClaw Gateway with `cdpUrl: "ws://lightpanda:9222"` in the profile
below. Use the same Compose files and project name when starting the Gateway.
No browser port is published to the host in this variant. The containers share
the project's bridge network and retain outbound internet access; the network
is not declared `internal: true` because that would prevent public-site browsing.

Use your normal OpenClaw Docker setup for its state directory, authentication,
and Gateway startup. The sidecar does not mount your OpenClaw state, browser
cookies, or host Docker socket.

For Podman, use an installed Compose provider and verify service-name DNS before
choosing the sidecar URL. A netavark installation without its `aardvark-dns`
helper can start a loopback-published engine while leaving container DNS broken;
successful engine startup does not prove sidecar connectivity.

## Native Linux and macOS

Download the release binary for your operating system and CPU from
[Lightpanda 1.0.2](https://github.com/lightpanda-io/browser/releases/tag/1.0.2).
The sample's `deploy/lightpanda/SHA256SUMS` records the release asset digests.

For Linux x86-64, run from the repository root:

```sh
curl --fail --location --output lightpanda-x86_64-linux https://github.com/lightpanda-io/browser/releases/download/1.0.2/lightpanda-x86_64-linux &&
  sha256sum --check --ignore-missing deploy/lightpanda/SHA256SUMS &&
  chmod +x lightpanda-x86_64-linux &&
  LIGHTPANDA_DISABLE_TELEMETRY=1 LIGHTPANDA_DISABLE_CORE_DUMP=1 ./lightpanda-x86_64-linux serve --host 127.0.0.1 --port 9222
```

For macOS Apple silicon:

```sh
curl --fail --location --output lightpanda-aarch64-macos https://github.com/lightpanda-io/browser/releases/download/1.0.2/lightpanda-aarch64-macos &&
  shasum --algorithm 256 --check --ignore-missing deploy/lightpanda/SHA256SUMS &&
  chmod +x lightpanda-aarch64-macos &&
  LIGHTPANDA_DISABLE_TELEMETRY=1 LIGHTPANDA_DISABLE_CORE_DUMP=1 ./lightpanda-aarch64-macos serve --host 127.0.0.1 --port 9222
```

Use `lightpanda-aarch64-linux` for Linux ARM64 or
`lightpanda-x86_64-macos` for Intel macOS. Only execute the downloaded binary after
its checksum matches. Linux release binaries require glibc; use the official
container image on musl-based systems such as Alpine. These commands run the
engine in the foreground; stop it with Ctrl+C.

## Configure an opt-in profile

Merge this browser block into your existing configuration:

```json5
{
  browser: {
    profiles: {
      lightpanda: {
        engine: "lightpanda",
        cdpUrl: "ws://127.0.0.1:9222",
        attachOnly: true,
      },
    },
  },
}
```

Use `profile: "lightpanda"` on browser tool calls. When the selected workload has
passed your checks, set `browser.defaultProfile` to `"lightpanda"` to make it the
default. Preserve your Chromium profile and select it explicitly for visual or
unsupported work. Restore the previous `defaultProfile` to undo the selection.

`engine` declares the capability contract; a CDP endpoint alone does not imply
Chromium compatibility. `attachOnly` means OpenClaw attaches to the service you
started instead of launching or taking ownership of a local Chrome process.
Do not set `executablePath` to Lightpanda: its CLI is not Chrome's launch CLI.

## Session and capability limits

- A Lightpanda CDP connection owns its page state. Closing the connection, stopping
  the container, or restarting the engine loses that state; reconnecting does not
  resume the previous page or login.
- One CDP connection supports one page target. Separate connections can coexist,
  but a Lightpanda profile is not a general multi-tab Chromium session.
- No automatic cross-engine replay occurs after an action fails. A click or form
  submission may already have happened; inspect its outcome before repeating it.
- Lightpanda's text-layout preview is not a rendered screenshot. It cannot prove
  CSS, image, font, or visual-layout correctness.
- The verified snapshot path is AI format with `aria` references. The engine
  selects those references by default, including efficient snapshot mode.
  Explicit role references, selector/frame-scoped snapshots, labeled screenshots,
  and the separate `aria` snapshot format are unsupported in this adapter.
- JavaScript and web APIs are not a guarantee that every website will work.
  Verify the sites and interaction patterns you actually use.
- Lightpanda 1.0.2 enforces CORS by default. Cross-origin fetch/XHR requests need
  the destination's appropriate CORS headers; the sample does not disable this
  protection. The engine also takes its language from `--locale` instead of
  falling back to English.

The engine and its session model are documented in the
[pinned Lightpanda source](https://github.com/lightpanda-io/browser/tree/c5f7bb29b127040c899d4e181b5709f76fc71a6f).
See [browser profiles](/tools/browser/profiles) and
[remote browsers](/tools/browser/remote) for the shared profile and routing rules.

## Page classification and judge

Browser `action="judge"` triages page blockers with the calling agent's selected
[Decision model](/concepts/decision-models), without returning page text to the
primary model. It reads up to 6,000 body-text characters from the existing tab,
adds the untrusted-content wrapper, and returns the typed Decision outcome.
It works with both text-capable Chromium and Lightpanda profiles. The bundled
`browser-automation` skill explains the separate loading,
empty-results, login, consent, bot-challenge, paywall, error, and unsupported-browser
questions. It is explicit, advisory work, not automatic navigation policy.

Use the selected provider only when page data is authorized for that destination.
Hosted Decision providers can charge; a local browser does not imply local
inference. Missing tools or unavailable inference leave ordinary browser
inspection available, not an automatic model/engine fallback. Missing, uncertain,
or all-low blocker scores do not prove usable content, especially on blank or
truncated pages. Consent, login, CAPTCHA, and payment actions still need their
normal authorization.

This is **not native Lightpanda `judge()` support**. As inspected on October 24,
2026, upstream
[`page.judge()`](https://github.com/lightpanda-io/lightpanda-python/blob/7b17601189e49c0678e2914fa51994958c81a968/lightpanda/browser.py#L324-L349)
on the experimental `page-classify` branch calls the MCP `classify` tool. The
branch's [CDP LP dispatcher](https://github.com/lightpanda-io/browser/blob/e04f855dd202446828799ebdccab31116425ff31/src/server/cdp/domains/lp.zig#L34-L73)
does not expose classification. OpenClaw's adapter uses CDP, so neither an engine
version nor a successful connection establishes this capability. Opening a
separate MCP session would not classify the existing CDP page and its login state.

The upstream [classification implementation](https://github.com/lightpanda-io/browser/blob/e04f855dd202446828799ebdccab31116425ff31/src/browser/classify.zig#L233-L255)
builds URL/title/status plus at most 8,192 bytes of semantic-tree content, then
[calls TypeSafe](https://github.com/lightpanda-io/browser/blob/e04f855dd202446828799ebdccab31116425ff31/src/browser/tools.zig#L1988-L2024).
It is not evidence of embedded model weights or offline inference. Native
integration needs an upstream classification operation that targets the existing
CDP session, with explicit capability discovery and inference configuration.
Until then, do not guess `LP.classify`/`LP.judge` methods or forward OpenClaw
credentials into an external browser process.
The released [Lightpanda 1.0.2](https://github.com/lightpanda-io/browser/tree/c5f7bb29b127040c899d4e181b5709f76fc71a6f)
does not include the experimental classification tool. Python's feature branch
also shortcuts HTTP failures into local flags; these are not model probabilities
and OpenClaw does not fabricate those judgments.

## Lightpanda 1.0.2 compatibility

The normal OpenClaw snapshot, reference-based typing/clicking, wait, and text
workflow was verified with the Linux x86-64 release binary and Playwright 1.64.0.
A successful click response is not proof that the task finished: wait for the
expected page state and read it back before reporting success or retrying a
submission.

The release improves mouse events inside shadow DOM, but an OpenClaw fixture
with a button in an open shadow root still fails Playwright's hit-target check
(`root.elementsFromPoint is not a function`). Use Chromium for affected sites;
do not force clicks or replay submissions to hide this compatibility gap.

Upstream's `fetch --dump structured_data` and `fetch --markdown-alternate` are
standalone Lightpanda CLI features, not new OpenClaw browser-tool arguments.
The upstream `LP.getPageStatus` CDP method reports page issues, including
JavaScript errors and failed or skipped resources. It is not exposed as an
OpenClaw browser action, and a clean issue summary alone does not prove task
completion. The adapter's capability limits above remain unchanged.

## Verification and benchmarks

Engine startup, CDP connectivity, task completion, and full OpenClaw integration
are separate checks. A running container or a successful `Browser.getVersion`
does not prove that snapshots, references, and actions work through OpenClaw.

### Chromium headless shell baseline

For an alternative without Lightpanda's AGPL engine, first test Chromium's
headless shell through the existing Chromium profile. It retains Chromium's
third-party license obligations; this is not an MIT-only binary. It does not
require another automation daemon or an OpenClaw engine adapter.

Use the repository-pinned Playwright installer rather than an unpinned wrapper:

```sh
node node_modules/playwright-core/cli.js install chromium-headless-shell
node node_modules/playwright-core/cli.js install --dry-run chromium-headless-shell
```

The second command prints the selected version, platform download, and install
directory. Locate `chrome-headless-shell` (or `chrome-headless-shell.exe` on
Windows) in that directory. Linux also needs the browser's system libraries and
fonts; see [Linux troubleshooting](/tools/browser-linux-troubleshooting).
Run from the repository root, quoting paths that contain spaces:

```sh
node --import ./scripts/tsx.mjs extensions/browser/scripts/bench-lightweight.ts --headless-shell "/path/to/chrome-headless-shell" --iterations 10 --output headless-shell-benchmark.json
```

The report labels the requested distribution separately from its Chromium
protocol engine and the observed browser version. `--headless-shell` selects
the benchmark executable only: it does not install a production browser,
change a profile, or establish binary provenance. Preserve its complete
distribution and `LICENSE.headless_shell` when reviewing deployment. The installer
also downloads platform helper assets, including FFmpeg; review and retain their
own notices separately. Use
separate invocations for the full Chromium and headless-shell comparisons;
memory or startup savings must be measured, not inferred from download size.

### Native engine comparison

Run the opt-in synthetic route benchmark from the repository root after
installing development dependencies:

```sh
node --import ./scripts/tsx.mjs extensions/browser/scripts/bench-lightweight.ts --lightpanda /path/to/lightpanda --chromium /path/to/chrome --iterations 10 --output lightweight-benchmark.json
```

Any binary flag can be used alone. The script creates isolated OpenClaw
state and browser data, serves a local form, then verifies navigation, the default
efficient AI snapshot, reference-based typing/clicking, exactly one form
submission, waiting, and text extraction through the browser route dispatcher.
The Chromium baseline uses OpenClaw's managed headless launch flags and disables
the sandbox for this isolated local fixture; it does not change production
browser configuration. Minimal Linux hosts still need Chromium's shared
libraries and fonts. A task-local installation can be selected using
`LD_LIBRARY_PATH` and `FONTCONFIG_FILE` without changing the host's packages.
Lightpanda additionally checks unsupported-operation rejection, its single-page
limit, and stale-target rejection after disconnecting. These checks do not use
an LLM and do not measure model reasoning or end-to-end agent token cost.

`--iterations` accepts 1 through 100 and counts **warm tasks**. A separate first
task includes the initial page open and CDP attachment; every warm task includes
navigation and the same form workflow. Native runs also report process startup
and time from startup through the first completed task. Warm percentiles exclude
the first task. Capability/session checks run after the measurement window.

A combined run uses one Node controller and records engine order; its later
engine can reuse controller modules already loaded by the earlier engine. The
first-task and process-start figures are not cold CLI/controller measurements.
Use separate invocations when comparing independently initialized controllers.

The memory fields are **maximum sampled process-tree PSS/RSS**, not true peaks.
They use Linux `/proc` with sampling attempts every 50 ms and at task boundaries.
Short-lived processes or transient allocations can be missed. Unsupported hosts
and externally managed engines report `null`, as do runs with unreadable process
memory, never a guessed engine-memory
figure. Controller RSS is a separate end-of-workload sample, not incremental
controller overhead; do not add independently sampled maxima and call the sum
total peak host memory.

### An externally managed engine

Use a dedicated engine instance. External mode closes the benchmark's control
connection and its own Chromium tab, but does not stop the engine process:

```sh
node --import ./scripts/tsx.mjs extensions/browser/scripts/bench-lightweight.ts --endpoint ws://127.0.0.1:9222 --engine lightpanda --fixture-bind 0.0.0.0 --fixture-host host.docker.internal --iterations 10 --output lightweight-container-benchmark.json
```

This example addresses a Docker Desktop engine from its host. The synthetic
fixture listener is explicitly exposed on the host so the container can reach
it; `--fixture-host` must name the controller from the browser's network, not
from the controller's own network. Linux Docker needs a reachable host address
or a configured `host-gateway` mapping. The default fixture listener/hostname
remain `127.0.0.1` when those flags are omitted.

External mode reports engine startup and memory as `null`. Capture the pinned
container/binary version separately with the report. A Windows Node controller
can use the same external-engine interface, but Windows Docker runtime behavior
has not been verified for this sample.

Compare the same deterministic tasks with a pinned Chromium baseline. Record
task completion before reporting speed or memory improvements; unsupported or
failed work must not be counted as a successful fast result. Report warm and
cold runs separately, engine versions, host OS/architecture, client overhead,
and whether memory includes the whole process tree or container.

For Docker Desktop, container memory does not include the VM's host overhead.
Do not compare a native-process RSS figure with a container-only figure and call
the difference total host savings. Keep all benchmark fixtures public or local;
do not export an existing logged-in browser profile to make a benchmark pass.

Platform support listed above describes upstream distribution and the deployment
topologies, not a claim that every platform has passed the same runtime tests.
Record actual platform and container-runtime results with the benchmark report.
