http://localhost:39000
Returns the health status of the application, not just HTTP process liveness.
Response (healthy):
{
"status": "ok",
"version": "0.1.0",
"application": "ok"
}Response (unhealthy, HTTP 503):
{
"status": "unhealthy",
"version": "0.1.0",
"application": "unavailable",
"error": "Browser page is closed"
}Returns a service discovery payload with key endpoints and docs hints.
Response (JSON):
{
"success": true,
"data": {
"name": "fuba-browser",
"version": "0.1.0",
"endpoints": {
"health": "/health",
"api": "/api",
"llmsTxt": "/llms.txt",
"docs": {
"index": "/api/docs",
"bundle": "/api/docs/llm",
"single": "/api/docs/{docId}"
}
},
"hints": [
"Use GET /api/docs to list available documentation IDs."
]
}
}Returns API-level discovery info including docs endpoints and curl examples.
Returns plain-text LLM entrypoint hints including /api/docs and /api/docs/llm?format=markdown.
These endpoints fetch markdown docs from the upstream repository and provide them in a format that is easy for LLM ingestion.
Default source base URL: https://raw.githubusercontent.com/fuba/fuba-browser/v<running-version> (derived from DOCS_REF or APP_VERSION or runtime package.json version). You can override with DOCS_BASE_URL.
Returns the list of available documents.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
docs |
string | No | Comma-separated IDs to filter list (e.g. api,cli,usage) |
Response:
{
"success": true,
"data": {
"documents": [
{
"id": "api",
"title": "REST API Reference",
"path": "doc/API.md",
"sourceUrl": "https://raw.githubusercontent.com/fuba/fuba-browser/v2.0.1/doc/API.md"
}
],
"bundleEndpoint": "/api/docs/llm"
}
}Returns one markdown document.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | No | Set markdown to receive text/markdown directly |
Response (JSON):
{
"success": true,
"data": {
"id": "api",
"title": "REST API Reference",
"path": "doc/API.md",
"sourceUrl": "https://raw.githubusercontent.com/fuba/fuba-browser/v2.0.1/doc/API.md",
"markdown": "# Fuba Browser API Documentation...",
"fetchedAt": "2026-02-13T01:20:00.000Z"
}
}Returns a concatenated markdown bundle for LLM context input.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
docs |
string | No | Comma-separated IDs to include (default: all docs) |
format |
string | No | Set markdown to receive text/markdown directly |
Response (JSON):
{
"success": true,
"data": {
"documents": [
{
"id": "api",
"title": "REST API Reference",
"path": "doc/API.md",
"sourceUrl": "https://raw.githubusercontent.com/fuba/fuba-browser/v2.0.1/doc/API.md"
}
],
"markdown": "# Fuba Browser Documentation Bundle...",
"format": "markdown",
"fetchedAt": "2026-02-13T01:20:00.000Z"
}
}Issue a one-time token for noVNC access. The token expires after the configured TTL (default: 5 minutes, configurable via VNC_TOKEN_TTL_SECONDS environment variable).
Each token is issued with a unique dynamic VNC password. This password is automatically added to the x11vnc password file and removed after TTL expiry (default: 10 minutes, configurable via VNC_PASSWORD_TTL_SECONDS). There is no fixed base password — all VNC access requires a dynamic password obtained via this API.
Request Body:
{
"vncHost": "puma2:39101"
}| Field | Type | Required | Description |
|---|---|---|---|
vncHost |
string | No | The host:port for noVNC redirect. When specified, the redirect will use this host directly instead of auto-detecting from request headers. Useful when accessing from an external hostname. |
Response:
{
"success": true,
"data": {
"token": "a1b2c3...hex64chars",
"expiresAt": "2026-02-08T02:35:28.463Z"
}
}Error (503): VNC password manager is not configured (missing VNC_PASSWDFILE).
curl example:
# Without vncHost (uses auto-detected host)
curl -X POST http://localhost:39000/api/web-vnc/token
# With vncHost (for external access)
curl -X POST -H 'Content-Type: application/json' \
-d '{"vncHost":"puma2:39101"}' \
http://localhost:39000/api/web-vnc/tokenConsume a one-time token and redirect to the noVNC web client with auto-connect parameters.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
token |
string | Yes | One-time token from POST /api/web-vnc/token |
Response:
- 302 redirect to
http://<host>:<port>/vnc.html#password=...&autoconnect=1- The
passwordin the URL fragment is the per-token dynamic password. - If the token was issued with
vncHost, the redirect uses that host:port directly. - Otherwise, the host is auto-detected from request headers and the port is set to the configured Web VNC port (
VNC_WEB_PORT, default: 39001).
- The
- 401 if the token is missing, invalid, or already consumed.
- 503 if no VNC password is associated with the token.
Usage flow:
# 1. Issue a token
TOKEN=$(curl -s -X POST -H 'Content-Type: application/json' \
-d '{"vncHost":"puma2:39101"}' \
http://puma2:39100/api/web-vnc/token | jq -r '.data.token')
# 2. Open in browser (one-time use)
open "http://puma2:39100/web-vnc?token=${TOKEN}"Navigate to a specified URL.
Request Body:
{
"url": "https://example.com"
}Response:
{
"success": true,
"data": {
"url": "https://example.com"
}
}Scroll the page to specified coordinates.
Request Body:
{
"x": 0,
"y": 100
}Response:
{
"success": true,
"data": {
"x": 0,
"y": 100
}
}Click an element matching the selector.
Request Body:
{
"selector": "#submit-button"
}Response:
{
"success": true,
"data": {
"selector": "#submit-button"
}
}Type text into an input field.
Request Body:
{
"selector": "input[name='username']",
"text": "john_doe"
}Response:
{
"success": true,
"data": {
"selector": "input[name='username']",
"text": "john_doe"
}
}Capture a screenshot of the current page.
Response:
- Content-Type: image/png
- Binary PNG data
Get page content as extended Markdown format.
Response:
{
"success": true,
"data": {
"html": "<html>...</html>",
"markdown": "# Page Title\n\n...",
"elements": [
{
"tagName": "a",
"selector": "#link-1",
"text": "Click here",
"bbox": {
"x": 10,
"y": 20,
"width": 100,
"height": 30
},
"attributes": {
"id": "link-1",
"href": "/page",
"class": "nav-link"
},
"isVisible": true,
"areaPercentage": 2.5
}
],
"url": "https://example.com",
"title": "Example Domain"
}
}Get all interactive elements on the page.
Response:
{
"success": true,
"data": [
{
"tagName": "button",
"selector": "#submit",
"text": "Submit",
"bbox": {
"x": 100,
"y": 200,
"width": 80,
"height": 40
},
"attributes": {
"id": "submit",
"type": "submit"
},
"isVisible": true,
"areaPercentage": 1.2
}
]
}Get simplified DOM tree information.
Response:
{
"success": true,
"data": {
"url": "https://example.com",
"title": "Example Domain",
"elementsCount": 15,
"elements": [...]
}
}Get all cookies for the current session.
Response:
{
"success": true,
"data": [
{
"name": "session_id",
"value": "abc123",
"domain": ".example.com",
"path": "/",
"expires": 1234567890,
"size": 16,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
}
]
}Set a cookie.
Request Body:
{
"url": "https://example.com",
"name": "user_pref",
"value": "dark_mode"
}Response:
{
"success": true,
"data": {
"url": "https://example.com",
"name": "user_pref",
"value": "dark_mode"
}
}Clear all cookies.
Response:
{
"success": true,
"data": {
"message": "Cookies cleared"
}
}Get current session information.
Response:
{
"success": true,
"data": {
"url": "https://example.com",
"title": "Example Domain",
"cookiesCount": 3
}
}The snapshot API provides accessibility tree-based element identification with ref IDs for fast, deterministic element targeting.
Get page accessibility snapshot with element refs.
Query Parameters:
interactive(boolean): Only include interactive elementscompact(boolean): Remove empty nodesdepth(number): Maximum tree depthselector(string): Scope to a CSS selector
Response:
{
"success": true,
"data": {
"url": "https://example.com",
"title": "Example Domain",
"viewport": { "width": 1200, "height": 2000 },
"timestamp": "2024-01-01T00:00:00.000Z",
"tree": [
{
"ref": "e1",
"role": "link",
"name": "Click here",
"tag": "a",
"selector": "#link-1",
"bbox": { "x": 10, "y": 20, "width": 100, "height": 30 },
"visible": true,
"focusable": true,
"attributes": { "href": "/page" },
"children": []
}
],
"refs": {
"e1": { ... }
}
}
}Perform action using a ref from snapshot.
Request Body:
{
"ref": "@e1",
"action": "click"
}Available actions:
click- Click the elementdblclick- Double-click the elementhover- Hover over the elementfocus- Focus the elementfill- Clear and type text (requiresvalue)type- Type text (requiresvalue)check- Check a checkboxuncheck- Uncheck a checkboxselect- Select an option (requiresvalue)
Response:
{
"success": true,
"data": {
"ref": "@e1",
"action": "click",
"selector": "#link-1"
}
}Clear stored snapshot.
Response:
{
"success": true,
"data": {
"message": "Snapshot cleared"
}
}Hover over an element.
Request Body:
{
"selector": "#menu-item"
}Focus an element.
Request Body:
{
"selector": "input[name='email']"
}Check a checkbox.
Request Body:
{
"selector": "input[type='checkbox']"
}Uncheck a checkbox.
Request Body:
{
"selector": "input[type='checkbox']"
}Select an option in a dropdown.
Request Body:
{
"selector": "select[name='country']",
"value": "JP"
}Wait for various conditions before proceeding.
Wait for an element to appear.
Request Body:
{
"selector": "#loading-complete",
"timeout": 30000
}Response:
{
"success": true,
"data": {
"selector": "#loading-complete",
"found": true
}
}Wait for text to appear on the page.
Request Body:
{
"text": "Success",
"timeout": 30000
}Wait for URL to match a pattern.
Request Body:
{
"pattern": "**/dashboard",
"timeout": 30000
}Wait for page load state.
Request Body:
{
"state": "networkidle"
}Available states:
domcontentloaded- DOM content loaded (default)networkidle- No network activity for 500ms
Wait for a specified duration.
Request Body:
{
"ms": 2000
}Get information about elements and page state.
Get the page title.
Response:
{
"success": true,
"data": {
"title": "Example Domain"
}
}Get the current URL.
Response:
{
"success": true,
"data": {
"url": "https://example.com/page"
}
}Get text content of an element.
Response:
{
"success": true,
"data": {
"selector": "#message",
"text": "Hello World"
}
}Get HTML content of an element.
Response:
{
"success": true,
"data": {
"selector": "#container",
"html": "<div>...</div>"
}
}Get value of an input element.
Response:
{
"success": true,
"data": {
"selector": "#email",
"value": "user@example.com"
}
}Get count of matching elements.
Response:
{
"success": true,
"data": {
"selector": ".item",
"count": 10
}
}Check if an element is visible.
Request Body:
{
"selector": "#modal"
}Response:
{
"success": true,
"data": {
"selector": "#modal",
"visible": true
}
}Check if an element is enabled.
Request Body:
{
"selector": "#submit"
}Check if a checkbox is checked.
Request Body:
{
"selector": "#agree"
}Keyboard and mouse control.
Press a key or key combination.
Request Body:
{
"key": "Enter"
}Examples:
"Enter","Tab","Escape""Control+c","Control+v""Shift+Tab"
Press and hold a key.
Request Body:
{
"key": "Shift"
}Release a key.
Request Body:
{
"key": "Shift"
}Move the mouse to coordinates.
Request Body:
{
"x": 100,
"y": 200
}Press a mouse button.
Request Body:
{
"button": "left"
}Release a mouse button.
Request Body:
{
"button": "left"
}Scroll using mouse wheel.
Request Body:
{
"deltaY": 300,
"deltaX": 0
}Access localStorage and sessionStorage.
Get all localStorage items.
Response:
{
"success": true,
"data": {
"token": "abc123",
"theme": "dark"
}
}Get a specific localStorage item.
Set a localStorage item.
Request Body:
{
"key": "token",
"value": "abc123"
}Clear all localStorage.
Delete a specific localStorage item.
Get all sessionStorage items.
Get a specific sessionStorage item.
Set a sessionStorage item.
Clear all sessionStorage.
Delete a specific sessionStorage item.
Debugging and development tools.
Get console logs.
Response:
{
"success": true,
"data": {
"logs": [
{
"type": "log",
"text": "Page loaded",
"timestamp": "2024-01-01T00:00:00.000Z"
}
]
}
}Clear console logs.
Get JavaScript errors.
Response:
{
"success": true,
"data": {
"errors": [
{
"message": "Uncaught TypeError",
"source": "https://example.com/app.js",
"line": 42,
"timestamp": "2024-01-01T00:00:00.000Z"
}
]
}
}Clear errors.
Execute JavaScript in the page context.
Warning: This is a powerful endpoint by design. It executes arbitrary JavaScript in the currently loaded page context and can access page DOM/state/session data.
Request Body:
{
"script": "document.title"
}Response:
{
"success": true,
"data": {
"result": "Example Domain"
}
}Highlight an element visually.
Request Body:
{
"selector": "#target"
}Inspect recent network requests and export response bodies (including data: URLs).
Returns the in-memory network request log for the current browser session.
Response:
{
"success": true,
"data": {
"entries": [
{
"id": "req-1",
"url": "https://example.com/pixel.png",
"method": "GET",
"resourceType": "image",
"timestamp": "2026-02-23T05:00:00.000Z",
"status": 200,
"statusText": "OK",
"ok": true,
"contentType": "image/png",
"finishedAt": "2026-02-23T05:00:00.120Z"
}
],
"count": 1
}
}Clear the in-memory network request log and cached response handles.
Response:
{
"success": true,
"data": {
"cleared": 12
}
}Returns the response body for a captured request ID.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string | No | binary (default) for raw bytes, or base64 for JSON metadata + base64/data URL |
Response (type=base64):
{
"success": true,
"data": {
"id": "req-1",
"url": "https://example.com/pixel.png",
"contentType": "image/png",
"size": 68,
"base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB...",
"dataUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB..."
}
}Response (type=binary):
- Raw response body bytes with
Content-Typeset to the captured response content type - Includes header
X-Network-Request-Id: <id>
Errors:
404if the request ID is unknown or the response body is no longer available
Save and load browser authentication state (cookies, localStorage, sessionStorage).
Save current browser state.
Response:
{
"success": true,
"data": {
"version": "1.0",
"timestamp": "2024-01-01T00:00:00.000Z",
"url": "https://example.com/dashboard",
"cookies": [...],
"localStorage": { "key1": "value1" },
"sessionStorage": { "key2": "value2" }
}
}Load browser state from saved data.
Request Body:
{
"state": { ... },
"navigateToUrl": true
}Options:
navigateToUrl(boolean): Navigate to the saved URL after loading state
Response:
{
"success": true,
"data": {
"message": "State loaded successfully",
"cookiesCount": 5,
"localStorageCount": 3,
"sessionStorageCount": 1,
"url": "https://example.com/dashboard"
}
}Get current state info without full data.
Response:
{
"success": true,
"data": {
"url": "https://example.com/dashboard",
"cookiesCount": 5,
"localStorageCount": 3,
"sessionStorageCount": 1,
"timestamp": "2024-01-01T00:00:00.000Z"
}
}System-level operations for browser management.
Restart the browser process. This completely resets the browser state including all pages, cookies, storage, and memory.
Request Body: (none required)
Response:
{
"success": true,
"message": "Browser has been reset"
}Error Response:
{
"success": false,
"error": "Reset failed"
}Use Cases:
- Browser becomes unresponsive
- Memory usage grows too high
- Need a completely clean state
- After long automation sessions
CLI Usage:
fbb resetIntercept, track, and retrieve files downloaded by the browser.
Uses a "wait before click" pattern: call POST /api/download/wait before triggering the download action, ensuring no race condition.
Wait for the next browser download to complete (long-polling).
Request Body:
{
"timeout": 60000
}| Field | Type | Required | Description |
|---|---|---|---|
timeout |
number | No | Timeout in milliseconds (default: 60000, max: 300000) |
Response:
{
"success": true,
"data": {
"id": "dl-1",
"url": "https://example.com/file.zip",
"suggestedFilename": "file.zip",
"status": "completed",
"startedAt": "2026-03-21T00:00:00.000Z",
"completedAt": "2026-03-21T00:00:05.000Z"
}
}List all tracked downloads.
Response:
{
"success": true,
"data": {
"entries": [
{
"id": "dl-1",
"url": "https://example.com/file.zip",
"suggestedFilename": "file.zip",
"status": "completed",
"startedAt": "2026-03-21T00:00:00.000Z",
"completedAt": "2026-03-21T00:00:05.000Z"
}
],
"count": 1
}
}Get download metadata by ID.
Response:
{
"success": true,
"data": {
"id": "dl-1",
"url": "https://example.com/file.zip",
"suggestedFilename": "file.zip",
"status": "completed",
"startedAt": "2026-03-21T00:00:00.000Z",
"completedAt": "2026-03-21T00:00:05.000Z"
}
}Get downloaded file content as binary.
Response:
- Raw file bytes with
Content-Type: application/octet-stream - Includes headers:
X-Download-Id: <id>X-Suggested-Filename: <url-encoded filename>Content-Disposition: attachment; filename="<url-encoded filename>"
Errors:
404if the download ID is not found500if the download is not yet completed
Clear download history and delete temp files.
Response:
{
"success": true,
"data": {
"cleared": 3
}
}All endpoints return error responses in the following format:
{
"success": false,
"error": "Error message describing what went wrong"
}Common HTTP status codes:
- 400: Bad Request (missing required parameters)
- 500: Internal Server Error