Skip to content

Control the live browser

The browser API provides plain REST endpoints for querying the live in-session browser’s status and navigating it to URLs — useful for programmatic browser control without an SDK or a WebSocket connection.

Every request needs a Jarvis API key. Send it as Authorization: Bearer <key> or X-Jarvis-Api-Key: <key>. A request without a valid key is rejected with 401:

{
"success": false,
"error": "A Jarvis API key is required (Authorization: Bearer <key> or X-Jarvis-Api-Key)",
"code": "unauthorized"
}

A 502 with "code": "auth_unavailable" means key validation itself could not be reached — retry rather than treating the key as bad.

Call these endpoints server-to-server. Cross-origin browser calls are limited to an allow-list of first-party origins, because a browser integration would have to ship your API key to end users.

Returns the current browser status.

Response:

{
"status": "idle",
"sessionId": null,
"liveViewUrl": null,
"desiredUrl": null,
"lastNavigatedUrl": null,
"lastError": null
}

status is one of idle, creating, ready, expired, or error. Once it is ready, liveViewUrl contains the URL for the live browser view.

desiredUrl is the page the session is currently targeting and lastNavigatedUrl the last one the browser actually reached, so the two together tell you whether a requested navigation has landed yet. lastError carries the reason a navigation was refused; it clears as soon as the browser reaches a page.

Retarget the live browser to a URL. If no browser is running yet, one is provisioned automatically and comes up on that URL.

The URL is added to the session’s known target pages and becomes the selected one, so it also survives the browser being reaped and recreated.

Request:

{ "url": "https://example.com" }

Response (202):

{
"accepted": true,
"url": "https://example.com",
"statusUrl": "/api/sessions/:sessionId/browser"
}

The navigation outlives the request, so 202 means accepted, not landed. Poll statusUrl until lastNavigatedUrl equals the URL you asked for:

Terminal window
curl -s -X POST \
-H "Authorization: Bearer $JARVIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}' \
"$EDITOR_WEB/api/sessions/$SESSION_ID/browser"
for _ in $(seq 30); do
status=$(curl -s -H "Authorization: Bearer $JARVIS_API_KEY" \
"$EDITOR_WEB/api/sessions/$SESSION_ID/browser")
echo "$status" | grep -q '"lastNavigatedUrl":"https://example.com"' && break
echo "$status" | grep -q '"lastError":"' && break
sleep 1
done
echo "$status"

A navigation the browser refuses leaves lastNavigatedUrl unchanged and reports the reason in lastError, which is why the loop above watches for both and gives up rather than waiting forever. A cold session pays for the browser to start first, so allow ~30s.

Error (400):

{ "error": "url is required" }

Session IDs must match [a-z0-9][a-z0-9_-]{0,63} — lowercase alphanumeric, 1–64 characters, may contain hyphens and underscores (but not as the first character). Uppercase IDs are rejected and fall through to the SPA router.

Try the browser API endpoints against a real Coframe Agent backend. Paste a Jarvis API key to get past the 401; the demo keeps it in the page only, so a reload clears it.