lightpanda-python
Lightpanda for Python: scrape and automate the web with pip install lightpanda. Browser included, no separate download.
Lightpanda is an open-source headless browser built for web scraping, automation, and AI agents. It executes JavaScript and renders pages like a full browser, but starts in milliseconds and uses an order of magnitude less memory than Chrome stacks. The wheel bundles the browser binary; there is no second install step.
uv add lightpanda # or: uv pip install lightpanda / pip install lightpanda
example.py:
from lightpanda import Browser
with Browser() as b:
page = b.new_session()
page.goto(url="https://example.com")
data = page.extract(schema={"title": "h1"})
print(data)
Run it like any Python script — no driver to install, no browser to download:
$ python example.py
{'title': 'Example Domain'}
The same API is available for asyncio — AsyncBrowser spawns the browser on
first use and runs sessions concurrently. async_example.py:
import asyncio
from lightpanda import AsyncBrowser
async def main():
async with AsyncBrowser() as b:
page = await b.new_session()
await page.goto(url="https://example.com")
data = await page.extract(schema={"title": "h1"})
print(data)
asyncio.run(main())
python async_example.py
The package also puts the full lightpanda CLI on PATH — agent REPL, fetch,
serve, and the rest: see the
command reference.
Drive it with Playwright or Puppeteer
Lightpanda has its own Chrome DevTools Protocol server, so existing
Playwright/Puppeteer code works against it without Chromium. CDPServer
starts lightpanda serve on a free localhost port and hands you the
endpoint:
from lightpanda import CDPServer
from playwright.sync_api import sync_playwright
with CDPServer() as server, sync_playwright() as p:
browser = p.chromium.connect_over_cdp(server.ws_endpoint)
page = browser.new_context().new_page()
page.goto("https://example.com")
print(page.title())
AsyncCDPServer is the asyncio twin (async with AsyncCDPServer() as server).
server.ws_endpoint is a plain CDP WebSocket, so Node clients connect to it
too: Puppeteer with puppeteer.connect({ browserWSEndpoint }) and Playwright
with chromium.connectOverCDP(...). Pass port= to pin the port, and
args= for lightpanda serve flags such as --cdp-max-connections or
--http-proxy. This is a separate process from Browser (the binary
cannot serve MCP and CDP from the same one). The package itself needs only
Python's standard library; Playwright is a dev-only test dependency and
connect_over_cdp never downloads a browser.
Drive it with Selenium (WebDriver BiDi)
The browser also speaks WebDriver BiDi.
BiDiServer starts lightpanda serve --protocol webdriver and hands you the
URL Selenium's webdriver.Remote takes as command_executor:
from lightpanda import BiDiServer
from selenium import webdriver
from selenium.webdriver.common.options import ArgOptions
options = ArgOptions()
options.web_socket_url = True # ask for a WebDriver BiDi session
with BiDiServer() as server:
driver = webdriver.Remote(command_executor=server.http_endpoint, options=options)
context = driver.browsing_context.create(type="tab")
driver.browsing_context.navigate(context=context, url="https://example.com", wait="complete")
print(driver.script.execute("() => document.title", context_id=context)["value"])
driver.quit()
AsyncBiDiServer is the asyncio twin, and server.bidi_endpoint
(ws://127.0.0.1:<port>/session) is the raw BiDi WebSocket for clients that
speak the protocol directly. The browser serves the BiDi modules plus the
classic session bootstrap Selenium needs, not the classic WebDriver
commands: driver.get, find_element and friends are not implemented, so
drive the page through driver.browsing_context and driver.script with an
explicit context, created first as above. Pass args=["--protocol", "cdp"]
to serve CDP on the same port as well.
How the bindings work
Every browser tool is a Session method, typed and documented in your IDE.
The methods are not written by hand: they are generated from the bundled
browser's MCP tool schemas (scripts/generate_methods.py →
lightpanda/_methods.py), so signatures and docstrings come straight from the
binary, with tool and parameter names in snake_case (waitForSelector →
wait_for_selector, backendNodeId → backend_node_id). Session.call is
the escape hatch that takes the raw tool and parameter names as the MCP
server declares them. The full API reference is published at
lightpanda.io/docs/python.
The bindings follow Lightpanda's development and the package version tracks browser releases — there is no backwards-compatibility guarantee: when the browser's tools change, the Python methods change with them.
Examples
examples/ scrapes a JavaScript-rendered site that requests
cannot read, analyses the result with pandas/matplotlib, and measures the same
job against Selenium + headless Chrome (100 quotes in ~3 s / 35 MB vs ~6 s /
1.2 GB, median of 5 runs). Each script runs standalone: uv run examples/quotes_analysis.py.
License
This client library is Apache-2.0. The bundled Lightpanda browser binary is licensed separately under AGPL-3.0 — see lightpanda-io/browser.
Development
The runtime binary is resolved from LIGHTPANDA_BIN, the package directory,
then PATH. For development, clone
lightpanda-io/browser as a sibling
checkout and build it (zig build) — or point LIGHTPANDA_BIN at any
lightpanda binary. Then:
uv run --group dev pytest tests
The dev group includes playwright and selenium as clients for the CDP
and BiDi tests (their pip packages only; no browser or driver download).
Those tests skip when the client is absent.
Regenerate the tool methods (lightpanda/_methods.py) and the API docs:
uv run --no-project python scripts/generate_methods.py
uv run --no-project --with pdoc python scripts/build_docs.py # writes docs/
Building a wheel
With a binary available (LIGHTPANDA_BIN, or the sibling checkout built
ReleaseFast):
uv build --wheel # -> dist/lightpanda-*-py3-none-<plat>.whl
LIGHTPANDA_PLAT=manylinux_2_35_x86_64 uv build --wheel # CI: tag for the release runner's glibc
The wheel is platform-specific (it carries the binary) but works on every
Python ≥3.10 — hence the py3-none-<plat> tag. Release wheels must bundle a
ReleaseFast binary; a debug build works but is several times larger and
slower.
Releasing
CI (.github/workflows/wheels.yml) builds and tests wheels for all four
platforms on every pull request and push to main, bundling the browser's
nightly release.
Publishing is automatic: when the browser repo builds a version release, its
release workflow (the update-python-package job in
browser's release.yml)
creates the matching release here. That release event starts a wheel run that
builds from that browser release, derives the wheel version from the tag,
tests on all platforms, and publishes to PyPI via trusted publishing — after a
maintainer approves the pypi environment deployment on the run page. A
release can also be triggered by hand: create a GitHub release here whose tag
matches a browser release tag, or use the workflow_dispatch path (any
browser tag, publish to TestPyPI or PyPI) for dry runs.
To ship a packaging or client-side fix without waiting for a new browser
release, create a GitHub release here tagged <browser tag>-N, e.g.
0.4.0-1: it bundles browser 0.4.0 again and publishes as the PEP 440
post-release 0.4.0.post1 (.postN is accepted as the tag too). Bare
pip install lightpanda, >= and ~= requirements pick post-releases up;
an exact ==0.4.0 pin deliberately does not, so pin with ~=0.4.0 to
receive them. The workflow_dispatch path has a matching post input.
The API reference at lightpanda.io/docs/python
is regenerated from the PyPI package by the
docs repo's python-reference workflow,
so a new release shows up there with no step on this side.
Metadata
Release files for lightpanda 0.4.0.post1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| lightpanda-0.4.0.post1-py3-none-manylinux_2_35_x86_64.whl | Python 3 | none | Linux glibc 2.35+ x86-64 | Details |
| lightpanda-0.4.0.post1-py3-none-manylinux_2_35_aarch64.whl | Python 3 | none | Linux glibc 2.35+ ARM64 | Details |
| lightpanda-0.4.0.post1-py3-none-macosx_14_0_arm64.whl | Python 3 | none | macOS 14.0+ ARM64 | Details |
| lightpanda-0.4.0.post1-py3-none-macosx_13_0_x86_64.whl | Python 3 | none | macOS 13.0+ x86-64 | Details |
Total release size: 150.4 MB
Release files / lightpanda-0.4.0.post1-py3-none-manylinux_2_35_x86_64.whl
| Download URL | lightpanda-0.4.0.post1-py3-none-manylinux_2_35_x86_64.whl |
|---|---|
| Size | 48.6 MB |
| Tags | Linux glibc 2.35+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
85c3b43623f62f74f30d4bdb92c2ba21ffe7bc6a1854d0d6ed54b93ebd54b5cb
|
|
BLAKE2b-256 checksum How to use checksums |
bb7b6095be41b8556a3324022dcd55ba33df9d97fefafd7ebaff2446796507d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / lightpanda-0.4.0.post1-py3-none-manylinux_2_35_aarch64.whl
| Download URL | lightpanda-0.4.0.post1-py3-none-manylinux_2_35_aarch64.whl |
|---|---|
| Size | 48.1 MB |
| Tags | Linux glibc 2.35+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
60a54185bdfd640e4a0355caad32b469bac7d65d7f27c28e2a2e762eec6c53ee
|
|
BLAKE2b-256 checksum How to use checksums |
063eef7e467d5afabf7c5f44ef745357c9ddf1a49752bf2948a4a7bfc3dd45d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / lightpanda-0.4.0.post1-py3-none-macosx_14_0_arm64.whl
| Download URL | lightpanda-0.4.0.post1-py3-none-macosx_14_0_arm64.whl |
|---|---|
| Size | 26.1 MB |
| Tags | Python 3 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
dc8f551bfcf50bae9d7ac3cba7a66019aa9cf651f9a65f0ffc36f04701c4a3f4
|
|
BLAKE2b-256 checksum How to use checksums |
0e201ca5d29ae5f14726b5c6bac14fd953ae691d3b83473102a61d94083d2e4e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / lightpanda-0.4.0.post1-py3-none-macosx_13_0_x86_64.whl
| Download URL | lightpanda-0.4.0.post1-py3-none-macosx_13_0_x86_64.whl |
|---|---|
| Size | 27.7 MB |
| Tags | Python 3 macOS 13.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
491cfbee811d6768265bf6e7d9834cd7a5de6512ac965a7a5e9bcf35185bce14
|
|
BLAKE2b-256 checksum How to use checksums |
34b38e611b4ebb761ba12c70eaf52448985c31bfbe807ae15c5d7758957056ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|