Skip to Content
ReferencePython SDK

Python SDK

The lightpanda package exposes Browser/AsyncBrowser, which spawn and manage the bundled binary, and Session/AsyncSession, with one method per browser action. See Use the Python SDK for practical documentation.

Browser

Browser() spawns the bundled binary when constructed. It is not fork-inheritable: create a fresh instance in a forked child.

ArgumentDefaultDescription
binaryNonePath to a specific lightpanda binary. When omitted, resolved from the LIGHTPANDA_BIN environment variable, then the binary bundled in the package, then PATH.
envNoneExtra environment variables for the spawned process.
timeout300.0Seconds to wait for a response before raising ProtocolError.
verboseFalsePrint the spawned process’s own logging.
args()Extra CLI flags for the spawned process, for example ["--http-cache-dir", path].
MethodReturnsDescription
new_session()SessionOpen a new isolated browsing context: its own page, cookies, and memory.
tools (property)dict[str, dict]Every available action, as name → {description, schema}, reported live by the running browser.
close()NoneStop the browser process.

with Browser() as b: calls close() on exit.

AsyncBrowser

AsyncBrowser mirrors Browser for asyncio: every call runs on a browser-owned thread pool, so the event loop is never blocked.

ArgumentDefaultDescription
binary, env, timeout, verbose, argssame as BrowserForwarded to the underlying Browser.
max_concurrency32Caps method calls executing concurrently across this browser’s sessions. Worker threads are created lazily.
MethodReturnsDescription
start()AsyncBrowserSpawn the process and fetch its action list. Idempotent; called automatically on async with entry and by new_session().
new_session()AsyncSessionStart the browser if needed, then open a new session.
session()async context managerasync with browser.session() as page: opens a session scoped to the block and closes it on exit.
tools (property)dict[str, dict]Same as Browser.tools.
close()NoneStop the browser process, unless it was adopted with wrap (see below).
AsyncBrowser.wrap(browser, max_concurrency=32) (classmethod)AsyncBrowserAdopt an already-running Browser for use from asyncio. close() then shuts down only the async facade, leaving the wrapped browser running.

async with AsyncBrowser() as b: calls start() on entry and close() on exit.

Session and AsyncSession

Browser.new_session() and AsyncBrowser.new_session() are the only way to obtain a Session or AsyncSession; do not construct one directly.

MemberDescription
id (property)The session’s id.
close()Close the session. Calls made after close() raise ToolError.
call(action, **kwargs)Invoke any action by name. The methods documented below route through this.

Sessions are context managers too: with browser.new_session() as page: closes the session on exit. Closing the browser ends every session anyway.

Calling an action

Every browser action is a method on Session/AsyncSession, keyword-only. The original action name (waitForSelector) and a snake_case alias (wait_for_selector) both resolve to the same method: call whichever reads better in your code.

⚠️

Only the method name gets a snake_case alias; its keyword arguments keep their original names. wait_for_selector(selector=..., timeout=...) has no case change, but click(selector=..., backendNodeId=...), screenshot(fullPage=...), and tree(maxDepth=...) all keep a camelCase keyword even though the method itself is snake_case.

A failed action raises ToolError.

In the Arguments column below, ? marks an optional keyword argument, and selector / backendNodeId marks a pair where one of the two is required. Prefer selector for reproducibility; it also wins when you pass both. backendNodeId values come from a prior tree, links, or find_element call. In the Returns column, JSON is a parsed Python dict or list, text is a plain string.

These methods bring a page into the browser:

MethodArgumentsReturnsDescription
gotourl, timeout?, waitUntil?textNavigate to a URL and load the page in memory so it can be reused later for info extraction. waitUntil accepts the same states as wait_for_state and defaults to load. On the 0.4.0 wheel, waitUntil isn’t yet a keyword; reach it with page.call("goto", url=..., waitUntil=...) until the next release.
searchquery, timeout?textRun a web search and return results as markdown: a numbered list of {title, url, snippet}. The browser does not navigate; to open a result, call goto with its URL.

Reading the page

These methods read the loaded page without modifying it:

