Headless Browser
Introduction
The Headless Browser tool gives the agent a real browser. It can navigate to a URL, wait for JavaScript to render, return the page as markdown or a semantic tree, click elements, fill forms, and run JS in the page context. Built on top of ferdiunal/larapanda, which wraps Lightpanda — a lightweight headless browser written in Zig.
If all you need is plain HTTP, Web Request is enough. Reach for the browser when the page is a SPA, hides content behind cookie walls, or only fills in after a network request lands.
It's disabled by default.
Requirements
The tool depends on two things that don't ship with laraclaw:
- The
ferdiunal/larapandaComposer package - A Lightpanda runtime — either the native CLI binary or Docker
The wizard can install both for you, or you can install them yourself and just point the wizard at them.
!IMPORTANT Larapanda v1.0 requires PHP 8.5. Laraclaw itself runs on PHP 8.4, so if you're still on 8.4 you'll need to upgrade before you can enable the browser tool.
Enabling the Browser
Run the wizard:
php artisan laraclaw:setup-browser
It walks two opt-in prompts:
- Install
ferdiunal/larapandanow via composer? If yes, the wizard runscomposer require ferdiunal/larapandafor you and streams the output. Composer regenerates the autoloader on disk but the running PHP process keeps its in-memory classmap, so the wizard exits after install and asks you to re-run it. - Install the Lightpanda binary now via the official install script? If yes, it pipes
https://pkg.lightpanda.io/install.shtobashand then prefills the path prompt with the most likely install location (/usr/local/bin/lightpanda,~/.lightpanda/bin/lightpanda, or~/.local/bin/lightpanda).
Both prompts default to no, so nothing is installed unless you explicitly say yes. If you'd rather install them yourself:
composer require ferdiunal/larapanda
curl -fsSL https://pkg.lightpanda.io/install.sh | bash
Leave the binary path blank and Larapanda falls back to running Lightpanda in Docker via the lightpanda/browser:nightly image. Useful for containerized setups where you don't want a binary on the host.
The wizard writes:
LARACLAW_BROWSER_ENABLED=true
LARAPANDA_RUNTIME=auto
LARAPANDA_BINARY_PATH=/usr/local/bin/lightpanda
LARAPANDA_RUNTIME=auto lets Larapanda prefer the CLI binary when it's present and fall back to Docker otherwise.
What the Agent Gets
When enabled, the entire Lightpanda tool catalog from Larapanda is registered with the agent, prefixed lightpanda_. The most common ones:
| Tool | What it does |
|---|---|
lightpanda_goto | Navigate to a URL and load it into session memory |
lightpanda_markdown | Return the current page as markdown |
lightpanda_semantic_tree | Return a simplified DOM tree suitable for reasoning |
lightpanda_interactiveElements | List clickable / focusable nodes with backend IDs |
lightpanda_click | Click an element by its backendNodeId |
lightpanda_fill | Fill a form input by backendNodeId |
lightpanda_waitForSelector | Wait for a CSS selector to appear |
lightpanda_evaluate | Run JavaScript in the page context |
lightpanda_links | Extract every link from the current page |
lightpanda_structuredData | Pull JSON-LD and OpenGraph metadata |
Tools are session-aware. The agent passes a session_id to keep page state across calls — for example, goto then click then markdown all on the same session.
To restrict which tools the agent sees, publish the larapanda config and set integrations.ai.exposed_tools:
php artisan vendor:publish --tag=larapanda-config
// config/larapanda.php
'integrations' => [
'ai' => [
'exposed_tools' => ['goto', 'markdown', 'semantic_tree'],
],
],
Runtime Modes
Larapanda resolves at request time based on LARAPANDA_RUNTIME:
auto— prefer the binary atLARAPANDA_BINARY_PATHwhen it's executable; otherwise fall back to Docker. This is what the wizard sets.cli— require the binary. Faster cold start. Fails if the binary is missing.docker— always run insidelightpanda/browser:nightly. No binary needed, but each session pays the container start cost.
Security Considerations
!NOTE The browser can fetch any URL the host machine can reach. There is no internal-network blocklist, unlike Web Request which guards against private IPs. Treat it as the agent having outbound HTTP from your server.
- Sessions live in memory. The default TTL is 5 minutes (
LARAPANDA_AI_SESSION_TTL); set it lower if you're paranoid about leftover page state between conversations. - JavaScript runs in the headless context. Pages can read cookies and local storage of the session they're in, but those are scoped per Lightpanda process, not your app.
obey_robotsis on by default. Larapanda will refuse to navigate to URLs disallowed byrobots.txt. Toggle withLARAPANDA_AI_OBEY_ROBOTS=falseif you're scraping with permission.- Enable
LARACLAW_LOG_AGENT_REQUESTS=trueto keep an audit trail of every fetch.