Repository navigation
HTTP API Reference
All routes on 127.0.0.1 only, JSON bodies (Content-Type: application/json), except /screenshot which returns raw PNG bytes. With --token SECRET, every route except /health requires Authorization: Bearer SECRET (or X-Navette-Token). Request bodies are capped at 10 MB — larger requests are dropped.
The optional "session" field selects a named session (default "default"). Sessions are created lazily on first use; ghost windows are attached to the OS only when a screenshot needs them.
| Route | Body | Returns |
|---|---|---|
GET /health |
— |
{ok, name, engine} — the probe. Also reports auth_ceremony on builds with the passkey plumbing. Exempt from token and Host guards. |
GET /sessions |
— | sessions with url + title |
POST /navigate |
{url, session?, with_content?, format?} |
{ok, url, title[, content]} — with_content folds the read into one round-trip. Redirected navigations complete fine (URL-match completion on wry backends). |
POST /read |
{session?, format?} |
{ok, content} — format: markdown (default) / text / html
|
POST /screenshot |
{session?} |
PNG bytes — native per engine (what the compositor drew, not a re-render), viewport-sized. Set the viewport before navigating for repeatable captures. Full-page capture is not implemented yet — tracked honestly rather than approximated. |
POST /wait |
{selector, ms?, session?} |
{ok} — polls until the selector exists (or the timeout fires). The primary sync primitive on JS-heavy/SPA pages: always /wait the flow's ready selector after /navigate before reading. |
| Route | Body | Returns |
|---|---|---|
POST /click |
{selector, session?, wait_navigation?} |
{ok} — real pointer+mouse events (pointerover/pointerdown/pointerup before the mouse events): Radix/HeadlessUI menus open like they do for a human. wait_navigation: true opts into auto-wait for form-POST navigations. |
POST /type |
{selector, value, session?} |
{ok} — React-safe native setter (frameworks see the value). |
POST /key |
{key, selector?, session?} |
{ok} — keydown+keyup on the focused element (optionally focused by selector). Attempt-first native OS events: CGEvent (macOS), SendInput (Windows), XTEST (Linux/X11) — isTrusted: true — falling back to synthetic dispatch and reporting which mode ran. Single characters ride with an attached unicode string, so the delivered e.key is what was asked for on any keyboard layout (verified on AZERTY). macOS delivery is verified in-page before mode: native is ever reported. |
POST /hover |
{selector, session?} |
{ok} — mouseover/mousemove at the element's center. |
POST /scroll |
{y?, selector?, session?} |
{ok, y} — absolute scroll, or scrollIntoView when selector is given. |
POST /upload |
{selector, filename, content_base64, mime?, session?} |
{ok, files} — fills a file input with in-memory content via a page-side DataTransfer; no OS dialog, nothing written to the visitor's filesystem. |
POST /evaluate |
{js, session?} |
{ok, result} — run JS in the page. Timeout NAVETTE_EVAL_TIMEOUT_SECS (default 20, clamp 5–300). |
POST /sessions/viewport |
{width, height, session?} |
{ok, width, height} — default 1280x800. |
| Route | Body | Returns |
|---|---|---|
POST /sessions/close |
{session} |
{ok} — close one session. Politeness rule: never close a session you didn't create (another workflow may depend on it). |
POST /sessions/show |
{session?} |
{ok, visible} — put the session's window ON SCREEN: titled, keyable, centered, page state intact. The human-moments gate: one-time logins, OAuth, 2FA, captcha (the human does it — never the machine). On macOS this is also the focus gate for native key input: the window must be the key window before any CGEvent is posted. |
POST /sessions/hide |
{session?} |
{ok, visible} — order the window back out. Session and state untouched. |
| Route | Body | Returns |
|---|---|---|
POST /sessions/state |
{session, store?} |
cookies JSON — the logged-in state. With store, the jar goes to the OS keychain under that name and only {stored, origin, cookies} returns — the jar never rides the wire. |
POST /sessions/load |
{session, cookies} or {session, store}
|
{ok, imported[, origin, saved_at]} — restore a logged-in state from JSON (the Playwright storageState equivalent) or from the keychain. |
GET /states |
— | stored states — names, origins, timestamps; never the jars. |
POST /states/delete |
{name} |
{ok} |
Cross-session isolation is CI-enforced on every engine: a cookie imported into session A must not appear in session B's exported jar, or the build fails. See Sessions and State and Security.
| Route | Body | Returns |
|---|---|---|
POST /creds/set |
{site, username, password, session} |
{site, origin} — HUMAN step (the CLI prompts on hidden stdin: navette creds set SITE). The credential binds to the exact origin of the session's current page. |
GET /creds |
— | sites + origins + usernames — never passwords. |
POST /creds/delete |
{site} |
{ok} |
POST /login |
{site, session?, submit?} |
fill + submit the login form from the keychain. The password never appears in the request, the response, or a log — it is resolved inside the daemon and injected into the page. 403 unless the session is on the credential's origin — a hostile page or a prompt-injected agent can neither harvest the secret nor aim it elsewhere. |
There is no password read-back API at all. The one honest limit: at fill time the password does reach the page — the same as human typing; the origin-binding is the defense.
-
JS dialogs (
alert/confirm/prompt) are auto-handled in-page: alert logs and no-ops, confirm accepts, prompt returns its default — agents never deadlock on a hidden modal. -
macOS bridge returns plist, not JSON: any
/evaluatereturning an object/array must be wrapped inJSON.stringify(...)— otherwise the result comes back as a plist string. This is the #1 recipe bug; everysites/recipe marks it MANDATORY. -
wry backends single-encode eval strings:
/evaluateresults return strings single-encoded through wry — macOS parity fix; don't double-decode. -
A malformed JSON body makes
/evaluatereturn{"ok":true,"result":""}silently — build payload files and validate them (python3 -m json.tool) before posting; on an empty result, re-run a trivial probe ({"js":"document.title"}) to separate a payload bug from page state. -
Session-create failures are slow: if WebView/WebView2 session creation fails, callers wait out the command timeout (20–45 s) instead of getting a fast 500 (known residual, refactor noted in
backend_wry.rs). -
DNS-rebinding guard: non-local
Hostheaders get 403 on everything except/health(--allow-host NAMEextends the accepted list for containers/tunnels). -
Linux WebKitGTK:
/evaluatescripts that writedocument.cookietime out (reads work) — use/sessions/loadfor cookie writes (issue #7).
slabbdev/navette · v1.9.0 · MIT — the browser for agents. One tiny Rust binary, the WebView your OS already ships.
navette — the browser for agents
- Home
- Use it
- Sessions, secrets, humans
- Ecosystem
- Evidence
- Project