MethodArgumentsReturnsDescription
markdownselector?, backendNodeId?, maxBytes?, url?, timeout?textRender the page, or a subtree, as markdown. Scope with selector or backendNodeId to read just the relevant region; use maxBytes to cap long pages.
htmlselector?, backendNodeId?, maxBytes?, strip?, url?, timeout?textRaw HTML for the document, or a single node’s outerHTML when scoped. Verbose; use only when you need attributes that markdown discards. Use maxBytes to cap long pages. strip is an object of element groups to omit: js (script, noscript, script preloads), css (style, stylesheet links), ui (css plus img, picture, video, audio, svg, canvas, iframe) and invisible (elements set to display:none). {"js": True, "css": True} keeps a page dump small. On the 0.4.0 wheel, maxBytes and strip aren’t yet keywords; reach them with page.call("html", maxBytes=..., strip=...) until the next release.
screenshotpath?, selector?, backendNodeId?, fullPage?, url?, timeout?text or bytesRender the page, or one node, as a PNG: the text layout Lightpanda computes, not a pixel-accurate rendering (no images, fonts, or CSS colors). path must be a relative path. In the 0.4.0 wheel, the Python SDK doesn’t request an inline image, so without path you get a plain size summary, not the image itself; always pass path for now. A later release is expected to return the image as bytes when path is omitted.
treeurl?, timeout?, backendNodeId?, maxDepth?textSimplified semantic DOM tree: role, name, value, and backendNodeId per node.
linkslimit?, url?, timeout?JSONExtract all links as text (visible anchor text, falling back to aria-label/title/image alt), href (resolved URL), and backendNodeId (pass to node_details). One entry per href; hidden links are omitted. limit returns at most that many links, in document order. On the 0.4.0 wheel, limit isn’t yet a keyword; reach it with page.call("links", limit=...) until the next release.
node_details (nodeDetails)backendNodeIdJSONTag, role, name, value, and other state for a node, plus a ready-to-use CSS selector that resolves to it. The way to turn a backendNodeId into a selector.
find_element (findElement)role?, name?JSONFind interactive elements by role and/or accessible name, with their backendNodeId.
interactive_elements (interactiveElements)url?, timeout?JSONEvery interactive element on the page.
structured_data (structuredData)url?, timeout?JSONStructured data on the page, such as JSON-LD or OpenGraph tags.
detect_forms (detectForms)url?, timeout?JSONForms on the page: fields, types, and required status.

Data extraction and scripting

MethodArgumentsReturnsDescription
extractschema, save?JSONExtract structured data from the current page using a schema mapping output field names to CSS-selector specs.
evaluatescript, url?, timeout?, save?typedEvaluate a JavaScript string in the page context and return its value. Runs in the page, so it cannot see your Python variables.

evaluate’s return is typed like the JavaScript result: for example 1+1 comes back as the int 2, and ({a:1}) comes back as the dict {"a": 1}.

extract’s schema maps output field names to CSS-selector specs. Pass it as a Python dict or list, it’s encoded for you; a JSON string also works:

Schema valueResult
"<sel>"First match’s text, or None
["<sel>"]Every match’s text
{"selector": "<sel>", "attr": "<name>"}First match’s attribute (href/src resolve to absolute URLs)
[{"selector": "<sel>", "attr": "<name>"}]Every match’s attribute
[{"selector": "<sel>", "fields": {...}}]One dict per match, with fields resolved relative to each match

Add "limit": N inside any array spec to cap matches. Every extracted value is a string or None; parse numbers yourself.

Interacting with the page

These methods dispatch real DOM events on the page:

MethodArgumentsReturnsDescription
clickselector / backendNodeIdtextClick an interactive element.
fillselector / backendNodeId, valuetextFill text into an input element.
scrollbackendNodeId?, x?, y?textScroll the page, or a specific element if backendNodeId is given.
hoverselector / backendNodeIdtextHover over an element, triggering mouseover and mouseenter.
presskey, selector?, backendNodeId?textPress a keyboard key, dispatching keydown and keyup. Targets the document if no element is given.
select_option (selectOption)selector / backendNodeId, valuetextSelect an option in a <select> element by its value.
set_checked (setChecked)selector / backendNodeId, checkedtextCheck (True) or uncheck (False) a checkbox or radio button. Dispatches input, change, and click events.

Waiting

These methods block until the page reaches a condition:

MethodArgumentsReturnsDescription
wait_for_selector (waitForSelector)selector, timeout?textWait for an element matching a CSS selector to appear, and return its backendNodeId.
wait_for_script (waitForScript)script, timeout?textWait until a JavaScript expression returns truthy, re-evaluated on every tick.
wait_for_state (waitForState)state, timeout?textWait for the page to reach a load state (load, domcontentloaded, networkalmostidle, networkidle, or done), with no navigation.

State and debugging

MethodArgumentsReturnsDescription
get_url (getUrl)nonetextThe URL currently loaded in the session.
get_cookies (getCookies)url?, all?textCookies stored in the browser. Defaults to the current page’s host; pass url for another host or all=True for every cookie.
get_env (getEnv)name?textWith name, read one LP_* environment variable. Without it, list the LP_* names that are set.
console_logs (consoleLogs)nonetextBuffered console.log/warn/error messages since the last call, which then clears the buffer.

Script replay

run_script and run_script_async (its awaitable variant, run in a worker thread) replay a saved PandaScript with no LLM call, by running lightpanda run <script> and returning its stdout. Installing the package also puts the lightpanda binary itself on PATH.

from lightpanda import run_script run_script("hn.js", env={"LP_HN_USERNAME": "me"})
ArgumentDefaultDescription
scriptrequiredPath to the script file.
envNoneExtra environment variables for the child process, for example LP_* placeholder values the script reads.
binaryNoneSame resolution as Browser’s binary argument.
timeoutNoneSeconds to wait for the process to exit.

A non-zero exit raises ScriptError. Exceeding timeout raises subprocess.TimeoutExpired instead.

Errors

ErrorRaised when
LightpandaErrorBase class for every error the package raises.
ProtocolErrorThe connection to the browser process failed: a malformed request, a timeout, or an internal error. Carries a code attribute.
ToolErrorA browser action reported failure, such as a bad selector, a JS exception inside evaluate, or a call on a closed session.
ScriptErrorrun_script or run_script_async exited with a non-zero status, or the script file doesn’t exist (returncode=-1). Carries returncode, stdout, and stderr attributes.