This document specifies the complete ABP REST API. The following table shows current implementation status:
| Category | Implemented | Planned |
|---|---|---|
| Tab Management | list, create, close, get, activate, stop | pin, mute, duplicate, move |
| Navigation | navigate, back, forward, reload | - |
| Mouse | click, move, scroll | drag, hover, mouse down/up |
| Keyboard | type, press, down, up | shortcut, insert |
| Screenshots | viewport (GET/POST), markup, cursor | full-page, region |
| JavaScript | execute | - |
| Text | get text (full page or selector) | - |
| Dialogs | get, accept, dismiss | - |
| Downloads | list, get, cancel | configure, wait, resume |
| File Chooser | provide files | configure, get pending |
| Popups | select picker | - |
| Browser | status, shutdown | get info |
| Execution Control | get/set state | - |
| History | sessions, actions, events, export | - |
| Network | query, save, clear, browser_curl | intercept |
| Window | - | bounds, state |
| Cookies | - | get, set, clear |
| Wait | duration wait | navigation, network idle |
| MCP | 30 tools via /mcp endpoint | - |
Features marked "Planned" are documented below but not yet implemented.
http://localhost:8222/api/v1
Not Yet Implemented
If --abp-auth-token is set, all requests must include:
Authorization: Bearer <token>
All action endpoints (POST/DELETE that modify state) accept standard parameters:
{
"action_params": { ... },
"wait_until": {
"type": "action_complete",
"timeout_ms": 30000
},
"screenshot": {
"area": "viewport",
"disable_markup": ["grid"],
"cursor": true
},
"network": {
"tag": "login-flow",
"types": ["XHR", "Fetch"]
}
}Control screenshot capture and element markup in the response.
| Value | Description |
|---|---|
none |
No screenshot returned |
viewport |
Capture visible viewport (default) |
All markup overlays are enabled by default. Use disable_markup to turn off specific ones.
| Tag | Description |
|---|---|
clickable |
Buttons, links, and other clickable elements (green outline, 2px) |
typeable |
Text inputs, textareas, contenteditable elements (orange outline, 2px) |
scrollable |
Elements with scrollable overflow content (purple dashed outline, 2px) |
grid |
100px coordinate grid overlay with pixel coordinate labels (red) |
selected |
The currently focused element (blue outline, 3px) |
Markup appearance:
- Each marked element gets a colored bounding box matching its tag
- Element index labels are drawn for reference
- All 5 overlays are enabled by default; use
disable_markupto turn off specific ones - Boxes are semi-transparent to not obscure content
Control virtual cursor visibility in screenshots. The virtual cursor is automatically positioned by input actions (click, scroll, move) and rendered at the compositor layer.
| Value | Description |
|---|---|
true |
Include virtual cursor in screenshot (default) |
false |
Hide virtual cursor for screenshot capture |
Example request with markup and cursor:
{
"x": 100,
"y": 200,
"wait_until": {"type": "action_complete"},
"screenshot": {
"area": "viewport",
"disable_markup": ["grid", "scrollable"],
"cursor": true
}
}| Type | Description |
|---|---|
immediate |
Return immediately after dispatching the action |
action_complete |
Wait for engine rendering/navigation lull after action (default) |
time |
Wait for a fixed duration specified by duration_ms |
{
"wait_until": {
"type": "action_complete",
"timeout_ms": 30000,
"duration_ms": 1000
}
}| Parameter | Type | Default | Description |
|---|---|---|---|
type |
string | action_complete |
Wait condition type |
timeout_ms |
number | 30000 | Maximum time to wait before returning |
duration_ms |
number | - | Fixed wait for time type |
The action_complete type uses engine-level signals to detect completion:
- Rendering quiescence: No pending paint/layout operations
- Navigation settled: No pending navigations or redirects
- Script idle: No pending JavaScript tasks or promises
- Minimum delay: Configurable minimum wait (default: 100ms) after last activity
All action responses include before and after screenshots, scroll position, and event log:
{
"result": { ... },
"screenshot_before": {
"data": "base64-encoded-image",
"width": 1920,
"height": 1080,
"virtual_time_ms": 1699999999000,
"format": "webp"
},
"screenshot_after": {
"data": "base64-encoded-image",
"width": 1920,
"height": 1080,
"virtual_time_ms": 1699999999999,
"format": "webp"
},
"scroll": {
"horizontal_percent": 0,
"vertical_percent": 25.5,
"horizontal_px": 0,
"vertical_px": 1200,
"page_width": 1920,
"page_height": 4700,
"viewport_width": 1920,
"viewport_height": 1080
},
"events": [
{
"type": "navigation",
"virtual_time_ms": 1699999999100,
"data": { ... }
}
],
"timing": {
"action_started_ms": 1699999999000,
"action_completed_ms": 1699999999050,
"wait_completed_ms": 1699999999500,
"duration_ms": 500
},
"network": {
"total": 12,
"completed": 10,
"pending": 2,
"tag": "login-flow"
}
}The network field is included in the response when a network object was present in the request.
| Field | Type | Description |
|---|---|---|
total |
number | Total network requests observed during the action |
completed |
number | Requests that received a response |
pending |
number | Requests still in-flight at action completion |
tag |
string | The tag under which calls were saved, or "" if not saved |
Both screenshot_before and screenshot_after share the same format:
| Field | Type | Description |
|---|---|---|
data |
string | Base64-encoded image |
width |
number | Image width in pixels |
height |
number | Image height in pixels |
virtual_time_ms |
number | Virtual time when screenshot was captured (ms since epoch) |
format |
string | Image format (default webp) |
screenshot_beforeis captured just before the action executes, reflecting the page state the agent sees.screenshot_afteris captured after the action completes and wait conditions are met.- Both screenshots include all element markup overlays by default. Use
screenshot.disable_markupto turn off specific overlays. - In MCP responses, both screenshots are returned as separate image content blocks (before first, then after).
The scroll object provides current scroll state after wait completion:
| Field | Type | Description |
|---|---|---|
horizontal_percent |
number | Horizontal scroll position as percentage (0-100) |
vertical_percent |
number | Vertical scroll position as percentage (0-100) |
horizontal_px |
number | Horizontal scroll offset in pixels |
vertical_px |
number | Vertical scroll offset in pixels |
page_width |
number | Total scrollable page width in pixels |
page_height |
number | Total scrollable page height in pixels |
viewport_width |
number | Visible viewport width in pixels |
viewport_height |
number | Visible viewport height in pixels |
Events are captured between action dispatch and wait completion:
Tab navigated to a new URL.
{
"type": "navigation",
"virtual_time_ms": 1699999999100,
"data": {
"tab_id": "tab_abc123",
"url": "https://example.com/page",
"navigation_type": "link_click"
}
}navigation_type values: link_click, form_submit, redirect, back_forward, reload
Browser dialog appeared (alert, confirm, prompt).
{
"type": "dialog",
"virtual_time_ms": 1699999999200,
"data": {
"tab_id": "tab_abc123",
"dialog_type": "confirm",
"message": "Are you sure you want to delete?",
"default_prompt": "",
"pending": true
}
}dialog_type values: alert, confirm, prompt, beforeunload
Native file picker dialog appeared. Use the id to provide files via POST /file-chooser/{id}.
{
"type": "file_chooser",
"virtual_time_ms": 1699999999300,
"data": {
"id": "fc_abc123",
"tab_id": "tab_abc123",
"chooser_type": "open",
"accepts": [{"description": "Images", "extensions": ["jpg", "png"]}],
"multiple": false,
"pending": true
}
}chooser_type values: open, open_multiple, save
New popup window or tab opened.
{
"type": "popup",
"virtual_time_ms": 1699999999400,
"data": {
"source_tab_id": "tab_abc123",
"new_tab_id": "tab_xyz789",
"url": "https://example.com/popup",
"popup_type": "window"
}
}popup_type values: window, tab
Tab was closed.
{
"type": "tab_closed",
"virtual_time_ms": 1699999999500,
"data": {
"tab_id": "tab_abc123",
"reason": "script"
}
}reason values: script, user, navigation
Page was scrolled.
{
"type": "scroll",
"virtual_time_ms": 1699999999550,
"data": {
"tab_id": "tab_abc123",
"delta": {
"x": 0,
"y": 300,
"direction": "down"
},
"position": {
"horizontal_percent": 0,
"vertical_percent": 45.2,
"horizontal_px": 0,
"vertical_px": 2100
},
"source": "wheel"
}
}delta.direction values: up, down, left, right
source values: wheel, keyboard, script, drag
Download was initiated.
{
"type": "download_started",
"virtual_time_ms": 1699999999600,
"data": {
"download_id": "dl_123",
"url": "https://example.com/file.pdf",
"filename": "file.pdf",
"mime_type": "application/pdf",
"total_bytes": 102400
}
}Download finished successfully.
{
"type": "download_completed",
"virtual_time_ms": 1699999999900,
"data": {
"download_id": "dl_123",
"path": "/downloads/file.pdf",
"filename": "file.pdf",
"bytes_received": 102400,
"mime_type": "application/pdf"
}
}Files were selected in a file chooser dialog.
{
"type": "file_selected",
"virtual_time_ms": 1699999999700,
"data": {
"id": "fc_abc123",
"tab_id": "tab_abc123",
"chooser_type": "open",
"files": ["/path/to/document.pdf", "/path/to/image.png"]
}
}For save dialogs:
{
"type": "file_selected",
"virtual_time_ms": 1699999999700,
"data": {
"id": "fc_abc123",
"tab_id": "tab_abc123",
"chooser_type": "save",
"path": "/path/to/output.pdf"
}
}File chooser was dismissed without selection.
{
"type": "file_chooser_cancelled",
"virtual_time_ms": 1699999999800,
"data": {
"id": "fc_abc123",
"tab_id": "tab_abc123",
"chooser_type": "open"
}
}A native <select> dropdown popup was intercepted. Use the id to respond via POST /select/{id}.
{
"type": "select_open",
"virtual_time_ms": 1699999999850,
"data": {
"id": "sp_abc123",
"tab_id": "tab_abc123",
"multiple": false,
"options": [
{"index": 0, "label": "Option A", "selected": true},
{"index": 1, "label": "Option B", "selected": false},
{"index": 2, "label": "Option C", "selected": false}
],
"pending": true
}
}Control screenshot capture via the screenshot object in the request body:
{
"screenshot": {
"area": "viewport",
"disable_markup": ["grid"],
"cursor": true
}
}| Field | Type | Default | Description |
|---|---|---|---|
area |
string | viewport |
Capture area: none, viewport |
disable_markup |
string[] | [] |
Markup tags to disable (all enabled by default): clickable, typeable, scrollable, grid, selected |
cursor |
boolean | true |
Include virtual cursor in screenshot |
Format: All screenshots are returned as WebP at quality 80. This is not configurable to ensure consistent bandwidth usage and simplify caching.
Optionally capture network traffic that occurs during an action. Captured calls are returned in the network summary field of the response and, when a tag is provided, are saved to the SQLite history database.
{
"network": {
"tag": "login-flow",
"types": ["XHR", "Fetch"]
}
}| Field | Type | Default | Description |
|---|---|---|---|
tag |
string | "" |
Tag used to save captured calls to the database. If omitted, calls are counted but not persisted. |
types |
string[] | all types | Network request types to capture. Values: XHR, Fetch, Document, Stylesheet, Image, Media, Font, Script, TextTrack, EventSource, WebSocket, Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other |
GET endpoints return data directly without the action envelope (no screenshot/events):
{ ... }For tab listing, the response is a bare JSON array. Other list endpoints (e.g., downloads) wrap results in an object.
{
"error": "Human readable error message"
}HTTP status codes indicate error type:
400- Bad request (invalid parameters)404- Resource not found (tab, download, etc.)500- Internal server error
GET /browser/status
Returns initialization status. Poll this endpoint to wait for ABP to be ready after browser launch.
Response (initializing):
{
"success": true,
"data": {
"ready": false,
"state": "initializing",
"components": {
"http_server": true,
"browser_window": false,
"devtools": false
},
"message": "Waiting for browser window"
}
}Response (ready):
{
"success": true,
"data": {
"ready": true,
"state": "ready",
"components": {
"http_server": true,
"browser_window": true,
"devtools": true
}
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Always true for this endpoint |
data.ready |
boolean | true when ABP is fully initialized and ready to accept commands |
data.state |
string | Current state: initializing, ready |
data.components.http_server |
boolean | HTTP server is listening |
data.components.browser_window |
boolean | Browser window is created and active |
data.components.devtools |
boolean | DevTools connection is established |
data.message |
string | Human-readable status message (present when not ready) |
Polling example:
# Wait for browser to be ready (bash)
while true; do
response=$(curl -s http://localhost:8222/api/v1/browser/status)
ready=$(echo "$response" | jq -r '.data.ready')
if [ "$ready" = "true" ]; then
echo "Browser ready"
break
fi
sleep 0.5
donePOST /browser/shutdown
Gracefully shuts down the browser.
Request:
{
"timeout_ms": 5000
}GET /browser/session-data
Returns file paths for the current session's data storage (database, screenshots directory).
Response:
{
"success": true,
"data": {
"session_dir": "/tmp/abp-abc123",
"database_path": "/tmp/abp-abc123/history.db",
"screenshots_dir": "/tmp/abp-abc123/screenshots",
"screenshots_enabled": false
}
}GET /browser/input-mode
Returns the current global input mode.
Response:
{
"input_mode": "agent"
}POST /browser/input-mode
Toggles between agent-controlled and human-controlled input modes.
"human": Aborts in-flight actions, saves execution state, resumes page, allows system input, blocks ABP action-loop operations, shows yellow gradient border."agent": Blocks system input, restores saved execution state (re-pauses if was paused), unblocks ABP operations, hides border.
Request:
{
"input_mode": "human"
}Response:
{
"input_mode": "human"
}Blocked operations in human mode: All action-loop operations (click, type, scroll, keyboard, execute, wait, screenshot POST, dialog accept/dismiss, permission grant/deny, file chooser, select), navigation (navigate, reload, back, forward), and POST /execution. Read-only endpoints (GET screenshot, text, tabs, status, dialog, downloads, permissions, history) remain available.
GET /tabs
Returns all open tabs as an array.
Response:
[
{
"id": "tab_abc123",
"url": "https://example.com",
"title": "Example Domain",
"active": true
}
]GET /tabs/{tab_id}
Returns detailed information about a specific tab.
Response:
{
"id": "tab_abc123",
"url": "https://example.com",
"title": "Example Domain",
"loading": false
}POST /tabs
Creates a new tab.
Request:
{
"url": "https://example.com",
"active": true,
"index": 0
}All fields optional. Defaults to blank tab at end, made active.
Response (201 Created):
{
"id": "tab_xyz789",
"url": "about:blank"
}DELETE /tabs/{tab_id}
Closes the specified tab.
Response:
{}POST /tabs/{tab_id}/activate
Switches to the specified tab.
Response:
{
"status": "activated",
"tab_id": "tab_xyz789",
"index": 0
}POST /tabs/{tab_id}/navigate
Request:
{
"url": "https://example.com",
"referrer": "https://google.com",
"wait_until": {
"type": "action_complete",
"timeout_ms": 30000
}
}Response:
{
"result": {
"status": "navigated",
"url": "https://example.com"
},
"screenshot_before": {
"data": "UklGRlYAAABXRUJQVlA4I...",
"width": 1920,
"height": 1080,
"virtual_time_ms": 1699999999000,
"format": "webp"
},
"screenshot_after": {
"data": "UklGRlYAAABXRUJQVlA4I...",
"width": 1920,
"height": 1080,
"virtual_time_ms": 1699999999500,
"format": "webp"
},
"scroll": {
"horizontal_percent": 0,
"vertical_percent": 0,
"horizontal_px": 0,
"vertical_px": 0,
"page_width": 1920,
"page_height": 1080,
"viewport_width": 1920,
"viewport_height": 1080
},
"events": [
{
"type": "navigation",
"virtual_time_ms": 1699999999100,
"data": {
"tab_id": "tab_abc123",
"url": "https://example.com"
}
}
],
"timing": {
"action_started_ms": 1699999999000,
"action_completed_ms": 1699999999100,
"wait_completed_ms": 1699999999500,
"duration_ms": 500
}
}POST /tabs/{tab_id}/back
Request:
{
"wait_until": {
"type": "action_complete",
"timeout_ms": 30000
}
}Returns 400 if there is no back history.
POST /tabs/{tab_id}/forward
Request:
{
"wait_until": {
"type": "action_complete",
"timeout_ms": 30000
}
}Returns 400 if there is no forward history.
POST /tabs/{tab_id}/reload
Reloads the page. Always uses normal reload (not cache-bypassing).
Request:
{
"wait_until": {
"type": "action_complete",
"timeout_ms": 30000
}
}POST /tabs/{tab_id}/stop
Response:
{
"status": "stopped",
"tab_id": "tab_abc123"
}POST /tabs/{tab_id}/click
Performs a mouse click at the specified coordinates.
Request:
{
"x": 100,
"y": 200,
"button": "left",
"click_count": 1,
"modifiers": [],
"wait_until": {
"type": "action_complete",
"timeout_ms": 5000
}
}button options: "left", "right", "middle"
modifiers options: "Shift", "Control", "Alt", "Meta" (also accepts left/right variants like "ShiftLeft", "ControlRight")
click_count: 1 for single click, 2 for double click, 3 for triple click
Response (example showing dialog triggered by click):
{
"result": {
"status": "clicked"
},
"screenshot_before": {
"data": "UklGRlYAAABXRUJQVlA4I...",
"width": 1920,
"height": 1080,
"virtual_time_ms": 1699999999000,
"format": "webp"
},
"screenshot_after": {
"data": "UklGRlYAAABXRUJQVlA4I...",
"width": 1920,
"height": 1080,
"virtual_time_ms": 1699999999500,
"format": "webp"
},
"scroll": {
"horizontal_percent": 0,
"vertical_percent": 25.5,
"horizontal_px": 0,
"vertical_px": 1200,
"page_width": 1920,
"page_height": 4700,
"viewport_width": 1920,
"viewport_height": 1080
},
"events": [
{
"type": "dialog",
"virtual_time_ms": 1699999999200,
"data": {
"tab_id": "tab_abc123",
"dialog_type": "confirm",
"message": "Delete this item?",
"pending": true
}
}
],
"timing": {
"action_started_ms": 1699999999000,
"action_completed_ms": 1699999999050,
"wait_completed_ms": 1699999999500,
"duration_ms": 500
}
}POST /tabs/{tab_id}/move
Moves mouse to coordinates (single move, no interpolation).
Request:
{
"x": 100,
"y": 200
}POST /tabs/{tab_id}/scroll
Scrolls the page using native mouse wheel events at the specified coordinates. Simulates a real user moving their mouse over an element and scrolling with the mouse wheel.
Request:
{
"x": 100,
"y": 200,
"delta_x": 0,
"delta_y": -300
}Parameters:
x(required): X coordinate of the element center to scroll. The mouse wheel event fires at this position.y(required): Y coordinate of the element center to scroll. The mouse wheel event fires at this position.delta_x(optional): Horizontal scroll amount in pixels. Positive = scroll right, negative = scroll left. Default: 0.delta_y(optional): Vertical scroll amount in pixels. Negative = scroll up, positive = scroll down. Default: 0.
At least one of delta_x or delta_y must be non-zero.
Note: Unlike keyboard-based scrolling (PageUp/PageDown), mouse wheel scrolling occurs at a specific coordinate, allowing scrolling of specific scrollable elements (overflow divs, iframes, etc.) by targeting their center point.
POST /tabs/{tab_id}/type
Types text as if entered by user. Generates keydown, char, and keyup events with a fixed 2ms delay between keystrokes.
Request:
{
"text": "Hello, World!"
}Response: Standard action envelope with result containing the typed text.
POST /tabs/{tab_id}/keyboard/press
Presses a key or key combination (keydown + keyup for all keys). Supports keyboard shortcuts via modifiers array.
Request:
{
"key": "Enter",
"modifiers": []
}Shortcut examples:
// Copy (Ctrl+C)
{"key": "c", "modifiers": ["Control"]}
// Paste (Ctrl+V)
{"key": "v", "modifiers": ["Control"]}
// Select All (Ctrl+A)
{"key": "a", "modifiers": ["Control"]}
// Undo (Ctrl+Z)
{"key": "z", "modifiers": ["Control"]}
// Redo (Ctrl+Shift+Z)
{"key": "z", "modifiers": ["Control", "Shift"]}
// Save (Ctrl+S)
{"key": "s", "modifiers": ["Control"]}
// Find (Ctrl+F)
{"key": "f", "modifiers": ["Control"]}
// Close tab (Ctrl+W)
{"key": "w", "modifiers": ["Control"]}
// New tab (Ctrl+T)
{"key": "t", "modifiers": ["Control"]}modifiers options: "Shift", "Control", "Alt", "Meta"
Common key values:
- Letters:
"a"-"z","A"-"Z" - Numbers:
"0"-"9" - Function keys:
"F1"-"F12" - Navigation:
"ArrowUp","ArrowDown","ArrowLeft","ArrowRight" - Editing:
"Backspace","Delete","Enter","Tab","Escape" - Whitespace:
"Space" - Special:
"Home","End","PageUp","PageDown","Insert"
POST /tabs/{tab_id}/keyboard/down
Presses key without releasing.
Request:
{
"key": "Shift",
"modifiers": []
}POST /tabs/{tab_id}/keyboard/up
Releases a pressed key.
Request:
{
"key": "Shift"
}POST /tabs/{tab_id}/execute
Execute JavaScript in the page context and retrieve results.
Request:
{
"script": "document.querySelectorAll('a').length"
}| Parameter | Type | Default | Description |
|---|---|---|---|
script |
string | required | JavaScript expression to evaluate |
Note: The MCP tool browser_execute_javascript uses expression as the parameter name and maps it to script internally.
Response:
{
"result": {
"value": 42,
"type": "number"
}
}Supported return types:
- Primitives:
string,number,boolean,null,undefined - Objects: Serialized as JSON (must be JSON-serializable)
- Arrays: Serialized as JSON array
- Promises: Resolved value returned (if
await_promiseis true)
Example expressions:
// Get page data
"document.title"
"window.location.href"
"document.body.innerText.length"
// Query counts
"document.querySelectorAll('button').length"
"document.forms.length"
// Check state
"document.readyState"
"window.scrollY"
// Extract data
"JSON.stringify(Array.from(document.querySelectorAll('h1')).map(h => h.textContent))"
// Application state
"window.APP_STATE?.user?.isLoggedIn ?? false"All screenshots are returned as WebP format at quality 80.
GET /tabs/{tab_id}/screenshot
Query params:
disable_markup=grid,scrollable- Comma-separated markup tags to disable (all enabled by default):clickable,typeable,scrollable,grid,selected
Response: Binary WebP image data with Content-Type: image/webp header.
POST /tabs/{tab_id}/screenshot
Uses the standard action envelope. Screenshots are returned in screenshot_before and screenshot_after fields.
Request:
{
"screenshot": {
"disable_markup": ["grid"],
"format": "webp",
"cursor": true
}
}Response: Standard action envelope with screenshot data in screenshot_before/screenshot_after.
POST /tabs/{tab_id}/text
Extracts text content from the page or a specific element.
Request:
{
"selector": ".main-content"
}| Parameter | Type | Required | Description |
|---|---|---|---|
selector |
string | No | CSS selector to extract text from. If omitted, returns document.body.innerText |
Response:
{
"text": "The extracted text content..."
}Returns {"text": null} if the selector matches no element.
POST /tabs/{tab_id}/wait
Waits for a specified duration. Uses the action envelope, so the page resumes execution during the wait and is paused again afterward.
Request:
{
"ms": 2000
}| Parameter | Type | Required | Description |
|---|---|---|---|
ms |
integer | Yes | Duration to wait in milliseconds (0-60000) |
Response: Standard action envelope with:
{
"result": {
"status": "waited",
"ms": 2000
}
}GET /tabs/{tab_id}/dialog
Response (dialog present):
{
"present": true,
"dialog_type": "confirm",
"message": "Are you sure you want to delete this item?",
"default_prompt": ""
}Response (no dialog):
{
"present": false
}POST /tabs/{tab_id}/dialog/accept
Request:
{
"prompt_text": "User input for prompt dialogs"
}Response:
{
"success": true
}POST /tabs/{tab_id}/dialog/dismiss
Response:
{
"success": true
}Downloads are configured via ABP config at launch (download path, auto-accept behavior). The API provides read-only access to download status.
GET /downloads
Query params:
state=in_progress- Filter by state:in_progress,completed,cancelled,failedlimit=100- Max entries
Response:
{
"downloads": [
{
"id": "dl_123",
"url": "https://example.com/file.pdf",
"filename": "file.pdf",
"path": "/downloads/file.pdf",
"state": "completed",
"bytes_received": 102400,
"total_bytes": 102400,
"mime_type": "application/pdf",
"start_time": 1699999999000,
"end_time": 1699999999500
}
]
}GET /downloads/{download_id}
Returns status information about a specific download.
Response:
{
"id": "dl_123",
"url": "https://example.com/file.pdf",
"filename": "file.pdf",
"path": "/downloads/file.pdf",
"state": "in_progress",
"bytes_received": 51200,
"total_bytes": 102400,
"percent_complete": 50,
"mime_type": "application/pdf",
"start_time": 1699999999000
}POST /downloads/{download_id}/cancel
Cancels an in-progress download.
Response:
{
"success": true,
"message": "Download cancelled"
}File chooser dialogs (triggered by clicking file inputs or save buttons) emit events with unique IDs. Use the file chooser endpoint to provide files to a pending dialog.
When an action triggers a file chooser, the response includes a file_chooser event:
{
"events": [
{
"type": "file_chooser",
"virtual_time_ms": 1699999999200,
"data": {
"id": "fc_abc123",
"tab_id": "tab_xyz789",
"chooser_type": "open",
"accepts": [
{"description": "Images", "extensions": ["jpg", "png", "gif"]},
{"description": "All Files", "extensions": ["*"]}
],
"multiple": false,
"pending": true
}
}
]
}chooser_type values: "open", "open_multiple", "save"
POST /file-chooser/{chooser_id}
Provides files to a pending file chooser dialog.
Request (for open dialogs):
{
"files": [
"/path/to/document.pdf",
"/path/to/image.png"
]
}Request (for save dialogs):
{
"path": "/path/to/save/output.pdf"
}Request (to cancel/dismiss):
{
"cancel": true
}Response (files provided):
{
"success": true
}Response (cancelled):
{
"success": true,
"cancelled": true
}Error (chooser not found or expired):
{
"error": "File chooser fc_abc123 not found or already closed"
}Native OS <select> dropdowns are intercepted at the Mojo IPC boundary before the native UI is shown. Agents discover pending popups via select_open events in action response events arrays.
POST /select/{popup_id}
Responds to a pending <select> dropdown popup by selecting options or cancelling.
Request (select options by index):
{
"indices": [1]
}For <select multiple>, provide multiple indices:
{
"indices": [0, 2, 3]
}Request (cancel/dismiss):
{
"cancel": true
}Response:
{
"success": true
}Error (popup not found or expired):
{
"error": "Select popup sp_abc123 not found or already closed"
}Network capture records HTTP requests and responses made by the tab during agent actions. Calls are buffered in memory per-tab and can be queried or saved to the SQLite history database with a tag for later retrieval.
GET /network
Returns saved network calls matching the given filters. All filter parameters (except include_body) are treated as substring regex patterns.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
tag |
string | Filter by save tag (regex) |
tab_id |
string | Filter by tab ID (regex) |
url |
string | Filter by full URL (regex) |
hostname |
string | Filter by hostname (regex) |
path |
string | Filter by URL path (regex) |
query |
string | Filter by URL query string (regex) |
method |
string | Filter by HTTP method, e.g. GET, POST (regex) |
status |
string | Filter by HTTP status code, e.g. 200, 4\d\d (regex) |
type |
string | Filter by request type, e.g. XHR, Fetch (regex) |
action_id |
string | Filter by action ID (regex) |
include_body |
boolean | Include request/response bodies in results (default: false) |
Response:
{
"calls": [
{
"id": "net_abc123",
"tag": "login-flow",
"tab_id": "tab_abc123",
"action_id": "act_xyz789",
"url": "https://api.example.com/login",
"method": "POST",
"status": 200,
"type": "Fetch",
"request_headers": {"content-type": "application/json"},
"response_headers": {"content-type": "application/json"},
"request_body": "{\"user\":\"alice\"}",
"response_body": "{\"token\":\"...\"}",
"timing_ms": 124,
"timestamp_ms": 1699999999200
}
],
"total": 1
}When include_body is false, request_body and response_body are omitted from each call object.
POST /network/save
Retroactively tags and persists the current in-memory network buffer to the SQLite database. Useful when you did not specify a tag in the action request and want to save the captured calls after the fact.
Request:
{
"tag": "login-flow",
"tab_id": "tab_abc123"
}| Parameter | Type | Required | Description |
|---|---|---|---|
tag |
string | Yes | Tag to assign to the saved calls |
tab_id |
string | No | Tab whose buffer to save. Defaults to the currently active tab. |
Response:
{
"saved": 12,
"tag": "login-flow"
}| Field | Type | Description |
|---|---|---|
saved |
number | Number of network calls written to the database |
tag |
string | The tag assigned to the saved calls |
DELETE /network
Clears saved network calls from the database. Pass tag to clear only calls with that tag, or omit to clear all saved calls.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
tag |
string | Tag to clear (omit to clear all) |
Response:
{
"deleted": 42
}POST /tabs/{tab_id}/curl
Executes an HTTP request from within the tab's session context, using its current cookies and credentials. Works even while JavaScript execution is paused. Useful for calling APIs that require authenticated sessions without needing to extract cookies manually.
Request:
{
"url": "https://api.example.com/users",
"method": "GET",
"headers": {"Authorization": "Bearer eyJ..."},
"body": "",
"tag": "api-call"
}| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | URL to request |
method |
string | No | HTTP method (default: GET) |
headers |
object | No | Additional request headers (key/value strings) |
body |
string | No | Request body |
tag |
string | No | Tag under which to save this call in the database |
Response:
{
"status": 200,
"headers": {"content-type": "application/json"},
"body": "{\"users\":[...]}",
"body_encoding": "text",
"url": "https://api.example.com/users",
"redirected": false
}| Field | Type | Description |
|---|---|---|
status |
number | HTTP response status code |
headers |
object | Response headers (key/value strings) |
body |
string | Response body. Text responses are returned as-is; binary responses are base64-encoded. |
body_encoding |
string | "text" for UTF-8 text, "base64" for binary responses |
url |
string | Final URL after any redirects |
redirected |
boolean | true if the request was redirected |
Example — fetch user profile using tab session:
curl -X POST http://localhost:8222/api/v1/tabs/tab_abc123/curl \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/api/profile", "method": "GET"}'Session and action history is stored in a SQLite database within the session directory. All history endpoints are under /api/v1/history/.
GET /history/sessions
Returns all recorded sessions.
GET /history/sessions/current
Returns the currently active session.
GET /history/sessions/{session_id}
Returns details for a specific session.
GET /history/sessions/{session_id}/export
Exports a session with all its actions and events.
GET /history/actions
Returns recorded actions. Supports query filtering.
GET /history/actions/{action_id}
Returns details for a specific action.
GET /history/actions/{action_id}/screenshot
Returns the screenshot associated with an action as binary image data.
DELETE /history/actions
Deletes action history records.
GET /history/events
Returns recorded events.
GET /history/events/{event_id}
Returns details for a specific event.
DELETE /history/events
Deletes event history records.
DELETE /history
Deletes all history (sessions, actions, and events).
Control JavaScript execution and virtual time for deterministic page state between agent actions. When enabled, the page is completely frozen (no JS execution, no timers) between actions.
GET /tabs/{tab_id}/execution
Returns the current execution control state for a tab.
Response:
{
"enabled": true,
"paused": true,
"virtual_time_base_ms": 1700000000000.0
}| Field | Type | Description |
|---|---|---|
enabled |
boolean | Whether execution control is enabled for this tab |
paused |
boolean | Whether JS execution is currently paused |
virtual_time_base_ms |
number | Virtual time base in milliseconds since epoch |
POST /tabs/{tab_id}/execution
Enable execution control and/or pause/resume JavaScript execution.
Request:
{
"paused": true,
"initial_virtual_time": 1700000000.0
}| Parameter | Type | Required | Description |
|---|---|---|---|
paused |
boolean | Yes | true to pause, false to resume |
initial_virtual_time |
number | No | Initial virtual time in seconds since Unix epoch (only used when first enabling) |
Response:
{
"enabled": true,
"paused": true,
"virtual_time_base_ms": 1700000000000.0
}Execution control uses two CDP mechanisms:
- Debugger.pause/resume - Halts/resumes all JavaScript execution
- Emulation.setVirtualTimePolicy - Freezes/advances timers, Date.now(), and animations
By default (unless --abp-disable-pause is set):
- Actions (click, type, navigate) automatically resume execution before dispatching
- After the action completes, execution is paused before taking screenshots
- Screenshots capture a completely frozen page state
Action Flow:
Agent sends click action
→ ABP resumes JS (Debugger.resume + virtual time advance)
→ Takes before screenshot (page state before action)
→ Dispatches click event
→ Waits for action to complete
→ Takes after screenshot (page state after action)
→ Pauses JS (virtual time pause + Debugger.pause)
→ Returns response with both screenshots
Execution control is enabled by default when using ABP. To disable it:
./chrome --enable-abp --abp-disable-pauseWith --abp-disable-pause, actions do not pause/resume execution - they behave without freezing the page.
- Deterministic testing: Ensure identical page state between test runs
- AI agent reliability: Freeze timers/animations while agent processes screenshot
- Debugging: Stop page execution to inspect state
| Code | Description |
|---|---|
INVALID_REQUEST |
Malformed request body |
TAB_NOT_FOUND |
Tab ID does not exist |
ELEMENT_NOT_FOUND |
Element ID does not exist or is stale |
SELECTOR_NOT_FOUND |
No element matches selector |
TIMEOUT |
Operation timed out |
NAVIGATION_FAILED |
Navigation could not complete |
ELEMENT_NOT_VISIBLE |
Element exists but is not visible |
ELEMENT_NOT_INTERACTABLE |
Element cannot receive input |
DIALOG_NOT_PRESENT |
No dialog to accept/dismiss |
FILE_CHOOSER_NOT_PRESENT |
No file chooser dialog to handle |
FILE_NOT_FOUND |
Specified file path does not exist |
FILE_NOT_READABLE |
File exists but cannot be read |
DOWNLOAD_NOT_FOUND |
Download ID does not exist |
DOWNLOAD_FAILED |
Download could not complete |
NETWORK_ERROR |
Network operation failed |
EVALUATION_ERROR |
JavaScript evaluation failed |
UNAUTHORIZED |
Missing or invalid auth token |
RATE_LIMITED |
Too many requests |
NOT_READY |
ABP is still initializing, poll /browser/status |
BROWSER_INIT_FAILED |
Browser window failed to initialize |
DEVTOOLS_INIT_FAILED |
DevTools connection failed to establish |