{"id":"32909c6b-1548-4d16-8f6d-ab4512db3918","entityType":"agent","slug":"clawhub-vasyaod-remote-browser","name":"Remote Browser Service","canonicalUrl":"https://www.xpersona.co/agent/clawhub-vasyaod-remote-browser","canonicalPath":"/agent/clawhub-vasyaod-remote-browser","generatedAt":"2026-10-11T04:33:35.467Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T02:17:20.486Z","emptyReason":null},"description":"Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t... Skill: Remote Browser Service Owner: vasyaod Summary: Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t... Tags: latest:1.0.9 Version history: v1.0.9 | 2026-06-30T00:05:59.956Z | user Add session 'description' metadata field (PUT + list 'descriptions' map); clarify CDP/VNC session lifecycle — closing a connecti","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.2K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s1734nk0kj9x904ddtmczp26ah83nvwh:remote-browser","sourceUrl":"https://clawhub.ai/vasyaod/remote-browser","homepage":"https://clawhub.ai/vasyaod/skills/remote-browser","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/vasyaod/remote-browser","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/vasyaod/skills/remote-browser","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":62,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T02:17:20.486Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T02:17:20.486Z","emptyReason":null},"stars":null,"forks":null,"downloads":1192,"packageName":null,"latestVersion":"1.0.9","tractionLabel":"1.2K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T02:17:20.412Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T02:17:20.486Z","lastCrawledAt":"2026-10-11T02:17:20.412Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T02:17:20.412Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.9","createdAt":"2026-06-30T00:05:59.956Z","changelog":"Add session 'description' metadata field (PUT + list 'descriptions' map); clarify CDP/VNC session lifecycle — closing a connection does not close the session (kept alive until 5-min idle or explicit terminate).","fileCount":3,"zipByteSize":11346},{"version":"1.0.8","createdAt":"2026-06-23T22:05:28.712Z","changelog":"Payment-card request_fill field kinds (card-holder-name/number/cvv/exp/billing) with per-field format spec; select-aware fill for dropdowns; WebSocket subprotocol auth for browser clients.","fileCount":3,"zipByteSize":10913},{"version":"1.0.5","createdAt":"2026-06-18T09:50:34.680Z","changelog":"Clarify request-fill IS the service's own secure credential prompt ('Keeper'), not OpenClaw secrets/SecretRefs. Default to it for any login; on no_keeper, have the user sign in via live VNC; never ask for a pasted password.","fileCount":3,"zipByteSize":10426},{"version":"1.0.4","createdAt":"2026-06-18T09:31:06.842Z","changelog":"Sync to single source of truth (primary skill in main repo). No functional change.","fileCount":3,"zipByteSize":10149},{"version":"1.0.3","createdAt":"2026-06-18T09:11:52.684Z","changelog":"Whole-profile persistence: sessions reopen logged in (incl. apps that store auth in IndexedDB/Service Workers, e.g. Telegram). Connecting/disconnecting (incl. CDP/Playwright) no longer ends a session; DELETE wipes all persisted state.","fileCount":3,"zipByteSize":10105},{"version":"1.0.2","createdAt":"2026-06-16T08:30:53.212Z","changelog":"Sync with remote-browser-service@1.0.4: 'submit' action; token-efficiency decision ladder; 5 MiB CDP frame (markup over screenshots); selector clicks use DOM element.click(); session status section; sessions reopen automatically with same session_id (encrypted included).","fileCount":3,"zipByteSize":9085},{"version":"1.0.1","createdAt":"2026-05-08T22:32:52.890Z","changelog":"Reword description and tips to clarify legitimate-use framing for moderation; no behavioral changes.","fileCount":3,"zipByteSize":6310},{"version":"1.0.0","createdAt":"2026-05-08T20:10:51.836Z","changelog":"Initial publish of the Remote Browser skill under the remote-browser slug.","fileCount":2,"zipByteSize":5035}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s1734nk0kj9x904ddtmczp26ah83nvwh:remote-browser","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T04:33:35.464Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-vasyaod-remote-browser/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T02:17:20.486Z","emptyReason":null},"readme":"Skill: Remote Browser Service\n\nOwner: vasyaod\n\nSummary: Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t...\n\nTags: latest:1.0.9\n\nVersion history:\n\nv1.0.9 | 2026-06-30T00:05:59.956Z | user\n\nAdd session 'description' metadata field (PUT + list 'descriptions' map); clarify CDP/VNC session lifecycle — closing a connection does not close the session (kept alive until 5-min idle or explicit terminate).\n\nv1.0.8 | 2026-06-23T22:05:28.712Z | user\n\nPayment-card request_fill field kinds (card-holder-name/number/cvv/exp/billing) with per-field format spec; select-aware fill for dropdowns; WebSocket subprotocol auth for browser clients.\n\nv1.0.5 | 2026-06-18T09:50:34.680Z | user\n\nClarify request-fill IS the service's own secure credential prompt ('Keeper'), not OpenClaw secrets/SecretRefs. Default to it for any login; on no_keeper, have the user sign in via live VNC; never ask for a pasted password.\n\nv1.0.4 | 2026-06-18T09:31:06.842Z | user\n\nSync to single source of truth (primary skill in main repo). No functional change.\n\nv1.0.3 | 2026-06-18T09:11:52.684Z | user\n\nWhole-profile persistence: sessions reopen logged in (incl. apps that store auth in IndexedDB/Service Workers, e.g. Telegram). Connecting/disconnecting (incl. CDP/Playwright) no longer ends a session; DELETE wipes all persisted state.\n\nv1.0.2 | 2026-06-16T08:30:53.212Z | user\n\nSync with remote-browser-service@1.0.4: 'submit' action; token-efficiency decision ladder; 5 MiB CDP frame (markup over screenshots); selector clicks use DOM element.click(); session status section; sessions reopen automatically with same session_id (encrypted included).\n\nv1.0.1 | 2026-05-08T22:32:52.890Z | user\n\nReword description and tips to clarify legitimate-use framing for moderation; no behavioral changes.\n\nv1.0.0 | 2026-05-08T20:10:51.836Z | user\n\nInitial publish of the Remote Browser skill under the remote-browser slug.\n\nArchive index:\n\nArchive v1.0.9: 3 files, 11346 bytes\n\nFiles: skill-card.md (2281b), SKILL.md (27843b), _meta.json (133b)\n\nFile v1.0.9:SKILL.md\n\n---\nname: remote-browser-service\ndescription: >\n  Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation,\n  form filling, navigation, and page inspection on sites the user owns or has permission to access.\n  Exposes the accessibility tree, text extraction, Chrome screenshots, VNC-native screenshots,\n  DOM actions, and VNC actions — optimized for AI agents. Requires an active browser session\n  (created via HTTP or WebSocket).\nmetadata:\n  openclaw:\n    emoji: \"🌐\"\n    requires:\n      env:\n        - name: AC_API_KEY\n          secret: true\n          optional: true\n          description: \"Bearer token or API key for auth (user_id derived from token)\"\n---\n\n# Remote Browser Service\n\nBrowser control for AI agents via HTTP API. Supports both DOM-oriented automation\nand remote-desktop/VNC control when you need the actual framebuffer.\n\n## Index\n\n- [Setup](#setup)\n- [Core Workflow](#core-workflow)\n- [API Reference](#api-reference)\n- [Screenshot](#screenshot)\n- [VNC interface](#vnc-interface)\n- [VNC screenshot](#vnc-screenshot)\n- [Act on elements](#act-on-elements)\n- [VNC action](#vnc-action)\n- [HTML snapshot](#html-snapshot)\n- [Token Cost Guide](#token-cost-guide)\n- [Limitations & fallbacks](#limitations--fallbacks)\n- [Environment Variables](#environment-variables)\n- [Tips](#tips)\n\n## Setup\n\nEnsure you have an active session:\n\n1. **Create session** — `POST /api/sessions` (HTTP, no WebSocket), or open WebSocket to `/ws/{session_id}` (DevTools CDP), or run from UI. Optional `url` in body (HTTP) or query (WS) to navigate immediately.\n2. **Or restore** — Use stored session from `GET /api/stored-sessions`\n3. **Auth** — Pass `Authorization: Bearer <token>` or `X-API-Key`, or `?access_token=<token>`\n\nBase URL: `https://rb.all-completed.com` (or `RBS_BASE_URL`). Replace `{session_id}` in examples. User ID is derived from the token.\n\n## Core Workflow\n\n1. **Navigate** to a URL\n2. **Snapshot** the accessibility tree (get refs) — `GET .../json`\n3. **Act** on refs or selectors (click, type, fill, press)\n4. **Snapshot** again to see results\n\nFor visual or OS-level flows, use the VNC path instead:\n\n1. **Open VNC interface** — `GET /users/{user_id}/vnc/{session_id}` when you want a live noVNC view\n2. **Capture VNC framebuffer** — `GET .../vnc/screenshot`\n3. **Send VNC input** — `POST .../vnc/action` with coordinates or keys\n4. **Capture again** to verify pixel-level results\n\nRefs (`e0`, `e1`, …) from `/json` can be used with `/action` via `selector` (use `ref` as selector for `e5` → `\"e5\"` maps to role/name; for now use CSS `selector`).\n\nSupported actions by mode:\n\n| Mode               | Kind     | Example                                                     |\n|--------------------|----------|-------------------------------------------------------------|\n| DOM (`/action`)    | `click`  | `{\"kind\":\"click\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `tap`    | `{\"kind\":\"tap\",\"selector\":\"button.submit\"}`                 |\n| DOM (`/action`)    | `type`   | `{\"kind\":\"type\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `fill`   | `{\"kind\":\"fill\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `press`  | `{\"kind\":\"press\",\"key\":\"Enter\"}`                            |\n| DOM (`/action`)    | `focus`  | `{\"kind\":\"focus\",\"selector\":\"input[name=search]\"}`          |\n| DOM (`/action`)    | `hover`  | `{\"kind\":\"hover\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `select` | `{\"kind\":\"select\",\"selector\":\"select\",\"value\":\"option-1\"}`  |\n| DOM (`/action`)    | `scroll` | `{\"kind\":\"scroll\",\"scrollY\":800}`                           |\n| DOM (`/action`)    | `submit` | `{\"kind\":\"submit\",\"selector\":\"#nav-search-form\"}` (or a field within the form) |\n| Secrets (`/request-fill`) | — | `{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}` — user fills it in the Keeper app; value never seen by the agent |\n| VNC (`/vnc/action`) | `move`   | `{\"kind\":\"move\",\"x\":320,\"y\":240}`                           |\n| VNC (`/vnc/action`) | `click`  | `{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}` |\n| VNC (`/vnc/action`) | `type`   | `{\"kind\":\"type\",\"text\":\"hello world\"}`                      |\n| VNC (`/vnc/action`) | `press`  | `{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}`                      |\n| VNC (`/vnc/action`) | `scroll` | `{\"kind\":\"scroll\",\"x\":320,\"y\":240,\"direction\":\"down\",\"repeat\":3}` |\n\n## API Reference\n\n### Create session (HTTP)\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n# Optional: {\"session_id\": \"my-session\", \"url\": \"https://example.com\"}\n# Fork from stored session: {\"session_id\": \"my-fork\", \"from\": \"original-session\"}\n# Ephemeral (start from metadata/fork but don't save): {\"ephemeral\": true}\n```\n\n**Session lifecycle — closing a connection does NOT close the session.** Persistent\nsessions live until a **5-minute idle timeout** or an **explicit terminate**, not when\nyour CDP/VNC connection drops:\n\n- **CDP (`/ws`)**: while connected the pod is pinned (`active_ws_connections > 0`, never\n  reaped). On disconnect it is **kept alive** and the 5-min idle clock restarts — so a\n  reconnecting client (e.g. Playwright `connectOverCDP`, which connects/disconnects a lot)\n  doesn't churn the pod. Only `ephemeral` sessions are deleted immediately on last disconnect.\n- **VNC (`/vnc/ws`)**: same as CDP — while a viewer streams the session is pinned\n  (`active_ws_connections > 0`), so it isn't reaped mid-view; on disconnect the pod is kept and\n  the idle clock restarts.\n- **Activity that restarts the 5-min clock**: opening a CDP/VNC connection, `GET .../status`,\n  `GET .../{session_id}`, and `POST .../ping`.\n- **To close immediately** instead of waiting out the idle timeout: `DELETE /api/sessions/{session_id}`\n  (or `terminate_session`). On teardown the profile is saved.\n\nMaximum 1 concurrent session per user. If creation returns 429 or WebSocket closes with a limit error: **wait a bit** (previous session may still be shutting down) **and/or close the previous session** via `DELETE /api/sessions/{session_id}` before retrying.\n\n### List sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n### Session status\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns live session state plus current page metadata:\n\n```json\n{\n  \"session_id\": \"session-123\",\n  \"created_at\": \"2026-02-12T10:00:00\",\n  \"active_ws_connections\": 1,\n  \"status\": \"ready\",\n  \"last_error\": null,\n  \"current_url\": \"https://example.com/page\",\n  \"page_title\": \"Example Domain\",\n  \"last_status_code\": 200\n}\n```\n\nHTTP status codes:\n\n- `200` - Session found; manager status returned, with live page metadata when available\n- `404` - Session not found for the authenticated user\n- `503` - Service not initialized\n\n`last_status_code` is the browser's last navigation response code when Chrome exposes it through Navigation Timing. If it is not available yet, the field is `null`.\n\n### List stored sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/stored-sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{sessions: [...], count}`. Connect via WebSocket to `/ws/{session_id}` to resume.\n\n### Navigate\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\"}'\n\n# With timeout (seconds)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\", \"timeout\": 60}'\n```\n\n### Set location\n\n```bash\n# Override geolocation for the page (e.g. for location-aware sites)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 37.7749, \"longitude\": -122.4194}'\n\n# With accuracy (meters)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 51.5074, \"longitude\": -0.1278, \"accuracy\": 50}'\n```\n\n### Image (download by selector)\n\n```bash\n# Capture a single element (e.g. image) by CSS selector\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img.hero\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o image.jpg\n\n# With quality, raw binary (selector=#banner for id)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img&quality=90&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o element.jpg\n```\n\nUse `selector` (CSS) or `ref` (from snapshot). Returns JPEG of the element's bounding box.\n\n### Snapshot (accessibility tree)\n\n```bash\n# Full tree\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Interactive elements only (buttons, links, inputs) — much smaller\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?filter=interactive\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Limit depth\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?depth=5\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{nodes: [{ref, role, name, depth, value?, disabled?, focused?, nodeId?}], count}`.\n\n### Extract text\n\n```bash\n# Readability mode (default) — strips nav/footer/ads\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw innerText\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text?mode=raw\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{url, title, text}`. Cheapest option (~800 tokens for most pages).\n\n### Screenshot\n\n```bash\n# JSON with base64\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw JPEG bytes\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# With quality (1-100)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?quality=50&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# Region capture (offset x,y and width,height in CSS pixels)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.jpg\n```\n\nUse this when Chrome DevTools rendering is enough. If you need browser chrome,\nOS dialogs, permission prompts, or the exact remote desktop pixels, use\n`/vnc/screenshot` instead.\n\n### VNC interface\n\n```bash\n# Built-in noVNC client page for a session\nopen \"https://rb.all-completed.com/users/{user_id}/vnc/{session_id}\"\n\n# Under the hood the page connects to the VNC websocket proxy\n# /users/{user_id}/vnc/ws/{session_id}\n```\n\nUse the VNC interface when you need a live remote-desktop view of the session\ninstead of DOM snapshots.\n\n### VNC screenshot\n\n```bash\n# Raw PNG bytes from the VNC framebuffer\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screen.png\n\n# Cropped framebuffer region\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.png\n```\n\nUnlike `/screenshot`, this captures the VNC framebuffer directly. Use it for\nbrowser chrome, native permission prompts, OS-level dialogs, or anything only\nvisible in the remote desktop.\n\n### Page size\n\n```bash\n# Get page content dimensions (use with screenshot clip)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/page-size\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{width, height}` in CSS pixels.\n\n### Act on elements\n\n```bash\n# Click by selector\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"selector\": \"button.submit\"}'\n\n# Click by coordinates (viewport x,y)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"x\": 100, \"y\": 200}'\n\n# Type into element (focus + insertText)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"type\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Fill (set value directly)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"fill\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Press a key\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"press\", \"key\": \"Enter\"}'\n# Press Enter in a specific input: -d '{\"kind\": \"press\", \"key\": \"Enter\", \"selector\": \"input#search\"}'\n\n# Focus, hover, select, scroll\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"focus\", \"selector\": \"input[name=search]\"}'\n\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"scroll\", \"scrollY\": 800}'\n```\n\n**Action kinds:** `click`, `type`, `fill`, `press`, `focus`, `hover`, `select`, `scroll`. Use `selector` (CSS) or `ref` (from snapshot). For `click` you can use `x` and `y` (viewport coordinates) instead of selector. For `fill`, the server focuses the field, `select()` only if the field already has text (then `Input.insertText` replaces), otherwise focuses and inserts like `type`—controlled inputs (e.g. React) update reliably. For `press` use `key` (e.g. `Enter`, `Tab`, `Escape`, `Space`, `ArrowUp`); optional `selector` focuses element first.\n\n### VNC action\n\n```bash\n# Move mouse\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"move\",\"x\":320,\"y\":240}'\n\n# Click at framebuffer coordinates\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}'\n\n# Press keys directly over VNC\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}'\n```\n\n**VNC action kinds:** `move`, `click`, `type`, `press`, `scroll`.\n\nThese actions are framebuffer-oriented and do not use DOM selectors. Prefer them\nwhen DOM automation cannot see or control the target UI.\n\n### HTML snapshot\n\n```bash\n# Full DOM with inlined CSS (opens in browser)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/html\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n## Token Cost Guide\n\n| Method | Typical tokens | When to use |\n|--------|----------------|-------------|\n| `/status` | ~50 | Just the current URL / title / HTTP status |\n| `/text` (readability) | ~800 | Reading page content |\n| `/text?mode=raw` | ~2K–8K | Content readability strips (hidden labels, etc.) |\n| `/json?filter=interactive` | ~3,600 | Finding buttons/links/inputs to act on (+ refs) |\n| `/json` (full a11y tree) | ~10,500 | Full structure / element relationships |\n| `/html?obfuscate=true` (simple markup) | ~10K–40K | Need exact CSS selectors / markup the a11y tree lacks |\n| `/html` (full markup) | very large | Raw DOM + inlined CSS; rarely needed, may exceed the 5 MiB cap |\n| `/image?selector=` | ~1K (vision) | Capture a single element / download an image |\n| `/screenshot` (clipped, low `quality`) | ~1K–2K (vision) | Visual check of one region |\n| `/screenshot` (full page) | ~2K+ (vision) | Whole-page layout / visual verification |\n| `/vnc/screenshot` | ~2K+ (vision) | Non-DOM/native UI, canvas, or when DOM tools fail |\n\n**Decision order — use the *cheapest* tool that answers your question, escalate only if it doesn't:**\n\n1. **`/status`** — only need where you are (URL/title/status).\n2. **`/text`** — reading/extracting content. (`?mode=raw` if readability hides what you need.)\n3. **`/json?filter=interactive`** — locating things to click/type; returns refs to act on.\n4. **`/json`** (full) — need structure/relationships the filtered tree omits.\n5. **`/html?obfuscate=true`** — need a precise selector/markup not surfaced by the a11y tree. Prefer obfuscated (compact) over full.\n6. **`/html`** (full) — last resort for raw markup/CSS; large.\n7. **`/screenshot` (clipped + low quality)** — *only* for visual confirmation or non-DOM layout. Always clip (`x,y,width,height`) and drop `quality`; never grab a full high-quality page when a region will do.\n8. **`/vnc/screenshot`** — only for native/canvas/non-DOM surfaces, or when DOM extraction genuinely fails.\n\n**Rule of thumb:** text/markup ≫ screenshots for token cost. A clipped JPEG is still an image; a `/text` call is a few hundred tokens. Act on **selectors/refs** from steps 2–6 rather than re-screenshotting to \"look again,\" and verify state changes with the cheapest read, not a fresh full screenshot.\n\n## Environment Variables\n\n| Var | Description |\n|-----|-------------|\n| `RBS_BASE_URL` | Base URL (e.g. https://rb.all-completed.com) |\n| `AC_API_KEY` | Bearer token or API key (user_id derived from token) |\n\n## Tips\n\n- **Session required** — Ensure a session exists before calling navigate/json/text/action. Create via `POST /api/sessions` (HTTP), WebSocket, or restore from stored sessions.\n- **Check live URL** — Use `GET /api/sessions/{session_id}/status` when you need the current page URL/title or last response status without fetching full page text.\n- **429 / session limit** — If create fails with 429 or WebSocket closes (limit exceeded): wait a few seconds and/or terminate the existing session with `DELETE /api/sessions/{session_id}` first, then retry.\n- **Refs from snapshot** — Use `selector` with the `ref` string (e.g. `\"e5\"`) when the action API supports ref→DOM resolution; otherwise prefer CSS selectors.\n- **Readability vs raw** — `/text` (default) strips nav/footer/ads; `?mode=raw` returns full `innerText`.\n- **Interactive filter** — `?filter=interactive` on `/json` reduces nodes by ~75% for action tasks.\n- **VNC vs DOM** — Use `/action` for selectors/refs in the page DOM. Use `/vnc/action` and `/vnc/screenshot` for pixel-level automation and UI outside the DOM.\n- **Stored sessions** — Sessions persist to S3 and are restored on reopen. The **whole browser profile** is captured (cookies, localStorage, sessionStorage, IndexedDB, **Service Workers**, Cache Storage, metadata) and restored as one consistent unit, so apps that keep their login in IndexedDB/Service Workers (e.g. Telegram Web) come back **logged in**, not just at the login page. List with `GET /api/stored-sessions`, then reopen by creating a session with the same `session_id` (HTTP/WebSocket). If `url` is not provided on connect, the saved page URL is used for redirect. Use `GET/PUT /api/stored-sessions/{session_id}` to read or update metadata: `url` (redirect on reopen), `description` (free-text human label, max 500 chars, returned in the list endpoint's `descriptions` map), `width`/`height` (default resolution), `encrypt_with_api_key`. To move or edit individual persisted blobs without a live browser, use `GET/PUT /api/stored-sessions/{session_id}/cookies` (JSON array of cookie objects), `GET/PUT .../local-storage`, `GET/PUT .../session-storage` (both JSON objects with string keys and string values), `GET/PUT .../indexeddb` (IndexedDB snapshot object), and `GET/PUT .../cache-storage` (Cache Storage snapshot object). `DELETE /api/stored-sessions/{session_id}` wipes all persisted state for a session.\n\n## Limitations & fallbacks\n\nReal-world heavy pages (Amazon, marketplaces, dashboards) hit these. Know the fallback for each:\n\n- **Prefer text/markup extraction over screenshots** — For reading page content, `/text`, `/json` (accessibility snapshot), and `/html` are *far* more efficient than `/screenshot` or `/vnc/screenshot`: they return compact, parseable structure instead of a large base64 image, so they cost a fraction of the tokens/bandwidth and give you selectors to act on. **Default to text/markup; use screenshots only for visual verification, pixel-level layout, or canvas/`<iframe>`/non-DOM UI.**\n- **CDP frame limit (now 5 MiB)** — `/text`, `/json`, and `/html` return over a CDP WebSocket whose frame cap was raised from 1 MiB to **5 MiB**, so they now succeed on most heavy pages. If a page is still too large and you get `502` / `frame exceeds limit ... bytes`, **then** fall back: prefer narrowing first (`/text?mode=readability` (default), `/json?filter=interactive`) before resorting to a **clipped `/screenshot`** (`x,y,width,height` + lower `quality`) or `/vnc/screenshot` (framebuffer, independent of the CDP limit).\n- **Prefer `fill` over `type` for form fields** — `type` does `focus()` + `Input.insertText`; some controlled/React inputs don't register it. `fill` does select-all + insertText with real input events and is the reliable choice for text fields. Use `type` only for appending to plain inputs.\n- **To submit a form, use `submit` (not `press` Enter)** — a synthetic `press` Enter does not perform the browser's default submit. Use `{\"kind\":\"submit\",\"selector\":\"<form or a field in it>\"}`, or click the submit button by selector (selector `click` does a DOM `element.click()`).\n- **Never type secrets yourself — use `request-fill` (\"Keeper\")** — for passwords, login codes, 2FA, or any value you must not see, call `POST /api/sessions/{id}/request-fill` instead of `fill`/`type`. **This is THIS service's own built-in secure credential fill — \"Keeper\" is the user's companion app for it. It is NOT OpenClaw `secrets`/`SecretRefs` (config-backed values); do not conclude \"there's no keeper\" because OpenClaw secrets has no live prompt — this endpoint IS the live prompt.** The user supplies the value out-of-band in their Keeper app (which shows your `message` + a screenshot of the field area) and the **service** types it into the field; the value is never returned to you or logged. It's **async**: you get `{request_id, status:\"pending\"}`, then poll `GET /api/sessions/fill-status/{request_id}` (tool `get_fill_status`) until `filled` / `cancelled` / `timeout` / `error`.\n  - **Default to this for any login.** Don't ask the user to paste a password into chat. Order of preference: (1) `request-fill`; (2) if it returns **`status:\"no_keeper\"`** (no Keeper app connected), have the user sign in themselves via the **live VNC view** (you never see the password) — the session then persists logged-in; (3) only as a last resort, with the user's explicit consent, accept a value they provide.\n  - **One field:** `{\"selector\":\"input[name=password]\",\"label\":\"Password\",\"field\":\"password\",\"message\":\"Logging into Telegram to read your unread chats\"}`.\n  - **Multiple fields in one prompt (max 50):** `{\"fields\":[{\"selector\":\"#user\",\"label\":\"Username\",\"field\":\"login\"},{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}],\"message\":\"Signing in\"}`.\n  - **`field`** sets the prompt kind: `password` (default, masked) / `code` / `login` / `email` / `text`. **`length`** caps the input (1–4096); **`format`** constrains it (`email`, `numeric`/`digits`, or a regex). Set them when you know the value's shape — see docs/keeper-fill-formats.md.\n  - **Payment cards** — use the card field kinds so the Keeper renders card-aware inputs and the user never exposes card data to you: `card-holder-name`, `card-number` (masked; `format` is a `#`-mask, default `################`, e.g. `\"#### #### #### ####\"`; submitted digits-only), `card-cvv` (masked), `card-exp` (`format` is a date template — `MM/YY` default, or `MM/YYYY` / `YY` / `YYYY` / `MM` for split month/year fields), `card-billing-address` (`format` names a component: `ADDRESS_LINE1`/`ADDRESS_LINE2`/`CITY`/`ZIP`/`STATE`/`COUNTRY` → single-line; **omit `format` for the whole address** → multi-line). One field per page input. **Dropdowns:** if the target is a `<select>` (expiry month/year, state, country), the service selects the matching `<option>` automatically — point the same `card-exp`/`card-billing-address` field at the `<select>`. Example: `{\"fields\":[{\"selector\":\"#num\",\"label\":\"Card number\",\"field\":\"card-number\"},{\"selector\":\"#exp\",\"label\":\"Expiry\",\"field\":\"card-exp\"},{\"selector\":\"#cvv\",\"label\":\"CVV\",\"field\":\"card-cvv\"},{\"selector\":\"#zip\",\"label\":\"ZIP\",\"field\":\"card-billing-address\",\"format\":\"ZIP\"}],\"message\":\"Enter card to check out\"}`.\n  - **One proof screenshot** is shown for the request. Pass **`screenshot_selector`** (or `screenshot_selectors`) to control what's captured — **prefer the whole `<form>`/container** (e.g. `\"screenshot_selector\":\"form#login\"`) so the user sees the form in context. Defaults to the field selectors' union if omitted.\n  - Full protocol: docs/keeper-protocol.md.\n- **Actions can report `{\"ok\": true}` without taking effect** — a `click` resolves the element box and dispatches a mouse event; if the target is off-viewport, covered by an overlay/sticky bar, or the page is a SPA mid-update, the event can be a no-op even though the call \"succeeds\". **Always verify state after any state-changing action** (re-screenshot, or re-check the relevant page e.g. the cart) rather than trusting `ok`. Prefer **selector-based** clicks over bare `x,y`; coordinate clicks on cart/checkout pages may also be blocked by host safety policy. If a selector click no-ops, try scrolling it into view first (`{\"kind\":\"scroll\"}`) or click via a screenshot-derived coordinate.\n- **Session lifetime & reopening** — A session with **no live viewer/client** (`active_ws_connections: 0`, e.g. one created purely via the API/MCP) is reclaimed after ~5 minutes idle, and **any service restart/deploy drops all live sessions**. The stored state survives, so **to reopen/resume, just create a session with the SAME `session_id`** — it relaunches the browser and restores the full profile (you stay logged in). List resumable ids with `GET /api/stored-sessions`. For multi-step tasks: keep acting (each call resets idle), avoid long external pauses, and `ping` between steps.\n- **Connecting/disconnecting (incl. CDP/Playwright) does not destroy the session** — opening a WebSocket/CDP connection (e.g. `connectOverCDP`) and closing it leaves the session running; it's reclaimed only by the idle timeout or an explicit `DELETE`. So a client may connect, work, disconnect, and reconnect later to the same live session without losing it.\n- **Encrypted sessions reopen the same way** — if a session was created with `encrypt_with_api_key`, you reopen it identically: create with the same `session_id` using the same API-key/OAuth auth you use for every call. The encryption key is derived **server-side from your token** — you never see, pass, or \"handle\" it. Don't avoid reopening an encrypted session; it is not a special case.\n\nFile v1.0.9:_meta.json\n\n{\n  \"ownerId\": \"kn730fwwv9rb4chrcwkdyx1pgx826v25\",\n  \"slug\": \"remote-browser\",\n  \"version\": \"1.0.9\",\n  \"publishedAt\": 1782777959956\n}\n\nFile v1.0.9:skill-card.md\n\n## Description:\n\nControls a remote Chrome browser via HTTP API for web automation, form filling, navigation, page inspection, screenshots, DOM actions, and VNC actions on sites the user owns or has permission to access.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[vasyaod](https://clawhub.ai/user/vasyaod)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and AI agents use this skill to operate a hosted Chrome browser through HTTP endpoints for permitted web automation, inspection, interaction, and visual fallback workflows.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Remote browser sessions can expose page contents, screenshots, actions, and logged-in browser state to the remote browser provider.\n\nMitigation: Install only when the provider is trusted, prefer ephemeral sessions, and avoid using sensitive accounts unless necessary.\n\nRisk: Persistent stored sessions can retain full browser profile state, including cookies and web storage, after a workflow ends.\n\nMitigation: Delete stored sessions when finished and use explicit session termination when persistent state is no longer needed.\n\nRisk: URL access tokens can be exposed through logs, browser history, or shared links.\n\nMitigation: Use Authorization headers or X-API-Key authentication instead of URL tokens when possible.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/vasyaod/skills/remote-browser)\n- [Remote Browser Service endpoint](https://rb.all-completed.com)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Markdown with HTTP API examples, JSON payloads, and concise operational guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide agents to retrieve text, accessibility snapshots, screenshots, VNC framebuffer images, session status, and stored-session metadata from the remote browser service.]\n\n## Skill Version(s):\n\n1.0.9 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.8: 3 files, 10913 bytes\n\nFiles: skill-card.md (2418b), SKILL.md (26654b), _meta.json (133b)\n\nFile v1.0.8:SKILL.md\n\n---\nname: remote-browser-service\ndescription: >\n  Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation,\n  form filling, navigation, and page inspection on sites the user owns or has permission to access.\n  Exposes the accessibility tree, text extraction, Chrome screenshots, VNC-native screenshots,\n  DOM actions, and VNC actions — optimized for AI agents. Requires an active browser session\n  (created via HTTP or WebSocket).\nmetadata:\n  openclaw:\n    emoji: \"🌐\"\n    requires:\n      env:\n        - name: AC_API_KEY\n          secret: true\n          optional: true\n          description: \"Bearer token or API key for auth (user_id derived from token)\"\n---\n\n# Remote Browser Service\n\nBrowser control for AI agents via HTTP API. Supports both DOM-oriented automation\nand remote-desktop/VNC control when you need the actual framebuffer.\n\n## Index\n\n- [Setup](#setup)\n- [Core Workflow](#core-workflow)\n- [API Reference](#api-reference)\n- [Screenshot](#screenshot)\n- [VNC interface](#vnc-interface)\n- [VNC screenshot](#vnc-screenshot)\n- [Act on elements](#act-on-elements)\n- [VNC action](#vnc-action)\n- [HTML snapshot](#html-snapshot)\n- [Token Cost Guide](#token-cost-guide)\n- [Limitations & fallbacks](#limitations--fallbacks)\n- [Environment Variables](#environment-variables)\n- [Tips](#tips)\n\n## Setup\n\nEnsure you have an active session:\n\n1. **Create session** — `POST /api/sessions` (HTTP, no WebSocket), or open WebSocket to `/ws/{session_id}` (DevTools CDP), or run from UI. Optional `url` in body (HTTP) or query (WS) to navigate immediately.\n2. **Or restore** — Use stored session from `GET /api/stored-sessions`\n3. **Auth** — Pass `Authorization: Bearer <token>` or `X-API-Key`, or `?access_token=<token>`\n\nBase URL: `https://rb.all-completed.com` (or `RBS_BASE_URL`). Replace `{session_id}` in examples. User ID is derived from the token.\n\n## Core Workflow\n\n1. **Navigate** to a URL\n2. **Snapshot** the accessibility tree (get refs) — `GET .../json`\n3. **Act** on refs or selectors (click, type, fill, press)\n4. **Snapshot** again to see results\n\nFor visual or OS-level flows, use the VNC path instead:\n\n1. **Open VNC interface** — `GET /users/{user_id}/vnc/{session_id}` when you want a live noVNC view\n2. **Capture VNC framebuffer** — `GET .../vnc/screenshot`\n3. **Send VNC input** — `POST .../vnc/action` with coordinates or keys\n4. **Capture again** to verify pixel-level results\n\nRefs (`e0`, `e1`, …) from `/json` can be used with `/action` via `selector` (use `ref` as selector for `e5` → `\"e5\"` maps to role/name; for now use CSS `selector`).\n\nSupported actions by mode:\n\n| Mode               | Kind     | Example                                                     |\n|--------------------|----------|-------------------------------------------------------------|\n| DOM (`/action`)    | `click`  | `{\"kind\":\"click\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `tap`    | `{\"kind\":\"tap\",\"selector\":\"button.submit\"}`                 |\n| DOM (`/action`)    | `type`   | `{\"kind\":\"type\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `fill`   | `{\"kind\":\"fill\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `press`  | `{\"kind\":\"press\",\"key\":\"Enter\"}`                            |\n| DOM (`/action`)    | `focus`  | `{\"kind\":\"focus\",\"selector\":\"input[name=search]\"}`          |\n| DOM (`/action`)    | `hover`  | `{\"kind\":\"hover\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `select` | `{\"kind\":\"select\",\"selector\":\"select\",\"value\":\"option-1\"}`  |\n| DOM (`/action`)    | `scroll` | `{\"kind\":\"scroll\",\"scrollY\":800}`                           |\n| DOM (`/action`)    | `submit` | `{\"kind\":\"submit\",\"selector\":\"#nav-search-form\"}` (or a field within the form) |\n| Secrets (`/request-fill`) | — | `{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}` — user fills it in the Keeper app; value never seen by the agent |\n| VNC (`/vnc/action`) | `move`   | `{\"kind\":\"move\",\"x\":320,\"y\":240}`                           |\n| VNC (`/vnc/action`) | `click`  | `{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}` |\n| VNC (`/vnc/action`) | `type`   | `{\"kind\":\"type\",\"text\":\"hello world\"}`                      |\n| VNC (`/vnc/action`) | `press`  | `{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}`                      |\n| VNC (`/vnc/action`) | `scroll` | `{\"kind\":\"scroll\",\"x\":320,\"y\":240,\"direction\":\"down\",\"repeat\":3}` |\n\n## API Reference\n\n### Create session (HTTP)\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n# Optional: {\"session_id\": \"my-session\", \"url\": \"https://example.com\"}\n# Fork from stored session: {\"session_id\": \"my-fork\", \"from\": \"original-session\"}\n# Ephemeral (start from metadata/fork but don't save): {\"ephemeral\": true}\n```\n\nSessions idle for 5 min are closed. Use `POST .../ping` to keep alive.\n\nMaximum 1 concurrent session per user. If creation returns 429 or WebSocket closes with a limit error: **wait a bit** (previous session may still be shutting down) **and/or close the previous session** via `DELETE /api/sessions/{session_id}` before retrying.\n\n### List sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n### Session status\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns live session state plus current page metadata:\n\n```json\n{\n  \"session_id\": \"session-123\",\n  \"created_at\": \"2026-02-12T10:00:00\",\n  \"active_ws_connections\": 1,\n  \"status\": \"ready\",\n  \"last_error\": null,\n  \"current_url\": \"https://example.com/page\",\n  \"page_title\": \"Example Domain\",\n  \"last_status_code\": 200\n}\n```\n\nHTTP status codes:\n\n- `200` - Session found; manager status returned, with live page metadata when available\n- `404` - Session not found for the authenticated user\n- `503` - Service not initialized\n\n`last_status_code` is the browser's last navigation response code when Chrome exposes it through Navigation Timing. If it is not available yet, the field is `null`.\n\n### List stored sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/stored-sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{sessions: [...], count}`. Connect via WebSocket to `/ws/{session_id}` to resume.\n\n### Navigate\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\"}'\n\n# With timeout (seconds)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\", \"timeout\": 60}'\n```\n\n### Set location\n\n```bash\n# Override geolocation for the page (e.g. for location-aware sites)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 37.7749, \"longitude\": -122.4194}'\n\n# With accuracy (meters)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 51.5074, \"longitude\": -0.1278, \"accuracy\": 50}'\n```\n\n### Image (download by selector)\n\n```bash\n# Capture a single element (e.g. image) by CSS selector\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img.hero\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o image.jpg\n\n# With quality, raw binary (selector=#banner for id)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img&quality=90&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o element.jpg\n```\n\nUse `selector` (CSS) or `ref` (from snapshot). Returns JPEG of the element's bounding box.\n\n### Snapshot (accessibility tree)\n\n```bash\n# Full tree\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Interactive elements only (buttons, links, inputs) — much smaller\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?filter=interactive\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Limit depth\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?depth=5\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{nodes: [{ref, role, name, depth, value?, disabled?, focused?, nodeId?}], count}`.\n\n### Extract text\n\n```bash\n# Readability mode (default) — strips nav/footer/ads\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw innerText\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text?mode=raw\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{url, title, text}`. Cheapest option (~800 tokens for most pages).\n\n### Screenshot\n\n```bash\n# JSON with base64\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw JPEG bytes\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# With quality (1-100)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?quality=50&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# Region capture (offset x,y and width,height in CSS pixels)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.jpg\n```\n\nUse this when Chrome DevTools rendering is enough. If you need browser chrome,\nOS dialogs, permission prompts, or the exact remote desktop pixels, use\n`/vnc/screenshot` instead.\n\n### VNC interface\n\n```bash\n# Built-in noVNC client page for a session\nopen \"https://rb.all-completed.com/users/{user_id}/vnc/{session_id}\"\n\n# Under the hood the page connects to the VNC websocket proxy\n# /users/{user_id}/vnc/ws/{session_id}\n```\n\nUse the VNC interface when you need a live remote-desktop view of the session\ninstead of DOM snapshots.\n\n### VNC screenshot\n\n```bash\n# Raw PNG bytes from the VNC framebuffer\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screen.png\n\n# Cropped framebuffer region\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.png\n```\n\nUnlike `/screenshot`, this captures the VNC framebuffer directly. Use it for\nbrowser chrome, native permission prompts, OS-level dialogs, or anything only\nvisible in the remote desktop.\n\n### Page size\n\n```bash\n# Get page content dimensions (use with screenshot clip)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/page-size\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{width, height}` in CSS pixels.\n\n### Act on elements\n\n```bash\n# Click by selector\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"selector\": \"button.submit\"}'\n\n# Click by coordinates (viewport x,y)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"x\": 100, \"y\": 200}'\n\n# Type into element (focus + insertText)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"type\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Fill (set value directly)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"fill\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Press a key\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"press\", \"key\": \"Enter\"}'\n# Press Enter in a specific input: -d '{\"kind\": \"press\", \"key\": \"Enter\", \"selector\": \"input#search\"}'\n\n# Focus, hover, select, scroll\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"focus\", \"selector\": \"input[name=search]\"}'\n\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"scroll\", \"scrollY\": 800}'\n```\n\n**Action kinds:** `click`, `type`, `fill`, `press`, `focus`, `hover`, `select`, `scroll`. Use `selector` (CSS) or `ref` (from snapshot). For `click` you can use `x` and `y` (viewport coordinates) instead of selector. For `fill`, the server focuses the field, `select()` only if the field already has text (then `Input.insertText` replaces), otherwise focuses and inserts like `type`—controlled inputs (e.g. React) update reliably. For `press` use `key` (e.g. `Enter`, `Tab`, `Escape`, `Space`, `ArrowUp`); optional `selector` focuses element first.\n\n### VNC action\n\n```bash\n# Move mouse\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"move\",\"x\":320,\"y\":240}'\n\n# Click at framebuffer coordinates\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}'\n\n# Press keys directly over VNC\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}'\n```\n\n**VNC action kinds:** `move`, `click`, `type`, `press`, `scroll`.\n\nThese actions are framebuffer-oriented and do not use DOM selectors. Prefer them\nwhen DOM automation cannot see or control the target UI.\n\n### HTML snapshot\n\n```bash\n# Full DOM with inlined CSS (opens in browser)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/html\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n## Token Cost Guide\n\n| Method | Typical tokens | When to use |\n|--------|----------------|-------------|\n| `/status` | ~50 | Just the current URL / title / HTTP status |\n| `/text` (readability) | ~800 | Reading page content |\n| `/text?mode=raw` | ~2K–8K | Content readability strips (hidden labels, etc.) |\n| `/json?filter=interactive` | ~3,600 | Finding buttons/links/inputs to act on (+ refs) |\n| `/json` (full a11y tree) | ~10,500 | Full structure / element relationships |\n| `/html?obfuscate=true` (simple markup) | ~10K–40K | Need exact CSS selectors / markup the a11y tree lacks |\n| `/html` (full markup) | very large | Raw DOM + inlined CSS; rarely needed, may exceed the 5 MiB cap |\n| `/image?selector=` | ~1K (vision) | Capture a single element / download an image |\n| `/screenshot` (clipped, low `quality`) | ~1K–2K (vision) | Visual check of one region |\n| `/screenshot` (full page) | ~2K+ (vision) | Whole-page layout / visual verification |\n| `/vnc/screenshot` | ~2K+ (vision) | Non-DOM/native UI, canvas, or when DOM tools fail |\n\n**Decision order — use the *cheapest* tool that answers your question, escalate only if it doesn't:**\n\n1. **`/status`** — only need where you are (URL/title/status).\n2. **`/text`** — reading/extracting content. (`?mode=raw` if readability hides what you need.)\n3. **`/json?filter=interactive`** — locating things to click/type; returns refs to act on.\n4. **`/json`** (full) — need structure/relationships the filtered tree omits.\n5. **`/html?obfuscate=true`** — need a precise selector/markup not surfaced by the a11y tree. Prefer obfuscated (compact) over full.\n6. **`/html`** (full) — last resort for raw markup/CSS; large.\n7. **`/screenshot` (clipped + low quality)** — *only* for visual confirmation or non-DOM layout. Always clip (`x,y,width,height`) and drop `quality`; never grab a full high-quality page when a region will do.\n8. **`/vnc/screenshot`** — only for native/canvas/non-DOM surfaces, or when DOM extraction genuinely fails.\n\n**Rule of thumb:** text/markup ≫ screenshots for token cost. A clipped JPEG is still an image; a `/text` call is a few hundred tokens. Act on **selectors/refs** from steps 2–6 rather than re-screenshotting to \"look again,\" and verify state changes with the cheapest read, not a fresh full screenshot.\n\n## Environment Variables\n\n| Var | Description |\n|-----|-------------|\n| `RBS_BASE_URL` | Base URL (e.g. https://rb.all-completed.com) |\n| `AC_API_KEY` | Bearer token or API key (user_id derived from token) |\n\n## Tips\n\n- **Session required** — Ensure a session exists before calling navigate/json/text/action. Create via `POST /api/sessions` (HTTP), WebSocket, or restore from stored sessions.\n- **Check live URL** — Use `GET /api/sessions/{session_id}/status` when you need the current page URL/title or last response status without fetching full page text.\n- **429 / session limit** — If create fails with 429 or WebSocket closes (limit exceeded): wait a few seconds and/or terminate the existing session with `DELETE /api/sessions/{session_id}` first, then retry.\n- **Refs from snapshot** — Use `selector` with the `ref` string (e.g. `\"e5\"`) when the action API supports ref→DOM resolution; otherwise prefer CSS selectors.\n- **Readability vs raw** — `/text` (default) strips nav/footer/ads; `?mode=raw` returns full `innerText`.\n- **Interactive filter** — `?filter=interactive` on `/json` reduces nodes by ~75% for action tasks.\n- **VNC vs DOM** — Use `/action` for selectors/refs in the page DOM. Use `/vnc/action` and `/vnc/screenshot` for pixel-level automation and UI outside the DOM.\n- **Stored sessions** — Sessions persist to S3 and are restored on reopen. The **whole browser profile** is captured (cookies, localStorage, sessionStorage, IndexedDB, **Service Workers**, Cache Storage, metadata) and restored as one consistent unit, so apps that keep their login in IndexedDB/Service Workers (e.g. Telegram Web) come back **logged in**, not just at the login page. List with `GET /api/stored-sessions`, then reopen by creating a session with the same `session_id` (HTTP/WebSocket). If `url` is not provided on connect, the saved page URL is used for redirect. Use `GET/PUT /api/stored-sessions/{session_id}` to read or update metadata (e.g. redirect URL). To move or edit individual persisted blobs without a live browser, use `GET/PUT /api/stored-sessions/{session_id}/cookies` (JSON array of cookie objects), `GET/PUT .../local-storage`, `GET/PUT .../session-storage` (both JSON objects with string keys and string values), `GET/PUT .../indexeddb` (IndexedDB snapshot object), and `GET/PUT .../cache-storage` (Cache Storage snapshot object). `DELETE /api/stored-sessions/{session_id}` wipes all persisted state for a session.\n\n## Limitations & fallbacks\n\nReal-world heavy pages (Amazon, marketplaces, dashboards) hit these. Know the fallback for each:\n\n- **Prefer text/markup extraction over screenshots** — For reading page content, `/text`, `/json` (accessibility snapshot), and `/html` are *far* more efficient than `/screenshot` or `/vnc/screenshot`: they return compact, parseable structure instead of a large base64 image, so they cost a fraction of the tokens/bandwidth and give you selectors to act on. **Default to text/markup; use screenshots only for visual verification, pixel-level layout, or canvas/`<iframe>`/non-DOM UI.**\n- **CDP frame limit (now 5 MiB)** — `/text`, `/json`, and `/html` return over a CDP WebSocket whose frame cap was raised from 1 MiB to **5 MiB**, so they now succeed on most heavy pages. If a page is still too large and you get `502` / `frame exceeds limit ... bytes`, **then** fall back: prefer narrowing first (`/text?mode=readability` (default), `/json?filter=interactive`) before resorting to a **clipped `/screenshot`** (`x,y,width,height` + lower `quality`) or `/vnc/screenshot` (framebuffer, independent of the CDP limit).\n- **Prefer `fill` over `type` for form fields** — `type` does `focus()` + `Input.insertText`; some controlled/React inputs don't register it. `fill` does select-all + insertText with real input events and is the reliable choice for text fields. Use `type` only for appending to plain inputs.\n- **To submit a form, use `submit` (not `press` Enter)** — a synthetic `press` Enter does not perform the browser's default submit. Use `{\"kind\":\"submit\",\"selector\":\"<form or a field in it>\"}`, or click the submit button by selector (selector `click` does a DOM `element.click()`).\n- **Never type secrets yourself — use `request-fill` (\"Keeper\")** — for passwords, login codes, 2FA, or any value you must not see, call `POST /api/sessions/{id}/request-fill` instead of `fill`/`type`. **This is THIS service's own built-in secure credential fill — \"Keeper\" is the user's companion app for it. It is NOT OpenClaw `secrets`/`SecretRefs` (config-backed values); do not conclude \"there's no keeper\" because OpenClaw secrets has no live prompt — this endpoint IS the live prompt.** The user supplies the value out-of-band in their Keeper app (which shows your `message` + a screenshot of the field area) and the **service** types it into the field; the value is never returned to you or logged. It's **async**: you get `{request_id, status:\"pending\"}`, then poll `GET /api/sessions/fill-status/{request_id}` (tool `get_fill_status`) until `filled` / `cancelled` / `timeout` / `error`.\n  - **Default to this for any login.** Don't ask the user to paste a password into chat. Order of preference: (1) `request-fill`; (2) if it returns **`status:\"no_keeper\"`** (no Keeper app connected), have the user sign in themselves via the **live VNC view** (you never see the password) — the session then persists logged-in; (3) only as a last resort, with the user's explicit consent, accept a value they provide.\n  - **One field:** `{\"selector\":\"input[name=password]\",\"label\":\"Password\",\"field\":\"password\",\"message\":\"Logging into Telegram to read your unread chats\"}`.\n  - **Multiple fields in one prompt (max 50):** `{\"fields\":[{\"selector\":\"#user\",\"label\":\"Username\",\"field\":\"login\"},{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}],\"message\":\"Signing in\"}`.\n  - **`field`** sets the prompt kind: `password` (default, masked) / `code` / `login` / `email` / `text`. **`length`** caps the input (1–4096); **`format`** constrains it (`email`, `numeric`/`digits`, or a regex). Set them when you know the value's shape — see docs/keeper-fill-formats.md.\n  - **Payment cards** — use the card field kinds so the Keeper renders card-aware inputs and the user never exposes card data to you: `card-holder-name`, `card-number` (masked; `format` is a `#`-mask, default `################`, e.g. `\"#### #### #### ####\"`; submitted digits-only), `card-cvv` (masked), `card-exp` (`format` is a date template — `MM/YY` default, or `MM/YYYY` / `YY` / `YYYY` / `MM` for split month/year fields), `card-billing-address` (`format` names a component: `ADDRESS_LINE1`/`ADDRESS_LINE2`/`CITY`/`ZIP`/`STATE`/`COUNTRY` → single-line; **omit `format` for the whole address** → multi-line). One field per page input. **Dropdowns:** if the target is a `<select>` (expiry month/year, state, country), the service selects the matching `<option>` automatically — point the same `card-exp`/`card-billing-address` field at the `<select>`. Example: `{\"fields\":[{\"selector\":\"#num\",\"label\":\"Card number\",\"field\":\"card-number\"},{\"selector\":\"#exp\",\"label\":\"Expiry\",\"field\":\"card-exp\"},{\"selector\":\"#cvv\",\"label\":\"CVV\",\"field\":\"card-cvv\"},{\"selector\":\"#zip\",\"label\":\"ZIP\",\"field\":\"card-billing-address\",\"format\":\"ZIP\"}],\"message\":\"Enter card to check out\"}`.\n  - **One proof screenshot** is shown for the request. Pass **`screenshot_selector`** (or `screenshot_selectors`) to control what's captured — **prefer the whole `<form>`/container** (e.g. `\"screenshot_selector\":\"form#login\"`) so the user sees the form in context. Defaults to the field selectors' union if omitted.\n  - Full protocol: docs/keeper-protocol.md.\n- **Actions can report `{\"ok\": true}` without taking effect** — a `click` resolves the element box and dispatches a mouse event; if the target is off-viewport, covered by an overlay/sticky bar, or the page is a SPA mid-update, the event can be a no-op even though the call \"succeeds\". **Always verify state after any state-changing action** (re-screenshot, or re-check the relevant page e.g. the cart) rather than trusting `ok`. Prefer **selector-based** clicks over bare `x,y`; coordinate clicks on cart/checkout pages may also be blocked by host safety policy. If a selector click no-ops, try scrolling it into view first (`{\"kind\":\"scroll\"}`) or click via a screenshot-derived coordinate.\n- **Session lifetime & reopening** — A session with **no live viewer/client** (`active_ws_connections: 0`, e.g. one created purely via the API/MCP) is reclaimed after ~5 minutes idle, and **any service restart/deploy drops all live sessions**. The stored state survives, so **to reopen/resume, just create a session with the SAME `session_id`** — it relaunches the browser and restores the full profile (you stay logged in). List resumable ids with `GET /api/stored-sessions`. For multi-step tasks: keep acting (each call resets idle), avoid long external pauses, and `ping` between steps.\n- **Connecting/disconnecting (incl. CDP/Playwright) does not destroy the session** — opening a WebSocket/CDP connection (e.g. `connectOverCDP`) and closing it leaves the session running; it's reclaimed only by the idle timeout or an explicit `DELETE`. So a client may connect, work, disconnect, and reconnect later to the same live session without losing it.\n- **Encrypted sessions reopen the same way** — if a session was created with `encrypt_with_api_key`, you reopen it identically: create with the same `session_id` using the same API-key/OAuth auth you use for every call. The encryption key is derived **server-side from your token** — you never see, pass, or \"handle\" it. Don't avoid reopening an encrypted session; it is not a special case.\n\nFile v1.0.8:_meta.json\n\n{\n  \"ownerId\": \"kn730fwwv9rb4chrcwkdyx1pgx826v25\",\n  \"slug\": \"remote-browser\",\n  \"version\": \"1.0.8\",\n  \"publishedAt\": 1782252328712\n}\n\nFile v1.0.8:skill-card.md\n\n## Description: <br>\nControls a remote Chrome browser via HTTP API for permitted web automation, form filling, navigation, page inspection, screenshots, VNC-native interaction, and DOM actions. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[vasyaod](https://clawhub.ai/user/vasyaod) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agents use this skill to operate a remote Chrome session for web navigation, form filling, page inspection, and visual or VNC-based workflows on sites they own or have permission to access. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can navigate pages and perform browser actions that affect accounts, forms, or other web state. <br>\nMitigation: Use it only on sites the user owns or has permission to access, review planned actions, and verify state changes after each meaningful action. <br>\nRisk: Credentials, login codes, or payment details could be exposed if entered directly into chat, commands, or logs. <br>\nMitigation: Use the documented request-fill flow for sensitive values and avoid placing secrets in review bundles or command examples. <br>\nRisk: Stored browser sessions can preserve cookies, local storage, IndexedDB, service workers, and cache data across reconnects. <br>\nMitigation: Delete stored sessions when they are no longer needed and limit access to authenticated users who are expected to operate the browser session. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/vasyaod/skills/remote-browser) <br>\n- [Remote Browser Service API base URL](https://rb.all-completed.com) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Guidance, Shell commands, JSON, API calls] <br>\n**Output Format:** [Markdown guidance with curl commands and JSON request and response examples] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Requires an active remote browser session; authentication may use a bearer token or API key.] <br>\n\n## Skill Version(s): <br>\n1.0.8 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.0.5: 3 files, 10426 bytes\n\nFiles: skill-card.md (2488b), SKILL.md (25474b), _meta.json (133b)\n\nFile v1.0.5:SKILL.md\n\n---\nname: remote-browser-service\ndescription: >\n  Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation,\n  form filling, navigation, and page inspection on sites the user owns or has permission to access.\n  Exposes the accessibility tree, text extraction, Chrome screenshots, VNC-native screenshots,\n  DOM actions, and VNC actions — optimized for AI agents. Requires an active browser session\n  (created via HTTP or WebSocket).\nmetadata:\n  openclaw:\n    emoji: \"🌐\"\n    requires:\n      env:\n        - name: AC_API_KEY\n          secret: true\n          optional: true\n          description: \"Bearer token or API key for auth (user_id derived from token)\"\n---\n\n# Remote Browser Service\n\nBrowser control for AI agents via HTTP API. Supports both DOM-oriented automation\nand remote-desktop/VNC control when you need the actual framebuffer.\n\n## Index\n\n- [Setup](#setup)\n- [Core Workflow](#core-workflow)\n- [API Reference](#api-reference)\n- [Screenshot](#screenshot)\n- [VNC interface](#vnc-interface)\n- [VNC screenshot](#vnc-screenshot)\n- [Act on elements](#act-on-elements)\n- [VNC action](#vnc-action)\n- [HTML snapshot](#html-snapshot)\n- [Token Cost Guide](#token-cost-guide)\n- [Limitations & fallbacks](#limitations--fallbacks)\n- [Environment Variables](#environment-variables)\n- [Tips](#tips)\n\n## Setup\n\nEnsure you have an active session:\n\n1. **Create session** — `POST /api/sessions` (HTTP, no WebSocket), or open WebSocket to `/ws/{session_id}` (DevTools CDP), or run from UI. Optional `url` in body (HTTP) or query (WS) to navigate immediately.\n2. **Or restore** — Use stored session from `GET /api/stored-sessions`\n3. **Auth** — Pass `Authorization: Bearer <token>` or `X-API-Key`, or `?access_token=<token>`\n\nBase URL: `https://rb.all-completed.com` (or `RBS_BASE_URL`). Replace `{session_id}` in examples. User ID is derived from the token.\n\n## Core Workflow\n\n1. **Navigate** to a URL\n2. **Snapshot** the accessibility tree (get refs) — `GET .../json`\n3. **Act** on refs or selectors (click, type, fill, press)\n4. **Snapshot** again to see results\n\nFor visual or OS-level flows, use the VNC path instead:\n\n1. **Open VNC interface** — `GET /users/{user_id}/vnc/{session_id}` when you want a live noVNC view\n2. **Capture VNC framebuffer** — `GET .../vnc/screenshot`\n3. **Send VNC input** — `POST .../vnc/action` with coordinates or keys\n4. **Capture again** to verify pixel-level results\n\nRefs (`e0`, `e1`, …) from `/json` can be used with `/action` via `selector` (use `ref` as selector for `e5` → `\"e5\"` maps to role/name; for now use CSS `selector`).\n\nSupported actions by mode:\n\n| Mode               | Kind     | Example                                                     |\n|--------------------|----------|-------------------------------------------------------------|\n| DOM (`/action`)    | `click`  | `{\"kind\":\"click\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `tap`    | `{\"kind\":\"tap\",\"selector\":\"button.submit\"}`                 |\n| DOM (`/action`)    | `type`   | `{\"kind\":\"type\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `fill`   | `{\"kind\":\"fill\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `press`  | `{\"kind\":\"press\",\"key\":\"Enter\"}`                            |\n| DOM (`/action`)    | `focus`  | `{\"kind\":\"focus\",\"selector\":\"input[name=search]\"}`          |\n| DOM (`/action`)    | `hover`  | `{\"kind\":\"hover\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `select` | `{\"kind\":\"select\",\"selector\":\"select\",\"value\":\"option-1\"}`  |\n| DOM (`/action`)    | `scroll` | `{\"kind\":\"scroll\",\"scrollY\":800}`                           |\n| DOM (`/action`)    | `submit` | `{\"kind\":\"submit\",\"selector\":\"#nav-search-form\"}` (or a field within the form) |\n| Secrets (`/request-fill`) | — | `{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}` — user fills it in the Keeper app; value never seen by the agent |\n| VNC (`/vnc/action`) | `move`   | `{\"kind\":\"move\",\"x\":320,\"y\":240}`                           |\n| VNC (`/vnc/action`) | `click`  | `{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}` |\n| VNC (`/vnc/action`) | `type`   | `{\"kind\":\"type\",\"text\":\"hello world\"}`                      |\n| VNC (`/vnc/action`) | `press`  | `{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}`                      |\n| VNC (`/vnc/action`) | `scroll` | `{\"kind\":\"scroll\",\"x\":320,\"y\":240,\"direction\":\"down\",\"repeat\":3}` |\n\n## API Reference\n\n### Create session (HTTP)\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n# Optional: {\"session_id\": \"my-session\", \"url\": \"https://example.com\"}\n# Fork from stored session: {\"session_id\": \"my-fork\", \"from\": \"original-session\"}\n# Ephemeral (start from metadata/fork but don't save): {\"ephemeral\": true}\n```\n\nSessions idle for 5 min are closed. Use `POST .../ping` to keep alive.\n\nMaximum 1 concurrent session per user. If creation returns 429 or WebSocket closes with a limit error: **wait a bit** (previous session may still be shutting down) **and/or close the previous session** via `DELETE /api/sessions/{session_id}` before retrying.\n\n### List sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n### Session status\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns live session state plus current page metadata:\n\n```json\n{\n  \"session_id\": \"session-123\",\n  \"created_at\": \"2026-02-12T10:00:00\",\n  \"active_ws_connections\": 1,\n  \"status\": \"ready\",\n  \"last_error\": null,\n  \"current_url\": \"https://example.com/page\",\n  \"page_title\": \"Example Domain\",\n  \"last_status_code\": 200\n}\n```\n\nHTTP status codes:\n\n- `200` - Session found; manager status returned, with live page metadata when available\n- `404` - Session not found for the authenticated user\n- `503` - Service not initialized\n\n`last_status_code` is the browser's last navigation response code when Chrome exposes it through Navigation Timing. If it is not available yet, the field is `null`.\n\n### List stored sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/stored-sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{sessions: [...], count}`. Connect via WebSocket to `/ws/{session_id}` to resume.\n\n### Navigate\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\"}'\n\n# With timeout (seconds)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\", \"timeout\": 60}'\n```\n\n### Set location\n\n```bash\n# Override geolocation for the page (e.g. for location-aware sites)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 37.7749, \"longitude\": -122.4194}'\n\n# With accuracy (meters)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 51.5074, \"longitude\": -0.1278, \"accuracy\": 50}'\n```\n\n### Image (download by selector)\n\n```bash\n# Capture a single element (e.g. image) by CSS selector\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img.hero\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o image.jpg\n\n# With quality, raw binary (selector=#banner for id)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img&quality=90&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o element.jpg\n```\n\nUse `selector` (CSS) or `ref` (from snapshot). Returns JPEG of the element's bounding box.\n\n### Snapshot (accessibility tree)\n\n```bash\n# Full tree\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Interactive elements only (buttons, links, inputs) — much smaller\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?filter=interactive\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Limit depth\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?depth=5\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{nodes: [{ref, role, name, depth, value?, disabled?, focused?, nodeId?}], count}`.\n\n### Extract text\n\n```bash\n# Readability mode (default) — strips nav/footer/ads\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw innerText\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text?mode=raw\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{url, title, text}`. Cheapest option (~800 tokens for most pages).\n\n### Screenshot\n\n```bash\n# JSON with base64\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw JPEG bytes\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# With quality (1-100)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?quality=50&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# Region capture (offset x,y and width,height in CSS pixels)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.jpg\n```\n\nUse this when Chrome DevTools rendering is enough. If you need browser chrome,\nOS dialogs, permission prompts, or the exact remote desktop pixels, use\n`/vnc/screenshot` instead.\n\n### VNC interface\n\n```bash\n# Built-in noVNC client page for a session\nopen \"https://rb.all-completed.com/users/{user_id}/vnc/{session_id}\"\n\n# Under the hood the page connects to the VNC websocket proxy\n# /users/{user_id}/vnc/ws/{session_id}\n```\n\nUse the VNC interface when you need a live remote-desktop view of the session\ninstead of DOM snapshots.\n\n### VNC screenshot\n\n```bash\n# Raw PNG bytes from the VNC framebuffer\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screen.png\n\n# Cropped framebuffer region\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.png\n```\n\nUnlike `/screenshot`, this captures the VNC framebuffer directly. Use it for\nbrowser chrome, native permission prompts, OS-level dialogs, or anything only\nvisible in the remote desktop.\n\n### Page size\n\n```bash\n# Get page content dimensions (use with screenshot clip)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/page-size\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{width, height}` in CSS pixels.\n\n### Act on elements\n\n```bash\n# Click by selector\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"selector\": \"button.submit\"}'\n\n# Click by coordinates (viewport x,y)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"x\": 100, \"y\": 200}'\n\n# Type into element (focus + insertText)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"type\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Fill (set value directly)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"fill\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Press a key\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"press\", \"key\": \"Enter\"}'\n# Press Enter in a specific input: -d '{\"kind\": \"press\", \"key\": \"Enter\", \"selector\": \"input#search\"}'\n\n# Focus, hover, select, scroll\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"focus\", \"selector\": \"input[name=search]\"}'\n\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"scroll\", \"scrollY\": 800}'\n```\n\n**Action kinds:** `click`, `type`, `fill`, `press`, `focus`, `hover`, `select`, `scroll`. Use `selector` (CSS) or `ref` (from snapshot). For `click` you can use `x` and `y` (viewport coordinates) instead of selector. For `fill`, the server focuses the field, `select()` only if the field already has text (then `Input.insertText` replaces), otherwise focuses and inserts like `type`—controlled inputs (e.g. React) update reliably. For `press` use `key` (e.g. `Enter`, `Tab`, `Escape`, `Space`, `ArrowUp`); optional `selector` focuses element first.\n\n### VNC action\n\n```bash\n# Move mouse\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"move\",\"x\":320,\"y\":240}'\n\n# Click at framebuffer coordinates\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}'\n\n# Press keys directly over VNC\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}'\n```\n\n**VNC action kinds:** `move`, `click`, `type`, `press`, `scroll`.\n\nThese actions are framebuffer-oriented and do not use DOM selectors. Prefer them\nwhen DOM automation cannot see or control the target UI.\n\n### HTML snapshot\n\n```bash\n# Full DOM with inlined CSS (opens in browser)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/html\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n## Token Cost Guide\n\n| Method | Typical tokens | When to use |\n|--------|----------------|-------------|\n| `/status` | ~50 | Just the current URL / title / HTTP status |\n| `/text` (readability) | ~800 | Reading page content |\n| `/text?mode=raw` | ~2K–8K | Content readability strips (hidden labels, etc.) |\n| `/json?filter=interactive` | ~3,600 | Finding buttons/links/inputs to act on (+ refs) |\n| `/json` (full a11y tree) | ~10,500 | Full structure / element relationships |\n| `/html?obfuscate=true` (simple markup) | ~10K–40K | Need exact CSS selectors / markup the a11y tree lacks |\n| `/html` (full markup) | very large | Raw DOM + inlined CSS; rarely needed, may exceed the 5 MiB cap |\n| `/image?selector=` | ~1K (vision) | Capture a single element / download an image |\n| `/screenshot` (clipped, low `quality`) | ~1K–2K (vision) | Visual check of one region |\n| `/screenshot` (full page) | ~2K+ (vision) | Whole-page layout / visual verification |\n| `/vnc/screenshot` | ~2K+ (vision) | Non-DOM/native UI, canvas, or when DOM tools fail |\n\n**Decision order — use the *cheapest* tool that answers your question, escalate only if it doesn't:**\n\n1. **`/status`** — only need where you are (URL/title/status).\n2. **`/text`** — reading/extracting content. (`?mode=raw` if readability hides what you need.)\n3. **`/json?filter=interactive`** — locating things to click/type; returns refs to act on.\n4. **`/json`** (full) — need structure/relationships the filtered tree omits.\n5. **`/html?obfuscate=true`** — need a precise selector/markup not surfaced by the a11y tree. Prefer obfuscated (compact) over full.\n6. **`/html`** (full) — last resort for raw markup/CSS; large.\n7. **`/screenshot` (clipped + low quality)** — *only* for visual confirmation or non-DOM layout. Always clip (`x,y,width,height`) and drop `quality`; never grab a full high-quality page when a region will do.\n8. **`/vnc/screenshot`** — only for native/canvas/non-DOM surfaces, or when DOM extraction genuinely fails.\n\n**Rule of thumb:** text/markup ≫ screenshots for token cost. A clipped JPEG is still an image; a `/text` call is a few hundred tokens. Act on **selectors/refs** from steps 2–6 rather than re-screenshotting to \"look again,\" and verify state changes with the cheapest read, not a fresh full screenshot.\n\n## Environment Variables\n\n| Var | Description |\n|-----|-------------|\n| `RBS_BASE_URL` | Base URL (e.g. https://rb.all-completed.com) |\n| `AC_API_KEY` | Bearer token or API key (user_id derived from token) |\n\n## Tips\n\n- **Session required** — Ensure a session exists before calling navigate/json/text/action. Create via `POST /api/sessions` (HTTP), WebSocket, or restore from stored sessions.\n- **Check live URL** — Use `GET /api/sessions/{session_id}/status` when you need the current page URL/title or last response status without fetching full page text.\n- **429 / session limit** — If create fails with 429 or WebSocket closes (limit exceeded): wait a few seconds and/or terminate the existing session with `DELETE /api/sessions/{session_id}` first, then retry.\n- **Refs from snapshot** — Use `selector` with the `ref` string (e.g. `\"e5\"`) when the action API supports ref→DOM resolution; otherwise prefer CSS selectors.\n- **Readability vs raw** — `/text` (default) strips nav/footer/ads; `?mode=raw` returns full `innerText`.\n- **Interactive filter** — `?filter=interactive` on `/json` reduces nodes by ~75% for action tasks.\n- **VNC vs DOM** — Use `/action` for selectors/refs in the page DOM. Use `/vnc/action` and `/vnc/screenshot` for pixel-level automation and UI outside the DOM.\n- **Stored sessions** — Sessions persist to S3 and are restored on reopen. The **whole browser profile** is captured (cookies, localStorage, sessionStorage, IndexedDB, **Service Workers**, Cache Storage, metadata) and restored as one consistent unit, so apps that keep their login in IndexedDB/Service Workers (e.g. Telegram Web) come back **logged in**, not just at the login page. List with `GET /api/stored-sessions`, then reopen by creating a session with the same `session_id` (HTTP/WebSocket). If `url` is not provided on connect, the saved page URL is used for redirect. Use `GET/PUT /api/stored-sessions/{session_id}` to read or update metadata (e.g. redirect URL). To move or edit individual persisted blobs without a live browser, use `GET/PUT /api/stored-sessions/{session_id}/cookies` (JSON array of cookie objects), `GET/PUT .../local-storage`, `GET/PUT .../session-storage` (both JSON objects with string keys and string values), `GET/PUT .../indexeddb` (IndexedDB snapshot object), and `GET/PUT .../cache-storage` (Cache Storage snapshot object). `DELETE /api/stored-sessions/{session_id}` wipes all persisted state for a session.\n\n## Limitations & fallbacks\n\nReal-world heavy pages (Amazon, marketplaces, dashboards) hit these. Know the fallback for each:\n\n- **Prefer text/markup extraction over screenshots** — For reading page content, `/text`, `/json` (accessibility snapshot), and `/html` are *far* more efficient than `/screenshot` or `/vnc/screenshot`: they return compact, parseable structure instead of a large base64 image, so they cost a fraction of the tokens/bandwidth and give you selectors to act on. **Default to text/markup; use screenshots only for visual verification, pixel-level layout, or canvas/`<iframe>`/non-DOM UI.**\n- **CDP frame limit (now 5 MiB)** — `/text`, `/json`, and `/html` return over a CDP WebSocket whose frame cap was raised from 1 MiB to **5 MiB**, so they now succeed on most heavy pages. If a page is still too large and you get `502` / `frame exceeds limit ... bytes`, **then** fall back: prefer narrowing first (`/text?mode=readability` (default), `/json?filter=interactive`) before resorting to a **clipped `/screenshot`** (`x,y,width,height` + lower `quality`) or `/vnc/screenshot` (framebuffer, independent of the CDP limit).\n- **Prefer `fill` over `type` for form fields** — `type` does `focus()` + `Input.insertText`; some controlled/React inputs don't register it. `fill` does select-all + insertText with real input events and is the reliable choice for text fields. Use `type` only for appending to plain inputs.\n- **To submit a form, use `submit` (not `press` Enter)** — a synthetic `press` Enter does not perform the browser's default submit. Use `{\"kind\":\"submit\",\"selector\":\"<form or a field in it>\"}`, or click the submit button by selector (selector `click` does a DOM `element.click()`).\n- **Never type secrets yourself — use `request-fill` (\"Keeper\")** — for passwords, login codes, 2FA, or any value you must not see, call `POST /api/sessions/{id}/request-fill` instead of `fill`/`type`. **This is THIS service's own built-in secure credential fill — \"Keeper\" is the user's companion app for it. It is NOT OpenClaw `secrets`/`SecretRefs` (config-backed values); do not conclude \"there's no keeper\" because OpenClaw secrets has no live prompt — this endpoint IS the live prompt.** The user supplies the value out-of-band in their Keeper app (which shows your `message` + a screenshot of the field area) and the **service** types it into the field; the value is never returned to you or logged. It's **async**: you get `{request_id, status:\"pending\"}`, then poll `GET /api/sessions/fill-status/{request_id}` (tool `get_fill_status`) until `filled` / `cancelled` / `timeout` / `error`.\n  - **Default to this for any login.** Don't ask the user to paste a password into chat. Order of preference: (1) `request-fill`; (2) if it returns **`status:\"no_keeper\"`** (no Keeper app connected), have the user sign in themselves via the **live VNC view** (you never see the password) — the session then persists logged-in; (3) only as a last resort, with the user's explicit consent, accept a value they provide.\n  - **One field:** `{\"selector\":\"input[name=password]\",\"label\":\"Password\",\"field\":\"password\",\"message\":\"Logging into Telegram to read your unread chats\"}`.\n  - **Multiple fields in one prompt (max 50):** `{\"fields\":[{\"selector\":\"#user\",\"label\":\"Username\",\"field\":\"login\"},{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}],\"message\":\"Signing in\"}`.\n  - **`field`** sets the prompt kind: `password` (default, masked) / `code` / `login` / `email` / `text`. **`length`** caps the input (1–4096); **`format`** constrains it (`email`, `numeric`/`digits`, or a regex). Set them when you know the value's shape — see docs/keeper-fill-formats.md.\n  - **One proof screenshot** is shown for the request. Pass **`screenshot_selector`** (or `screenshot_selectors`) to control what's captured — **prefer the whole `<form>`/container** (e.g. `\"screenshot_selector\":\"form#login\"`) so the user sees the form in context. Defaults to the field selectors' union if omitted.\n  - Full protocol: docs/keeper-protocol.md.\n- **Actions can report `{\"ok\": true}` without taking effect** — a `click` resolves the element box and dispatches a mouse event; if the target is off-viewport, covered by an overlay/sticky bar, or the page is a SPA mid-update, the event can be a no-op even though the call \"succeeds\". **Always verify state after any state-changing action** (re-screenshot, or re-check the relevant page e.g. the cart) rather than trusting `ok`. Prefer **selector-based** clicks over bare `x,y`; coordinate clicks on cart/checkout pages may also be blocked by host safety policy. If a selector click no-ops, try scrolling it into view first (`{\"kind\":\"scroll\"}`) or click via a screenshot-derived coordinate.\n- **Session lifetime & reopening** — A session with **no live viewer/client** (`active_ws_connections: 0`, e.g. one created purely via the API/MCP) is reclaimed after ~5 minutes idle, and **any service restart/deploy drops all live sessions**. The stored state survives, so **to reopen/resume, just create a session with the SAME `session_id`** — it relaunches the browser and restores the full profile (you stay logged in). List resumable ids with `GET /api/stored-sessions`. For multi-step tasks: keep acting (each call resets idle), avoid long external pauses, and `ping` between steps.\n- **Connecting/disconnecting (incl. CDP/Playwright) does not destroy the session** — opening a WebSocket/CDP connection (e.g. `connectOverCDP`) and closing it leaves the session running; it's reclaimed only by the idle timeout or an explicit `DELETE`. So a client may connect, work, disconnect, and reconnect later to the same live session without losing it.\n- **Encrypted sessions reopen the same way** — if a session was created with `encrypt_with_api_key`, you reopen it identically: create with the same `session_id` using the same API-key/OAuth auth you use for every call. The encryption key is derived **server-side from your token** — you never see, pass, or \"handle\" it. Don't avoid reopening an encrypted session; it is not a special case.\n\nFile v1.0.5:_meta.json\n\n{\n  \"ownerId\": \"kn730fwwv9rb4chrcwkdyx1pgx826v25\",\n  \"slug\": \"remote-browser\",\n  \"version\": \"1.0.5\",\n  \"publishedAt\": 1781776234680\n}\n\nFile v1.0.5:skill-card.md\n\n## Description: <br>\nControl a remote Chrome browser via HTTP API for authorized web automation, form filling, navigation, page inspection, screenshots, text extraction, DOM actions, and VNC actions. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[vasyaod](https://clawhub.ai/user/vasyaod) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and AI agents use this skill to operate a remote browser session for authorized web automation, including navigation, page inspection, form interaction, screenshots, and VNC-level fallback control. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Persistent remote browser profiles can retain authenticated sessions and sensitive page data. <br>\nMitigation: Review before use on logged-in accounts or sensitive sites, prefer ephemeral sessions where possible, and delete stored sessions when finished. <br>\nRisk: Browser automation can submit purchases, account changes, or other irreversible actions. <br>\nMitigation: Require confirmation before allowing an agent to submit purchases, account changes, or other high-impact actions. <br>\nRisk: Passwords or 2FA codes may be exposed if users paste credentials directly into an agent conversation. <br>\nMitigation: Use the documented secure request-fill flow for passwords and 2FA; if unavailable, have the user sign in through live VNC instead of asking for pasted credentials. <br>\n\n\n## Reference(s): <br>\n- [ClawHub Skill Page](https://clawhub.ai/vasyaod/remote-browser) <br>\n- [Publisher Profile](https://clawhub.ai/user/vasyaod) <br>\n- [Remote Browser Service API Base](https://rb.all-completed.com) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with HTTP API examples and bash code blocks] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Guidance covers active browser sessions, authenticated API calls, DOM and VNC actions, screenshots, stored sessions, and credential-fill handling.] <br>\n\n## Skill Version(s): <br>\n1.0.5 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.0.4: 3 files, 10149 bytes\n\nFiles: skill-card.md (2468b), SKILL.md (24773b), _meta.json (133b)\n\nFile v1.0.4:SKILL.md\n\n---\nname: remote-browser-service\ndescription: >\n  Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation,\n  form filling, navigation, and page inspection on sites the user owns or has permission to access.\n  Exposes the accessibility tree, text extraction, Chrome screenshots, VNC-native screenshots,\n  DOM actions, and VNC actions — optimized for AI agents. Requires an active browser session\n  (created via HTTP or WebSocket).\nmetadata:\n  openclaw:\n    emoji: \"🌐\"\n    requires:\n      env:\n        - name: AC_API_KEY\n          secret: true\n          optional: true\n          description: \"Bearer token or API key for auth (user_id derived from token)\"\n---\n\n# Remote Browser Service\n\nBrowser control for AI agents via HTTP API. Supports both DOM-oriented automation\nand remote-desktop/VNC control when you need the actual framebuffer.\n\n## Index\n\n- [Setup](#setup)\n- [Core Workflow](#core-workflow)\n- [API Reference](#api-reference)\n- [Screenshot](#screenshot)\n- [VNC interface](#vnc-interface)\n- [VNC screenshot](#vnc-screenshot)\n- [Act on elements](#act-on-elements)\n- [VNC action](#vnc-action)\n- [HTML snapshot](#html-snapshot)\n- [Token Cost Guide](#token-cost-guide)\n- [Limitations & fallbacks](#limitations--fallbacks)\n- [Environment Variables](#environment-variables)\n- [Tips](#tips)\n\n## Setup\n\nEnsure you have an active session:\n\n1. **Create session** — `POST /api/sessions` (HTTP, no WebSocket), or open WebSocket to `/ws/{session_id}` (DevTools CDP), or run from UI. Optional `url` in body (HTTP) or query (WS) to navigate immediately.\n2. **Or restore** — Use stored session from `GET /api/stored-sessions`\n3. **Auth** — Pass `Authorization: Bearer <token>` or `X-API-Key`, or `?access_token=<token>`\n\nBase URL: `https://rb.all-completed.com` (or `RBS_BASE_URL`). Replace `{session_id}` in examples. User ID is derived from the token.\n\n## Core Workflow\n\n1. **Navigate** to a URL\n2. **Snapshot** the accessibility tree (get refs) — `GET .../json`\n3. **Act** on refs or selectors (click, type, fill, press)\n4. **Snapshot** again to see results\n\nFor visual or OS-level flows, use the VNC path instead:\n\n1. **Open VNC interface** — `GET /users/{user_id}/vnc/{session_id}` when you want a live noVNC view\n2. **Capture VNC framebuffer** — `GET .../vnc/screenshot`\n3. **Send VNC input** — `POST .../vnc/action` with coordinates or keys\n4. **Capture again** to verify pixel-level results\n\nRefs (`e0`, `e1`, …) from `/json` can be used with `/action` via `selector` (use `ref` as selector for `e5` → `\"e5\"` maps to role/name; for now use CSS `selector`).\n\nSupported actions by mode:\n\n| Mode               | Kind     | Example                                                     |\n|--------------------|----------|-------------------------------------------------------------|\n| DOM (`/action`)    | `click`  | `{\"kind\":\"click\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `tap`    | `{\"kind\":\"tap\",\"selector\":\"button.submit\"}`                 |\n| DOM (`/action`)    | `type`   | `{\"kind\":\"type\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `fill`   | `{\"kind\":\"fill\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `press`  | `{\"kind\":\"press\",\"key\":\"Enter\"}`                            |\n| DOM (`/action`)    | `focus`  | `{\"kind\":\"focus\",\"selector\":\"input[name=search]\"}`          |\n| DOM (`/action`)    | `hover`  | `{\"kind\":\"hover\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `select` | `{\"kind\":\"select\",\"selector\":\"select\",\"value\":\"option-1\"}`  |\n| DOM (`/action`)    | `scroll` | `{\"kind\":\"scroll\",\"scrollY\":800}`                           |\n| DOM (`/action`)    | `submit` | `{\"kind\":\"submit\",\"selector\":\"#nav-search-form\"}` (or a field within the form) |\n| Secrets (`/request-fill`) | — | `{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}` — user fills it in the Keeper app; value never seen by the agent |\n| VNC (`/vnc/action`) | `move`   | `{\"kind\":\"move\",\"x\":320,\"y\":240}`                           |\n| VNC (`/vnc/action`) | `click`  | `{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}` |\n| VNC (`/vnc/action`) | `type`   | `{\"kind\":\"type\",\"text\":\"hello world\"}`                      |\n| VNC (`/vnc/action`) | `press`  | `{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}`                      |\n| VNC (`/vnc/action`) | `scroll` | `{\"kind\":\"scroll\",\"x\":320,\"y\":240,\"direction\":\"down\",\"repeat\":3}` |\n\n## API Reference\n\n### Create session (HTTP)\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n# Optional: {\"session_id\": \"my-session\", \"url\": \"https://example.com\"}\n# Fork from stored session: {\"session_id\": \"my-fork\", \"from\": \"original-session\"}\n# Ephemeral (start from metadata/fork but don't save): {\"ephemeral\": true}\n```\n\nSessions idle for 5 min are closed. Use `POST .../ping` to keep alive.\n\nMaximum 1 concurrent session per user. If creation returns 429 or WebSocket closes with a limit error: **wait a bit** (previous session may still be shutting down) **and/or close the previous session** via `DELETE /api/sessions/{session_id}` before retrying.\n\n### List sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n### Session status\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns live session state plus current page metadata:\n\n```json\n{\n  \"session_id\": \"session-123\",\n  \"created_at\": \"2026-02-12T10:00:00\",\n  \"active_ws_connections\": 1,\n  \"status\": \"ready\",\n  \"last_error\": null,\n  \"current_url\": \"https://example.com/page\",\n  \"page_title\": \"Example Domain\",\n  \"last_status_code\": 200\n}\n```\n\nHTTP status codes:\n\n- `200` - Session found; manager status returned, with live page metadata when available\n- `404` - Session not found for the authenticated user\n- `503` - Service not initialized\n\n`last_status_code` is the browser's last navigation response code when Chrome exposes it through Navigation Timing. If it is not available yet, the field is `null`.\n\n### List stored sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/stored-sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{sessions: [...], count}`. Connect via WebSocket to `/ws/{session_id}` to resume.\n\n### Navigate\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\"}'\n\n# With timeout (seconds)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\", \"timeout\": 60}'\n```\n\n### Set location\n\n```bash\n# Override geolocation for the page (e.g. for location-aware sites)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 37.7749, \"longitude\": -122.4194}'\n\n# With accuracy (meters)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 51.5074, \"longitude\": -0.1278, \"accuracy\": 50}'\n```\n\n### Image (download by selector)\n\n```bash\n# Capture a single element (e.g. image) by CSS selector\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img.hero\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o image.jpg\n\n# With quality, raw binary (selector=#banner for id)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img&quality=90&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o element.jpg\n```\n\nUse `selector` (CSS) or `ref` (from snapshot). Returns JPEG of the element's bounding box.\n\n### Snapshot (accessibility tree)\n\n```bash\n# Full tree\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Interactive elements only (buttons, links, inputs) — much smaller\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?filter=interactive\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Limit depth\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?depth=5\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{nodes: [{ref, role, name, depth, value?, disabled?, focused?, nodeId?}], count}`.\n\n### Extract text\n\n```bash\n# Readability mode (default) — strips nav/footer/ads\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw innerText\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text?mode=raw\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{url, title, text}`. Cheapest option (~800 tokens for most pages).\n\n### Screenshot\n\n```bash\n# JSON with base64\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw JPEG bytes\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# With quality (1-100)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?quality=50&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# Region capture (offset x,y and width,height in CSS pixels)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.jpg\n```\n\nUse this when Chrome DevTools rendering is enough. If you need browser chrome,\nOS dialogs, permission prompts, or the exact remote desktop pixels, use\n`/vnc/screenshot` instead.\n\n### VNC interface\n\n```bash\n# Built-in noVNC client page for a session\nopen \"https://rb.all-completed.com/users/{user_id}/vnc/{session_id}\"\n\n# Under the hood the page connects to the VNC websocket proxy\n# /users/{user_id}/vnc/ws/{session_id}\n```\n\nUse the VNC interface when you need a live remote-desktop view of the session\ninstead of DOM snapshots.\n\n### VNC screenshot\n\n```bash\n# Raw PNG bytes from the VNC framebuffer\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screen.png\n\n# Cropped framebuffer region\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.png\n```\n\nUnlike `/screenshot`, this captures the VNC framebuffer directly. Use it for\nbrowser chrome, native permission prompts, OS-level dialogs, or anything only\nvisible in the remote desktop.\n\n### Page size\n\n```bash\n# Get page content dimensions (use with screenshot clip)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/page-size\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{width, height}` in CSS pixels.\n\n### Act on elements\n\n```bash\n# Click by selector\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"selector\": \"button.submit\"}'\n\n# Click by coordinates (viewport x,y)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"x\": 100, \"y\": 200}'\n\n# Type into element (focus + insertText)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"type\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Fill (set value directly)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"fill\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Press a key\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"press\", \"key\": \"Enter\"}'\n# Press Enter in a specific input: -d '{\"kind\": \"press\", \"key\": \"Enter\", \"selector\": \"input#search\"}'\n\n# Focus, hover, select, scroll\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"focus\", \"selector\": \"input[name=search]\"}'\n\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"scroll\", \"scrollY\": 800}'\n```\n\n**Action kinds:** `click`, `type`, `fill`, `press`, `focus`, `hover`, `select`, `scroll`. Use `selector` (CSS) or `ref` (from snapshot). For `click` you can use `x` and `y` (viewport coordinates) instead of selector. For `fill`, the server focuses the field, `select()` only if the field already has text (then `Input.insertText` replaces), otherwise focuses and inserts like `type`—controlled inputs (e.g. React) update reliably. For `press` use `key` (e.g. `Enter`, `Tab`, `Escape`, `Space`, `ArrowUp`); optional `selector` focuses element first.\n\n### VNC action\n\n```bash\n# Move mouse\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"move\",\"x\":320,\"y\":240}'\n\n# Click at framebuffer coordinates\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}'\n\n# Press keys directly over VNC\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}'\n```\n\n**VNC action kinds:** `move`, `click`, `type`, `press`, `scroll`.\n\nThese actions are framebuffer-oriented and do not use DOM selectors. Prefer them\nwhen DOM automation cannot see or control the target UI.\n\n### HTML snapshot\n\n```bash\n# Full DOM with inlined CSS (opens in browser)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/html\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n## Token Cost Guide\n\n| Method | Typical tokens | When to use |\n|--------|----------------|-------------|\n| `/status` | ~50 | Just the current URL / title / HTTP status |\n| `/text` (readability) | ~800 | Reading page content |\n| `/text?mode=raw` | ~2K–8K | Content readability strips (hidden labels, etc.) |\n| `/json?filter=interactive` | ~3,600 | Finding buttons/links/inputs to act on (+ refs) |\n| `/json` (full a11y tree) | ~10,500 | Full structure / element relationships |\n| `/html?obfuscate=true` (simple markup) | ~10K–40K | Need exact CSS selectors / markup the a11y tree lacks |\n| `/html` (full markup) | very large | Raw DOM + inlined CSS; rarely needed, may exceed the 5 MiB cap |\n| `/image?selector=` | ~1K (vision) | Capture a single element / download an image |\n| `/screenshot` (clipped, low `quality`) | ~1K–2K (vision) | Visual check of one region |\n| `/screenshot` (full page) | ~2K+ (vision) | Whole-page layout / visual verification |\n| `/vnc/screenshot` | ~2K+ (vision) | Non-DOM/native UI, canvas, or when DOM tools fail |\n\n**Decision order — use the *cheapest* tool that answers your question, escalate only if it doesn't:**\n\n1. **`/status`** — only need where you are (URL/title/status).\n2. **`/text`** — reading/extracting content. (`?mode=raw` if readability hides what you need.)\n3. **`/json?filter=interactive`** — locating things to click/type; returns refs to act on.\n4. **`/json`** (full) — need structure/relationships the filtered tree omits.\n5. **`/html?obfuscate=true`** — need a precise selector/markup not surfaced by the a11y tree. Prefer obfuscated (compact) over full.\n6. **`/html`** (full) — last resort for raw markup/CSS; large.\n7. **`/screenshot` (clipped + low quality)** — *only* for visual confirmation or non-DOM layout. Always clip (`x,y,width,height`) and drop `quality`; never grab a full high-quality page when a region will do.\n8. **`/vnc/screenshot`** — only for native/canvas/non-DOM surfaces, or when DOM extraction genuinely fails.\n\n**Rule of thumb:** text/markup ≫ screenshots for token cost. A clipped JPEG is still an image; a `/text` call is a few hundred tokens. Act on **selectors/refs** from steps 2–6 rather than re-screenshotting to \"look again,\" and verify state changes with the cheapest read, not a fresh full screenshot.\n\n## Environment Variables\n\n| Var | Description |\n|-----|-------------|\n| `RBS_BASE_URL` | Base URL (e.g. https://rb.all-completed.com) |\n| `AC_API_KEY` | Bearer token or API key (user_id derived from token) |\n\n## Tips\n\n- **Session required** — Ensure a session exists before calling navigate/json/text/action. Create via `POST /api/sessions` (HTTP), WebSocket, or restore from stored sessions.\n- **Check live URL** — Use `GET /api/sessions/{session_id}/status` when you need the current page URL/title or last response status without fetching full page text.\n- **429 / session limit** — If create fails with 429 or WebSocket closes (limit exceeded): wait a few seconds and/or terminate the existing session with `DELETE /api/sessions/{session_id}` first, then retry.\n- **Refs from snapshot** — Use `selector` with the `ref` string (e.g. `\"e5\"`) when the action API supports ref→DOM resolution; otherwise prefer CSS selectors.\n- **Readability vs raw** — `/text` (default) strips nav/footer/ads; `?mode=raw` returns full `innerText`.\n- **Interactive filter** — `?filter=interactive` on `/json` reduces nodes by ~75% for action tasks.\n- **VNC vs DOM** — Use `/action` for selectors/refs in the page DOM. Use `/vnc/action` and `/vnc/screenshot` for pixel-level automation and UI outside the DOM.\n- **Stored sessions** — Sessions persist to S3 and are restored on reopen. The **whole browser profile** is captured (cookies, localStorage, sessionStorage, IndexedDB, **Service Workers**, Cache Storage, metadata) and restored as one consistent unit, so apps that keep their login in IndexedDB/Service Workers (e.g. Telegram Web) come back **logged in**, not just at the login page. List with `GET /api/stored-sessions`, then reopen by creating a session with the same `session_id` (HTTP/WebSocket). If `url` is not provided on connect, the saved page URL is used for redirect. Use `GET/PUT /api/stored-sessions/{session_id}` to read or update metadata (e.g. redirect URL). To move or edit individual persisted blobs without a live browser, use `GET/PUT /api/stored-sessions/{session_id}/cookies` (JSON array of cookie objects), `GET/PUT .../local-storage`, `GET/PUT .../session-storage` (both JSON objects with string keys and string values), `GET/PUT .../indexeddb` (IndexedDB snapshot object), and `GET/PUT .../cache-storage` (Cache Storage snapshot object). `DELETE /api/stored-sessions/{session_id}` wipes all persisted state for a session.\n\n## Limitations & fallbacks\n\nReal-world heavy pages (Amazon, marketplaces, dashboards) hit these. Know the fallback for each:\n\n- **Prefer text/markup extraction over screenshots** — For reading page content, `/text`, `/json` (accessibility snapshot), and `/html` are *far* more efficient than `/screenshot` or `/vnc/screenshot`: they return compact, parseable structure instead of a large base64 image, so they cost a fraction of the tokens/bandwidth and give you selectors to act on. **Default to text/markup; use screenshots only for visual verification, pixel-level layout, or canvas/`<iframe>`/non-DOM UI.**\n- **CDP frame limit (now 5 MiB)** — `/text`, `/json`, and `/html` return over a CDP WebSocket whose frame cap was raised from 1 MiB to **5 MiB**, so they now succeed on most heavy pages. If a page is still too large and you get `502` / `frame exceeds limit ... bytes`, **then** fall back: prefer narrowing first (`/text?mode=readability` (default), `/json?filter=interactive`) before resorting to a **clipped `/screenshot`** (`x,y,width,height` + lower `quality`) or `/vnc/screenshot` (framebuffer, independent of the CDP limit).\n- **Prefer `fill` over `type` for form fields** — `type` does `focus()` + `Input.insertText`; some controlled/React inputs don't register it. `fill` does select-all + insertText with real input events and is the reliable choice for text fields. Use `type` only for appending to plain inputs.\n- **To submit a form, use `submit` (not `press` Enter)** — a synthetic `press` Enter does not perform the browser's default submit. Use `{\"kind\":\"submit\",\"selector\":\"<form or a field in it>\"}`, or click the submit button by selector (selector `click` does a DOM `element.click()`).\n- **Never type secrets yourself — use `request-fill`** — for passwords, login codes, 2FA, or any value you must not see, call `POST /api/sessions/{id}/request-fill` instead of `fill`/`type`. The user supplies the value out-of-band in their Keeper desktop app (which shows your `message` + a screenshot of the field area) and the **service** types it into the field; the value is never returned to you or logged. It's **async**: you get `{request_id, status:\"pending\"}` (or `no_keeper`), then poll `GET /api/sessions/fill-status/{request_id}` (tool `get_fill_status`) until `filled` / `cancelled` / `timeout` / `error`.\n  - **One field:** `{\"selector\":\"input[name=password]\",\"label\":\"Password\",\"field\":\"password\",\"message\":\"Logging into Telegram to read your unread chats\"}`.\n  - **Multiple fields in one prompt (max 50):** `{\"fields\":[{\"selector\":\"#user\",\"label\":\"Username\",\"field\":\"login\"},{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}],\"message\":\"Signing in\"}`.\n  - **`field`** sets the prompt kind: `password` (default, masked) / `code` / `login` / `email` / `text`. **`length`** caps the input (1–4096); **`format`** constrains it (`email`, `numeric`/`digits`, or a regex). Set them when you know the value's shape — see docs/keeper-fill-formats.md.\n  - **One proof screenshot** is shown for the request. Pass **`screenshot_selector`** (or `screenshot_selectors`) to control what's captured — **prefer the whole `<form>`/container** (e.g. `\"screenshot_selector\":\"form#login\"`) so the user sees the form in context. Defaults to the field selectors' union if omitted.\n  - Full protocol: docs/keeper-protocol.md.\n- **Actions can report `{\"ok\": true}` without taking effect** — a `click` resolves the element box and dispatches a mouse event; if the target is off-viewport, covered by an overlay/sticky bar, or the page is a SPA mid-update, the event can be a no-op even though the call \"succeeds\". **Always verify state after any state-changing action** (re-screenshot, or re-check the relevant page e.g. the cart) rather than trusting `ok`. Prefer **selector-based** clicks over bare `x,y`; coordinate clicks on cart/checkout pages may also be blocked by host safety policy. If a selector click no-ops, try scrolling it into view first (`{\"kind\":\"scroll\"}`) or click via a screenshot-derived coordinate.\n- **Session lifetime & reopening** — A session with **no live viewer/client** (`active_ws_connections: 0`, e.g. one created purely via the API/MCP) is reclaimed after ~5 minutes idle, and **any service restart/deploy drops all live sessions**. The stored state survives, so **to reopen/resume, just create a session with the SAME `session_id`** — it relaunches the browser and restores the full profile (you stay logged in). List resumable ids with `GET /api/stored-sessions`. For multi-step tasks: keep acting (each call resets idle), avoid long external pauses, and `ping` between steps.\n- **Connecting/disconnecting (incl. CDP/Playwright) does not destroy the session** — opening a WebSocket/CDP connection (e.g. `connectOverCDP`) and closing it leaves the session running; it's reclaimed only by the idle timeout or an explicit `DELETE`. So a client may connect, work, disconnect, and reconnect later to the same live session without losing it.\n- **Encrypted sessions reopen the same way** — if a session was created with `encrypt_with_api_key`, you reopen it identically: create with the same `session_id` using the same API-key/OAuth auth you use for every call. The encryption key is derived **server-side from your token** — you never see, pass, or \"handle\" it. Don't avoid reopening an encrypted session; it is not a special case.\n\nFile v1.0.4:_meta.json\n\n{\n  \"ownerId\": \"kn730fwwv9rb4chrcwkdyx1pgx826v25\",\n  \"slug\": \"remote-browser\",\n  \"version\": \"1.0.4\",\n  \"publishedAt\": 1781775066842\n}\n\nFile v1.0.4:skill-card.md\n\n## Description: <br>\nControls a remote Chrome browser through an HTTP API for permitted web automation, form filling, navigation, page inspection, screenshots, text extraction, DOM actions, and VNC actions. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[vasyaod](https://clawhub.ai/user/vasyaod) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agents use this skill to operate a remote browser session on sites they own or have permission to access. It supports DOM-oriented automation, visual verification, and remote-desktop workflows when page structure alone is insufficient. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can retain and manipulate authenticated browser state, including cookies and site storage. <br>\nMitigation: Use isolated sessions for sensitive work, clear stored sessions when finished, and enable profile persistence only when it is explicitly needed. <br>\nRisk: Remote browser actions can change website state through clicks, form fills, navigation, and VNC input. <br>\nMitigation: Operate only on sites the user owns or has permission to access, and verify state-changing actions with a status, text, snapshot, or screenshot check. <br>\nRisk: The service depends on bearer-token or API-key authentication for browser access. <br>\nMitigation: Provide credentials only through secret environment handling and avoid exposing tokens in prompts, logs, examples, or generated commands. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/vasyaod/remote-browser) <br>\n- [Remote Browser Service API](https://rb.all-completed.com) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with HTTP API examples and shell commands] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May include browser session identifiers, URLs, selectors, screenshots, text extracts, accessibility snapshots, and action payloads.] <br>\n\n## Skill Version(s): <br>\n1.0.4 (source: server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.0.3: 3 files, 10105 bytes\n\nFiles: skill-card.md (2365b), SKILL.md (24773b), _meta.json (133b)\n\nFile v1.0.3:SKILL.md\n\n---\nname: remote-browser-service\ndescription: >\n  Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation,\n  form filling, navigation, and page inspection on sites the user owns or has permission to access.\n  Exposes the accessibility tree, text extraction, Chrome screenshots, VNC-native screenshots,\n  DOM actions, and VNC actions — optimized for AI agents. Requires an active browser session\n  (created via HTTP or WebSocket).\nmetadata:\n  openclaw:\n    emoji: \"🌐\"\n    requires:\n      env:\n        - name: AC_API_KEY\n          secret: true\n          optional: true\n          description: \"Bearer token or API key for auth (user_id derived from token)\"\n---\n\n# Remote Browser Service\n\nBrowser control for AI agents via HTTP API. Supports both DOM-oriented automation\nand remote-desktop/VNC control when you need the actual framebuffer.\n\n## Index\n\n- [Setup](#setup)\n- [Core Workflow](#core-workflow)\n- [API Reference](#api-reference)\n- [Screenshot](#screenshot)\n- [VNC interface](#vnc-interface)\n- [VNC screenshot](#vnc-screenshot)\n- [Act on elements](#act-on-elements)\n- [VNC action](#vnc-action)\n- [HTML snapshot](#html-snapshot)\n- [Token Cost Guide](#token-cost-guide)\n- [Limitations & fallbacks](#limitations--fallbacks)\n- [Environment Variables](#environment-variables)\n- [Tips](#tips)\n\n## Setup\n\nEnsure you have an active session:\n\n1. **Create session** — `POST /api/sessions` (HTTP, no WebSocket), or open WebSocket to `/ws/{session_id}` (DevTools CDP), or run from UI. Optional `url` in body (HTTP) or query (WS) to navigate immediately.\n2. **Or restore** — Use stored session from `GET /api/stored-sessions`\n3. **Auth** — Pass `Authorization: Bearer <token>` or `X-API-Key`, or `?access_token=<token>`\n\nBase URL: `https://rb.all-completed.com` (or `RBS_BASE_URL`). Replace `{session_id}` in examples. User ID is derived from the token.\n\n## Core Workflow\n\n1. **Navigate** to a URL\n2. **Snapshot** the accessibility tree (get refs) — `GET .../json`\n3. **Act** on refs or selectors (click, type, fill, press)\n4. **Snapshot** again to see results\n\nFor visual or OS-level flows, use the VNC path instead:\n\n1. **Open VNC interface** — `GET /users/{user_id}/vnc/{session_id}` when you want a live noVNC view\n2. **Capture VNC framebuffer** — `GET .../vnc/screenshot`\n3. **Send VNC input** — `POST .../vnc/action` with coordinates or keys\n4. **Capture again** to verify pixel-level results\n\nRefs (`e0`, `e1`, …) from `/json` can be used with `/action` via `selector` (use `ref` as selector for `e5` → `\"e5\"` maps to role/name; for now use CSS `selector`).\n\nSupported actions by mode:\n\n| Mode               | Kind     | Example                                                     |\n|--------------------|----------|-------------------------------------------------------------|\n| DOM (`/action`)    | `click`  | `{\"kind\":\"click\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `tap`    | `{\"kind\":\"tap\",\"selector\":\"button.submit\"}`                 |\n| DOM (`/action`)    | `type`   | `{\"kind\":\"type\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `fill`   | `{\"kind\":\"fill\",\"selector\":\"#email\",\"text\":\"user@example.com\"}` |\n| DOM (`/action`)    | `press`  | `{\"kind\":\"press\",\"key\":\"Enter\"}`                            |\n| DOM (`/action`)    | `focus`  | `{\"kind\":\"focus\",\"selector\":\"input[name=search]\"}`          |\n| DOM (`/action`)    | `hover`  | `{\"kind\":\"hover\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `select` | `{\"kind\":\"select\",\"selector\":\"select\",\"value\":\"option-1\"}`  |\n| DOM (`/action`)    | `scroll` | `{\"kind\":\"scroll\",\"scrollY\":800}`                           |\n| DOM (`/action`)    | `submit` | `{\"kind\":\"submit\",\"selector\":\"#nav-search-form\"}` (or a field within the form) |\n| Secrets (`/request-fill`) | — | `{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}` — user fills it in the Keeper app; value never seen by the agent |\n| VNC (`/vnc/action`) | `move`   | `{\"kind\":\"move\",\"x\":320,\"y\":240}`                           |\n| VNC (`/vnc/action`) | `click`  | `{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}` |\n| VNC (`/vnc/action`) | `type`   | `{\"kind\":\"type\",\"text\":\"hello world\"}`                      |\n| VNC (`/vnc/action`) | `press`  | `{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}`                      |\n| VNC (`/vnc/action`) | `scroll` | `{\"kind\":\"scroll\",\"x\":320,\"y\":240,\"direction\":\"down\",\"repeat\":3}` |\n\n## API Reference\n\n### Create session (HTTP)\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n# Optional: {\"session_id\": \"my-session\", \"url\": \"https://example.com\"}\n# Fork from stored session: {\"session_id\": \"my-fork\", \"from\": \"original-session\"}\n# Ephemeral (start from metadata/fork but don't save): {\"ephemeral\": true}\n```\n\nSessions idle for 5 min are closed. Use `POST .../ping` to keep alive.\n\nMaximum 1 concurrent session per user. If creation returns 429 or WebSocket closes with a limit error: **wait a bit** (previous session may still be shutting down) **and/or close the previous session** via `DELETE /api/sessions/{session_id}` before retrying.\n\n### List sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n### Session status\n\n```bash\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns live session state plus current page metadata:\n\n```json\n{\n  \"session_id\": \"session-123\",\n  \"created_at\": \"2026-02-12T10:00:00\",\n  \"active_ws_connections\": 1,\n  \"status\": \"ready\",\n  \"last_error\": null,\n  \"current_url\": \"https://example.com/page\",\n  \"page_title\": \"Example Domain\",\n  \"last_status_code\": 200\n}\n```\n\nHTTP status codes:\n\n- `200` - Session found; manager status returned, with live page metadata when available\n- `404` - Session not found for the authenticated user\n- `503` - Service not initialized\n\n`last_status_code` is the browser's last navigation response code when Chrome exposes it through Navigation Timing. If it is not available yet, the field is `null`.\n\n### List stored sessions\n\n```bash\ncurl \"https://rb.all-completed.com/api/stored-sessions\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{sessions: [...], count}`. Connect via WebSocket to `/ws/{session_id}` to resume.\n\n### Navigate\n\n```bash\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\"}'\n\n# With timeout (seconds)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/navigate\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\", \"timeout\": 60}'\n```\n\n### Set location\n\n```bash\n# Override geolocation for the page (e.g. for location-aware sites)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 37.7749, \"longitude\": -122.4194}'\n\n# With accuracy (meters)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/location\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"latitude\": 51.5074, \"longitude\": -0.1278, \"accuracy\": 50}'\n```\n\n### Image (download by selector)\n\n```bash\n# Capture a single element (e.g. image) by CSS selector\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img.hero\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o image.jpg\n\n# With quality, raw binary (selector=#banner for id)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/image?selector=img&quality=90&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o element.jpg\n```\n\nUse `selector` (CSS) or `ref` (from snapshot). Returns JPEG of the element's bounding box.\n\n### Snapshot (accessibility tree)\n\n```bash\n# Full tree\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Interactive elements only (buttons, links, inputs) — much smaller\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?filter=interactive\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Limit depth\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/json?depth=5\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{nodes: [{ref, role, name, depth, value?, disabled?, focused?, nodeId?}], count}`.\n\n### Extract text\n\n```bash\n# Readability mode (default) — strips nav/footer/ads\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw innerText\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/text?mode=raw\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{url, title, text}`. Cheapest option (~800 tokens for most pages).\n\n### Screenshot\n\n```bash\n# JSON with base64\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot\" \\\n  -H \"Authorization: Bearer <token>\"\n\n# Raw JPEG bytes\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# With quality (1-100)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?quality=50&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screenshot.jpg\n\n# Region capture (offset x,y and width,height in CSS pixels)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.jpg\n```\n\nUse this when Chrome DevTools rendering is enough. If you need browser chrome,\nOS dialogs, permission prompts, or the exact remote desktop pixels, use\n`/vnc/screenshot` instead.\n\n### VNC interface\n\n```bash\n# Built-in noVNC client page for a session\nopen \"https://rb.all-completed.com/users/{user_id}/vnc/{session_id}\"\n\n# Under the hood the page connects to the VNC websocket proxy\n# /users/{user_id}/vnc/ws/{session_id}\n```\n\nUse the VNC interface when you need a live remote-desktop view of the session\ninstead of DOM snapshots.\n\n### VNC screenshot\n\n```bash\n# Raw PNG bytes from the VNC framebuffer\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o screen.png\n\n# Cropped framebuffer region\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/screenshot?x=0&y=0&width=800&height=600&raw=true\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -o region.png\n```\n\nUnlike `/screenshot`, this captures the VNC framebuffer directly. Use it for\nbrowser chrome, native permission prompts, OS-level dialogs, or anything only\nvisible in the remote desktop.\n\n### Page size\n\n```bash\n# Get page content dimensions (use with screenshot clip)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/page-size\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\nReturns `{width, height}` in CSS pixels.\n\n### Act on elements\n\n```bash\n# Click by selector\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"selector\": \"button.submit\"}'\n\n# Click by coordinates (viewport x,y)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"click\", \"x\": 100, \"y\": 200}'\n\n# Type into element (focus + insertText)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"type\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Fill (set value directly)\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"fill\", \"selector\": \"#email\", \"text\": \"user@example.com\"}'\n\n# Press a key\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"press\", \"key\": \"Enter\"}'\n# Press Enter in a specific input: -d '{\"kind\": \"press\", \"key\": \"Enter\", \"selector\": \"input#search\"}'\n\n# Focus, hover, select, scroll\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"focus\", \"selector\": \"input[name=search]\"}'\n\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\": \"scroll\", \"scrollY\": 800}'\n```\n\n**Action kinds:** `click`, `type`, `fill`, `press`, `focus`, `hover`, `select`, `scroll`. Use `selector` (CSS) or `ref` (from snapshot). For `click` you can use `x` and `y` (viewport coordinates) instead of selector. For `fill`, the server focuses the field, `select()` only if the field already has text (then `Input.insertText` replaces), otherwise focuses and inserts like `type`—controlled inputs (e.g. React) update reliably. For `press` use `key` (e.g. `Enter`, `Tab`, `Escape`, `Space`, `ArrowUp`); optional `selector` focuses element first.\n\n### VNC action\n\n```bash\n# Move mouse\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"move\",\"x\":320,\"y\":240}'\n\n# Click at framebuffer coordinates\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"click\",\"x\":320,\"y\":240,\"button\":\"left\",\"repeat\":1}'\n\n# Press keys directly over VNC\ncurl -X POST \"https://rb.all-completed.com/api/sessions/{session_id}/vnc/action\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"kind\":\"press\",\"keys\":[\"Ctrl\",\"l\"]}'\n```\n\n**VNC action kinds:** `move`, `click`, `type`, `press`, `scroll`.\n\nThese actions are framebuffer-oriented and do not use DOM selectors. Prefer them\nwhen DOM automation cannot see or control the target UI.\n\n### HTML snapshot\n\n```bash\n# Full DOM with inlined CSS (opens in browser)\ncurl \"https://rb.all-completed.com/api/sessions/{session_id}/html\" \\\n  -H \"Authorization: Bearer <token>\"\n```\n\n## Token Cost Guide\n\n| Method | Typical tokens | When to use |\n|--------|----------------|-------------|\n| `/status` | ~50 | Just the current URL / title / HTTP status |\n| `/text` (readability) | ~800 | Reading page content |\n| `/text?mode=raw` | ~2K–8K | Content readability strips (hidden labels, etc.) |\n| `/json?filter=interactive` | ~3,600 | Finding buttons/links/inputs to act on (+ refs) |\n| `/json` (full a11y tree) | ~10,500 | Full structure / element relationships |\n| `/html?obfuscate=true` (simple markup) | ~10K–40K | Need exact CSS selectors / markup the a11y tree lacks |\n| `/html` (full markup) | very large | Raw DOM + inlined CSS; rarely needed, may exceed the 5 MiB cap |\n| `/image?selector=` | ~1K (vision) | Capture a single element / download an image |\n| `/screenshot` (clipped, low `quality`) | ~1K–2K (vision) | Visual check of one region |\n| `/screenshot` (full page) | ~2K+ (vision) | Whole-page layout / visual verification |\n| `/vnc/screenshot` | ~2K+ (vision) | Non-DOM/native UI, canvas, or when DOM tools fail |\n\n**Decision order — use the *cheapest* tool that answers your question, escalate only if it doesn't:**\n\n1. **`/status`** — only need where you are (URL/title/status).\n2. **`/text`** — reading/extracting content. (`?mode=raw` if readability hides what you need.)\n3. **`/json?filter=interactive`** — locating things to click/type; returns refs to act on.\n4. **`/json`** (full) — need structure/relationships the filtered tree omits.\n5. **`/html?obfuscate=true`** — need a precise selector/markup not surfaced by the a11y tree. Prefer obfuscated (compact) over full.\n6. **`/html`** (full) — last resort for raw markup/CSS; large.\n7. **`/screenshot` (clipped + low quality)** — *only* for visual confirmation or non-DOM layout. Always clip (`x,y,width,height`) and drop `quality`; never grab a full high-quality page when a region will do.\n8. **`/vnc/screenshot`** — only for native/canvas/non-DOM surfaces, or when DOM extraction genuinely fails.\n\n**Rule of thumb:** text/markup ≫ screenshots for token cost. A clipped JPEG is still an image; a `/text` call is a few hundred tokens. Act on **selectors/refs** from steps 2–6 rather than re-screenshotting to \"look again,\" and verify state changes with the cheapest read, not a fresh full screenshot.\n\n## Environment Variables\n\n| Var | Description |\n|-----|-------------|\n| `RBS_BASE_URL` | Base URL (e.g. https://rb.all-completed.com) |\n| `AC_API_KEY` | Bearer token or API key (user_id derived from token) |\n\n## Tips\n\n- **Session required** — Ensure a session exists before calling navigate/json/text/action. Create via `POST /api/sessions` (HTTP), WebSocket, or restore from stored sessions.\n- **Check live URL** — Use `GET /api/sessions/{session_id}/status` when you need the current page URL/title or last response status without fetching full page text.\n- **429 / session limit** — If create fails with 429 or WebSocket closes (limit exceeded): wait a few seconds and/or terminate the existing session with `DELETE /api/sessions/{session_id}` first, then retry.\n- **Refs from snapshot** — Use `selector` with the `ref` string (e.g. `\"e5\"`) when the action API supports ref→DOM resolution; otherwise prefer CSS selectors.\n- **Readability vs raw** — `/text` (default) strips nav/footer/ads; `?mode=raw` returns full `innerText`.\n- **Interactive filter** — `?filter=interactive` on `/json` reduces nodes by ~75% for action tasks.\n- **VNC vs DOM** — Use `/action` for selectors/refs in the page DOM. Use `/vnc/action` and `/vnc/screenshot` for pixel-level automation and UI outside the DOM.\n- **Stored sessions** — Sessions persist to S3 and are restored on reopen. The **whole browser profile** is captured (cookies, localStorage, sessionStorage, IndexedDB, **Service Workers**, Cache Storage, metadata) and restored as one consistent unit, so apps that keep their login in IndexedDB/Service Workers (e.g. Telegram Web) come back **logged in**, not just at the login page. List with `GET /api/stored-sessions`, then reopen by creating a session with the same `session_id` (HTTP/WebSocket). If `url` is not provided on connect, the saved page URL is used for redirect. Use `GET/PUT /api/stored-sessions/{session_id}` to read or update metadata (e.g. redirect URL). To move or edit individual persisted blobs without a live browser, use `GET/PUT /api/stored-sessions/{session_id}/cookies` (JSON array of cookie objects), `GET/PUT .../local-storage`, `GET/PUT .../session-storage` (both JSON objects with string keys and string values), `GET/PUT .../indexeddb` (IndexedDB snapshot object), and `GET/PUT .../cache-storage` (Cache Storage snapshot object). `DELETE /api/stored-sessions/{session_id}` wipes all persisted state for a session.\n\n## Limitations & fallbacks\n\nReal-world heavy pages (Amazon, marketplaces, dashboards) hit these. Know the fallback for each:\n\n- **Prefer text/markup extraction over screenshots** — For reading page content, `/text`, `/json` (accessibility snapshot), and `/html` are *far* more efficient than `/screenshot` or `/vnc/screenshot`: they return compact, parseable structure instead of a large base64 image, so they cost a fraction of the tokens/bandwidth and give you selectors to act on. **Default to text/markup; use screenshots only for visual verification, pixel-level layout, or canvas/`<iframe>`/non-DOM UI.**\n- **CDP frame limit (now 5 MiB)** — `/text`, `/json`, and `/html` return over a CDP WebSocket whose frame cap was raised from 1 MiB to **5 MiB**, so they now succeed on most heavy pages. If a page is still too large and you get `502` / `frame exceeds limit ... bytes`, **then** fall back: prefer narrowing first (`/text?mode=readability` (default), `/json?filter=interactive`) before resorting to a **clipped `/screenshot`** (`x,y,width,height` + lower `quality`) or `/vnc/screenshot` (framebuffer, independent of the CDP limit).\n- **Prefer `fill` over `type` for form fields** — `type` does `focus()` + `Input.insertText`; some controlled/React inputs don't register it. `fill` does select-all + insertText with real input events and is the reliable choice for text fields. Use `type` only for appending to plain inputs.\n- **To submit a form, use `submit` (not `press` Enter)** — a synthetic `press` Enter does not perform the browser's default submit. Use `{\"kind\":\"submit\",\"selector\":\"<form or a field in it>\"}`, or click the submit button by selector (selector `click` does a DOM `element.click()`).\n- **Never type secrets yourself — use `request-fill`** — for passwords, login codes, 2FA, or any value you must not see, call `POST /api/sessions/{id}/request-fill` instead of `fill`/`type`. The user supplies the value out-of-band in their Keeper desktop app (which shows your `message` + a screenshot of the field area) and the **service** types it into the field; the value is never returned to you or logged. It's **async**: you get `{request_id, status:\"pending\"}` (or `no_keeper`), then poll `GET /api/sessions/fill-status/{request_id}` (tool `get_fill_status`) until `filled` / `cancelled` / `timeout` / `error`.\n  - **One field:** `{\"selector\":\"input[name=password]\",\"label\":\"Password\",\"field\":\"password\",\"message\":\"Logging into Telegram to read your unread chats\"}`.\n  - **Multiple fields in one prompt (max 50):** `{\"fields\":[{\"selector\":\"#user\",\"label\":\"Username\",\"field\":\"login\"},{\"selector\":\"#pass\",\"label\":\"Password\",\"field\":\"password\"}],\"message\":\"Signing in\"}`.\n  - **`field`** sets the prompt kind: `password` (default, masked) / `code` / `login` / `email` / `text`. **`length`** caps the input (1–4096); **`format`** constrains it (`email`, `numeric`/`digits`, or a regex). Set them when you know the value's shape — see docs/keeper-fill-formats.md.\n  - **One proof screenshot** is shown for the request. Pass **`screenshot_selector`** (or `screenshot_selectors`) to control what's captured — **prefer the whole `<form>`/container** (e.g. `\"screenshot_selector\":\"form#login\"`) so the user sees the form in context. Defaults to the field selectors' union if omitted.\n  - Full protocol: docs/keeper-protocol.md.\n- **Actions can report `{\"ok\": true}` without taking effect** — a `click` resolves the element box and dispatches a mouse event; if the target is off-viewport, covered by an overlay/sticky bar, or the page is a SPA mid-update, the event can be a no-op even though the call \"succeeds\". **Always verify state after any state-changing action** (re-screenshot, or re-check the relevant page e.g. the cart) rather than trusting `ok`. Prefer **selector-based** clicks over bare `x,y`; coordinate clicks on cart/checkout pages may also be blocked by host safety policy. If a selector click no-ops, try scrolling it into view first (`{\"kind\":\"scroll\"}`) or click via a screenshot-derived coordinate.\n- **Session lifetime & reopening** — A session with **no live viewer/client** (`active_ws_connections: 0`, e.g. one created purely via the API/MCP) is reclaimed after ~5 minutes idle, and **any service restart/deploy drops all live sessions**. The stored state survives, so **to reopen/resume, just create a session with the SAME `session_id`** — it relaunches the browser and restores the full profile (you stay logged in). List resumable ids with `GET /api/stored-sessions`. For multi-step tasks: keep acting (each call resets idle), avoid long external pauses, and `ping` between steps.\n- **Connecting/disconnecting (incl. CDP/Playwright) does not destroy the session** — opening a WebSocket/CDP connection (e.g. `connectOverCDP`) and closing it leaves the session running; it's reclaimed only by the idle timeout or an explicit `DELETE`. So a client may connect, work, disconnect, and reconnect later to the same live session without losing it.\n- **Encrypted sessions reopen the same way** — if a session was created with `encrypt_with_api_key`, you reopen it identically: create with the same `session_id` using the same API-key/OAuth auth you use for every call. The encryption key is derived **server-side from your token** — you never see, pass, or \"handle\" it. Don't avoid reopening an encrypted session; it is not a special case.\n\nFile v1.0.3:_meta.json\n\n{\n  \"ownerId\": \"kn730fwwv9rb4chrcwkdyx1pgx826v25\",\n  \"slug\": \"remote-browser\",\n  \"version\": \"1.0.3\",\n  \"publishedAt\": 1781773912684\n}\n\nFile v1.0.3:skill-card.md\n\n## Description: <br>\nControl a remote Chrome browser via HTTP API for permitted web automation, form filling, navigation, page inspection, screenshots, text extraction, accessibility-tree inspection, DOM actions, and VNC actions. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[vasyaod](https://clawhub.ai/user/vasyaod) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and AI agents use this skill to create or resume an authenticated remote browser session, inspect page content, and perform permitted DOM or VNC-level browser actions on sites the user owns or is authorized to access. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk:\n\nArchive v1.0.2: 3 files, 9085 bytes\n\nFiles: skill-card.md (2419b), SKILL.md (22237b), _meta.json (133b)\n\nArchive v1.0.1: 3 files, 6310 bytes\n\nFiles: skill-card.md (2369b), SKILL.md (15771b), _meta.json (133b)\n\nArchive v1.0.0: 2 files, 5035 bytes\n\nFiles: SKILL.md (15715b), _meta.json (133b)","readmeExcerpt":"Skill: Remote Browser Service Owner: vasyaod Summary: Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t... Tags: latest:1.0.9 Version history: v1.0.9 | 2026-06-30T00:05:59.956Z | user Add session 'description' metadata field (PUT + list 'descriptions' map); clarify CDP/VNC session lifecycle — closing a connecti","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"curl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"},{"language":"bash","snippet":"curl -X POST \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n# Optional: {\"session_id\": \"my-session\", \"url\": \"https://example.com\"}\n# Fork from stored session: {\"session_id\": \"my-fork\", \"from\": \"original-session\"}\n# Ephemeral (start from metadata/fork but don't save): {\"ephemeral\": true}"},{"language":"bash","snippet":"curl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\""},{"language":"bash","snippet":"curl \"https://rb.all-completed.com/api/sessions\" \\\n  -H \"Authorization: Bearer <token>\""},{"language":"bash","snippet":"curl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\""},{"language":"bash","snippet":"curl \"https://rb.all-completed.com/api/sessions/{session_id}/status\" \\\n  -H \"Authorization: Bearer <token>\""}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: remote-browser-service\ndescription: >\n  Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation,\n  form filling, navigation, and page inspection on sites the user owns or has permission to access.\n  Exposes the accessibility tree, text extraction, Chrome screenshots, VNC-native screenshots,\n  DOM actions, and VNC actions — optimized for AI agents. Requires an active browser session\n  (created via HTTP or WebSocket).\nmetadata:\n  openclaw:\n    emoji: \"🌐\"\n    requires:\n      env:\n        - name: AC_API_KEY\n          secret: true\n          optional: true\n          description: \"Bearer token or API key for auth (user_id derived from token)\"\n---\n\n# Remote Browser Service\n\nBrowser control for AI agents via HTTP API. Supports both DOM-oriented automation\nand remote-desktop/VNC control when you need the actual framebuffer.\n\n## Index\n\n- [Setup](#setup)\n- [Core Workflow](#core-workflow)\n- [API Reference](#api-reference)\n- [Screenshot](#screenshot)\n- [VNC interface](#vnc-interface)\n- [VNC screenshot](#vnc-screenshot)\n- [Act on elements](#act-on-elements)\n- [VNC action](#vnc-action)\n- [HTML snapshot](#html-snapshot)\n- [Token Cost Guide](#token-cost-guide)\n- [Limitations & fallbacks](#limitations--fallbacks)\n- [Environment Variables](#environment-variables)\n- [Tips](#tips)\n\n## Setup\n\nEnsure you have an active session:\n\n1. **Create session** — `POST /api/sessions` (HTTP, no WebSocket), or open WebSocket to `/ws/{session_id}` (DevTools CDP), or run from UI. Optional `url` in body (HTTP) or query (WS) to navigate immediately.\n2. **Or restore** — Use stored session from `GET /api/stored-sessions`\n3. **Auth** — Pass `Authorization: Bearer <token>` or `X-API-Key`, or `?access_token=<token>`\n\nBase URL: `https://rb.all-completed.com` (or `RBS_BASE_URL`). Replace `{session_id}` in examples. User ID is derived from the token.\n\n## Core Workflow\n\n1. **Navigate** to a URL\n2. **Snapshot** the accessibility tree (get refs) — `GET .../json`\n3. **Act** on refs or selectors (click, type, fill, press)\n4. **Snapshot** again to see results\n\nFor visual or OS-level flows, use the VNC path instead:\n\n1. **Open VNC interface** — `GET /users/{user_id}/vnc/{session_id}` when you want a live noVNC view\n2. **Capture VNC framebuffer** — `GET .../vnc/screenshot`\n3. **Send VNC input** — `POST .../vnc/action` with coordinates or keys\n4. **Capture again** to verify pixel-level results\n\nRefs (`e0`, `e1`, …) from `/json` can be used with `/action` via `selector` (use `ref` as selector for `e5` → `\"e5\"` maps to role/name; for now use CSS `selector`).\n\nSupported actions by mode:\n\n| Mode               | Kind     | Example                                                     |\n|--------------------|----------|-------------------------------------------------------------|\n| DOM (`/action`)    | `click`  | `{\"kind\":\"click\",\"selector\":\"button.submit\"}`               |\n| DOM (`/action`)    | `tap`    | `{\"kind\":\"tap\",\"selector\":\"button.submit\"}`      "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn730fwwv9rb4chrcwkdyx1pgx826v25\",\n  \"slug\": \"remote-browser\",\n  \"version\": \"1.0.9\",\n  \"publishedAt\": 1782777959956\n}"},{"path":"skill-card.md","content":"## Description:\n\nControls a remote Chrome browser via HTTP API for web automation, form filling, navigation, page inspection, screenshots, DOM actions, and VNC actions on sites the user owns or has permission to access.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[vasyaod](https://clawhub.ai/user/vasyaod)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and AI agents use this skill to operate a hosted Chrome browser through HTTP endpoints for permitted web automation, inspection, interaction, and visual fallback workflows.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Remote browser sessions can expose page contents, screenshots, actions, and logged-in browser state to the remote browser provider.\n\nMitigation: Install only when the provider is trusted, prefer ephemeral sessions, and avoid using sensitive accounts unless necessary.\n\nRisk: Persistent stored sessions can retain full browser profile state, including cookies and web storage, after a workflow ends.\n\nMitigation: Delete stored sessions when finished and use explicit session termination when persistent state is no longer needed.\n\nRisk: URL access tokens can be exposed through logs, browser history, or shared links.\n\nMitigation: Use Authorization headers or X-API-Key authentication instead of URL tokens when possible.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/vasyaod/skills/remote-browser)\n- [Remote Browser Service endpoint](https://rb.all-completed.com)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, JSON, Guidance]\n\n**Output Format:** [Markdown with HTTP API examples, JSON payloads, and concise operational guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May guide agents to retrieve text, accessibility snapshots, screenshots, VNC framebuffer images, session status, and stored-session metadata from the remote browser service.]\n\n## Skill Version(s):\n\n1.0.9 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t... Skill: Remote Browser Service Owner: vasyaod Summary: Control a remote Chrome browser via HTTP API (Kubernetes or Docker backend). Use for web automation, form filling, navigation, and page inspection on sites t... Tags: latest:1.0.9 Version history: v1.0.9 | 2026-06-30T00:05:59.956Z | user Add session 'description' metadata field (PUT + list 'descriptions' map); clarify CDP/VNC session lifecycle — closing a connecti","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1256,"uniquenessScore":51,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T02:17:20.486Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T02:17:20.486Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T04:33:35.467Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}