> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Browser

> Drive a computer's managed browser over REST — actions, session state, saved logins and who may reopen them.

> [!NOTE]
>
> The option object, guards and lifetime are in the [Browser](https://vetta.sh/docs/computer/browser.md) guide. This page is the routes.

A [computer](https://vetta.sh/docs/api/computers.md) created with a `browser` block carries one **browser session**. The
first action opens it; `DELETE` closes it. Every route below takes the `computers:write` scope
unless it says otherwise. Three routes — live view, granting and revoking a saved login — answer
only a signed-in dashboard session: an API key gets `403 forbidden` whatever its scopes.

## The browser session object

**id** `string`

Unique id (e.g. `brw_01H...`).

**object** `string`

Always `browser_session`.

**computer\_id** `string | null`

The computer the browser runs on.

**session\_id** `string | null`

The [agent session](https://vetta.sh/docs/api/sessions.md) whose `browser` tool opened it; `null` for a browser opened over the API.

**status** `string`

`creating`, `active`, `closed` or `error`.

**allowed\_domains** `string[]`

The allow-list every action is checked against.

**region** `string`

`us-west`, `us-east`, `eu-central` or `ap-southeast`.

**context\_id** `string | null`

The saved login (`bct_`) this session reopened, if any.

**context\_backed** `boolean`

`true` when the session carries a saved login — `extract`, `observe`, `links` and `screenshot` then need `allow_extract`.

**timeout\_at** `string`

When the session closes on its own (`timeout_minutes` after it opened). A sweep on the platform clock closes and bills any session past it within a minute; the row is then `closed` like one you deleted.

**opened\_at** `string`

When the browser came up.

**closed\_at** `string | null`

When it closed; `null` while open.

**created\_at** `string`

Creation timestamp.

The live-view URL and the upstream connect URL are bearer credentials. Neither is a field on this
object, and neither appears in a tool result, an event or a log.

## Perform an action

`POST /v1/computers/{id}/browser/actions` — opens the browser lazily on the first call.

The body is **one action**, discriminated on `action`. `Idempotency-Key` is **required** for `goto`
and `act` and optional elsewhere.

| `action` | body | how it runs |
| - | - | - |
| `goto` | `{ url }` | deterministic |
| `click` | `{ selector }` | deterministic |
| `type` | `{ selector, text }` | deterministic; credential-shaped `text` is refused |
| `extract` | `{ instruction?, selector?, schema? }` | selector only → the element's text; with `instruction`/`schema` → model-driven, shaped to `schema` |
| `act` | `{ instruction, variables? }` | model-driven; `%name%` placeholders are filled from `variables` |
| `observe` | `{ instruction }` | model-driven → candidate elements |
| `links` | `{ contains?, limit? }` | deterministic; `limit` defaults to 50, max 200 |
| `screenshot` | `{}` | deterministic → a `fil_` file |

```bash cURL theme={"system"}
curl https://api.vetta.sh/v1/computers/cmp_01H.../browser/actions \
  -H "Authorization: Bearer $VETTA_API_KEY" \
  -H "Idempotency-Key: 5f3b0e2e-1" \
  -H "Content-Type: application/json" \
  -d '{ "action": "act", "instruction": "search for %term%", "variables": { "term": "vetta" } }'
```

Every action answers the same object:

**object** `string`

Always `browser_action`.

**action** `string`

The action that ran.

**url** `string`

The page URL after the action.

**text** `string | null`

`extract` without a schema: the text read.

**data** `unknown | null`

`extract` with a schema: the data, in that shape.

**links** `object[] | null`

`links`: `[{ href, text }]`.

**elements** `object[] | null`

`observe`: `[{ selector, description }]`.

**file\_id** `string | null`

`screenshot`: the `fil_` id of the PNG. Never the bytes.

**performed** `boolean`

Always `true` on a `200`. An `act` that did nothing is a `502 provider_error`, not a `200` with `false`.

`variables` values are never echoed — not in the result, not in the event, not in the audit row.

### What is refused

| Guard | Error |
| - | - |
| Page URL off the allow-list, or a private, loopback or metadata host — checked before **and** after every action | `403 forbidden`, `param: url` |
| Write-looking `act`, `click` or `type` (submit, purchase, delete, send, pay, confirm) without `allow_writes` | `403 forbidden`, `param: allow_writes` |
| Credential-shaped `type.text` or `act.instruction` (password, token and key patterns; vault values are sealed and never compared) — credentials travel only through [login](#log-in-with-a-saved-credential) | `400 validation_failed`, `param: text` / `instruction` |
| `extract`, `observe`, `links` or `screenshot` on a context-backed session without `allow_extract` | `403 forbidden`, `param: allow_extract` |
| An `act` the automation could not perform | `502 provider_error` |
| A `context_name` the calling agent has no grant for | `403 forbidden`, `param: context_name` |
| A `context_name` that names a saved login on more than one identity — the lookup is organization-wide by name, and a computer's options carry no identity to pick one | `400 validation_failed`, `param: context_name` |

> [!NOTE]
>
> Name saved logins uniquely across the organization if more than one identity will hold them: `shop-ava` rather than two `shop`s. A name is unique per identity at save time, so the collision only arises across identities.

## Read the session

`GET /v1/computers/{id}/browser` → the [browser session](#the-browser-session-object), or `404 not_found` when none is open.

## Close the session

`DELETE /v1/computers/{id}/browser` — idempotent. The closed [browser session](#the-browser-session-object)
(`status: closed`, `closed_at` set), or `204` when nothing was open. Closing settles the session's
minutes on the `browser` line item, capped at `timeout_at`, and, on a session opened with `persist_context` or `human_login`,
writes its cookies and storage into the saved login.

## Live view

`GET /v1/computers/{id}/browser/live-view` — **dashboard session only.** A `browser_live_view`
(`{ object, url, expires_at }`) for the one browser currently open; the URL is a bearer credential
and is never logged or put in an event. An API key gets `403 forbidden`.

The dashboard's Browser tab on a computer renders it, and lists every browser the computer ever
drove — see [Browser sessions](https://vetta.sh/docs/api/browser-sessions.md). Never hand the URL to an agent or store it.

## Save a login

`POST /v1/computers/{id}/browser/context` → `201 browser_context`

A saved login is **bound when a browser opens**: the engine attaches it at session start and flushes
cookies and storage into it at close. This call therefore has two moments:

1. **No browser open on the computer** — creates the empty saved login under `name`, owned by an
   [identity](https://vetta.sh/docs/api/identities.md). Open the next browser with `context_name` (and `human_login` or
   `persist_context`) to fill it.
2. **A browser open with that `context_name`** — marks the login saved and releases the
   `human_login` lock; the same `bct_` comes back and the close persists the login.

On a browser open without that context the call is `400 validation_failed` (`param: context_name`):
nothing that browser holds can reach the saved login.

**name** `string` *required*

1–64 characters; unique per identity.

**identity\_id** `string` *required*

The `idn_` that owns the saved login.

**service** `string`

What the login is for, e.g. `figma.com`.

**id** `string`

`bct_` id.

**object** `string`

Always `browser_context`.

**identity\_id** `string`

The owning identity.

**name** `string`

The name a later `context_name` reopens.

**service** `string | null`

As given.

**created\_at** `string`

Creation timestamp.

**last\_used\_at** `string | null`

When a session last reopened it.

## Grant a saved login

`POST /v1/browser/contexts/{name}/grants` — **dashboard session only** → `201 browser_grant`

A saved login is default-deny: a session may reopen it only when its agent — or the agent's member
role — holds a grant. The same grantee twice is a `200` replay of the existing grant; a new one
reaches your [webhooks](https://vetta.sh/docs/api/webhooks.md) as `browser.context.granted`. Over the REST
API, an **owner or admin** dashboard session — or an API key holding the `admin` scope — opens every
saved login of the organization without a grant; a **member** session, and any other API key, needs
the `member` role grant; an agent's `browser` tool needs a grant by its `agt_` id or by role.

**identity\_id** `string` *required*

The identity that owns `{name}`.

**grantee\_type** `string` *required*

`agent` or `role`.

**grantee\_id** `string` *required*

An `agt_` id, or `owner` / `admin` / `member`.

**id** `string`

`bgr_` id.

**object** `string`

Always `browser_grant`.

**context\_id** `string`

The `bct_` granted.

**grantee\_type** `string`

`agent` or `role`.

**grantee\_id** `string`

As given.

**created\_at** `string`

Creation timestamp.

## Revoke a saved login

`DELETE /v1/browser/contexts/{name}?identity_id=idn_...` — **dashboard session only.** Deletes the
saved login and every grant on it. `identity_id` is required. Webhooks receive
`browser.context.revoked { context_id }`.

## Log in with a saved credential

`POST /v1/computers/{id}/browser/login` → `browser_action`

Reads the identity's vault credential `login:<service>` and fills the form through `%username%` and
`%password%` placeholders. The plaintext never enters the model or a result.

**service** `string` *required*

The credential's service, e.g. `figma.com`.

**url** `string` *required*

The sign-in page.

**identity\_id** `string` *required*

Whose vault to read.

## Sign up

`POST /v1/computers/{id}/browser/signup` → `browser_action`

Generates a password, stores it as `login:<service>` in the identity's vault, then runs the sign-up
flow with it. When an agent's `browser` tool does this, the session **always pauses for a person to
confirm** — see [Tools](https://vetta.sh/docs/capabilities/tools.md).

**service** `string` *required*

The service being joined.

**url** `string` *required*

The sign-up page.

**identity\_id** `string` *required*

Whose vault receives the credential.

**email** `string` *required*

The address to register.

## Save a credential

`POST /v1/browser/credentials` → the [vault credential](https://vetta.sh/docs/api/vaults.md)'s metadata

Seals `login:<service>` into the identity's vault so `login` can use it. The reply is metadata —
no route ever returns the value.

**identity\_id** `string` *required*

Whose vault.

**service** `string` *required*

The service, e.g. `figma.com`.

**email** `string` *required*

The account's email.

**password** `string` *required*

Write-only.

**username** `string`

When the site signs in by username rather than email.

## Errors

`forbidden`, `validation_failed`, `not_found`, `context_locked` (`409` — a `human_login` flow holds
the saved login for 15 minutes), `provider_error` (`502`), `computer_unavailable`, `rate_limited`,
`feature_not_configured`. See [Errors](https://vetta.sh/docs/api/errors.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.