Browser Automation
Drive a real browser programmatically: step-based automation, persistent sessions, action recording, lazy-load / network capture, WebSocket and Server-Sent Events scraping, and screenshots.
What it automates
| Capability | Details |
|---|---|
| Step-based automation | navigate, click, type, extract, wait, screenshot, scroll, submit, … |
| Persistent sessions | Create/save/restore/destroy browser sessions with cookies + storage |
| Action recording | Record browser actions into a reusable Playwright script |
| Capture | Lazy-load/infinite-scroll detection, network API-call extraction |
| Streaming | WebSocket + SSE data capture |
| Screenshots | Full-page screenshots as base64 PNG |
Endpoints
Routers: routers/automation.py (Automation), routers/sessions.py
(Sessions), routers/recorder.py (Recorder), routers/scraping.py +
routers/scraping_api.py (Capture), routers/advanced.py (WS/SSE)
| Method | Path | Summary |
|---|---|---|
| POST | /v1/automate | Execute browser automation steps (steps, session_id, headless, viewport) |
| POST | /v1/screenshot | Screenshot a URL → base64 PNG |
| POST | /v1/session/create | Create a persistent session (url, persist default true) |
| POST | /v1/session/destroy | Destroy a session (save_state optional) |
| GET | /v1/sessions | List active + saved sessions |
| POST | /v1/session/save | Save current session state (cookies, storage) to disk |
| POST | /v1/session/restore | Restore a saved session into a browser context |
| POST | /v1/record/start | Start recording browser actions |
| POST | /v1/record/step | Record one action step (action, selector, value) |
| POST | /v1/record/export | Export recording as a script (fmt default json) |
| POST | /v1/record/clear | Clear recorded actions |
| POST | /v1/capture/lazy | Detect lazy loading / infinite scroll, generate scroll scripts |
| POST | /v1/capture/network | Extract API calls, GraphQL queries, JSON-LD, Next.js/Nuxt state |
| POST | /v1/ws/scrape | Capture a WebSocket data stream (url, max_messages, message_filter) |
| POST | /v1/sse/scrape | Capture Server-Sent Events (url, max_events, event_filter) |
POST /v1/automate
Request body (AutomateRequest):
| Field | Type | Default | Description |
|---|---|---|---|
session_id | string | — | Reuse an existing browser session |
steps | array | — | Required. Ordered list of steps |
headless | boolean | true | Run headless |
viewport | object | — | {width, height} override |
Step schema: action (required), selector, value, url, timeout
(default 30000 ms), wait_until (default networkidle).
Example — login flow:
curl -X POST http://localhost:8005/v1/automate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{
"steps": [
{"action": "navigate", "url": "https://login.example.com"},
{"action": "type", "selector": "#username", "value": "user"},
{"action": "type", "selector": "#password", "value": "pass"},
{"action": "click", "selector": "#login-btn"},
{"action": "extract", "selectors": {"title": "h1"}}
]
}'
Response (200): the extracted data from the final step, e.g.
{ "title": "Welcome, user" }.
Sessions
# Create a persistent session
curl -X POST http://localhost:8005/v1/session/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"url": "https://example.com", "persist": true}'
# → { "success": true, "data": { "session_id": "sess_abc123", "persist": true } }
# Reuse it in automation
curl -X POST http://localhost:8005/v1/automate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{
"session_id": "sess_abc123",
"steps": [{"action": "navigate", "url": "https://example.com"}]
}'
Saved sessions are stored in the sessions volume (/app/sessions in Docker,
~/.pry/sessions on bare metal) and survive restarts.
Recording
curl -X POST http://localhost:8005/v1/record/start \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"session_id": "sess_abc123"}'
curl -X POST http://localhost:8005/v1/record/step \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"session_id": "sess_abc123", "action": "click", "selector": "#checkout"}'
curl -X POST http://localhost:8005/v1/record/export \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"session_id": "sess_abc123", "fmt": "json"}'
Capture
# Lazy-load / infinite scroll detection + generated scroll script
curl -X POST http://localhost:8005/v1/capture/lazy \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"url": "https://app.example.com/feed", "auto_scroll": true, "max_scrolls": 5}'
# Network capture — find the hidden APIs a SPA calls
curl -X POST http://localhost:8005/v1/capture/network \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"url": "https://app.example.com"}'
Response (/v1/capture/network):
{
"success": true,
"data": {
"url": "https://app.example.com",
"api_calls": ["https://api.example.com/v1/products"],
"graphql_queries": ["query Products { products { id name } }"],
"json_ld": [{"@type": "Product"}],
"nextjs_props": true,
"nuxt_state": false
}
}
WebSocket / SSE
# Capture WebSocket messages
curl -X POST http://localhost:8005/v1/ws/scrape \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"url": "wss://stream.example.com/trades", "max_messages": 100, "timeout": 30}'
# Capture Server-Sent Events
curl -X POST http://localhost:8005/v1/sse/scrape \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"url": "https://stream.example.com/events", "max_events": 50, "timeout": 30}'
Screenshots
curl -X POST http://localhost:8005/v1/screenshot \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <key>" \
-d '{"url": "https://example.com"}'
Response (200):
{
"success": true,
"data": {
"screenshot": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
}
}
MCP tools
| Tool | Backing endpoint |
|---|---|
pry_screenshot | POST /v1/screenshot |
For deeper automation from agents, compose pry_scrape (with
bypassCloudflare) + pry_extract on rendered content.
Who uses this
- Login-gated scraping — automate sign-in once, reuse the session for data extraction.
- E2E QA — scripted flows with screenshots for visual verification.
- SPA / hidden-API discovery —
capture/networkto find the JSON APIs behind a JavaScript app, then scrape those directly. - Real-time data —
ws/scrape/sse/scrapefor live feeds (trades, notifications, events). - Workflow automation — record actions once, export as Playwright scripts, run in CI.
Next steps
- Stealth & Anti-Detection — how browsers stay undetected
- Document Parsing — parse what the browser renders
- Automation API — full endpoint reference incl. TLS impersonation and Camoufox
- x402 Pay-per-call —
automateandcaptureare priced operations