> ## 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

> An optional managed browser attached to the computer — domain-scoped, write-guarded, and driven through high-level actions.

A [computer](/docs/computer/index) can have an **optional managed browser** attached. It is a real browser operated by Vetta's browser automation interface and driven by the agent through a small set of high-level actions. Every action is domain-scoped. The browser itself [carries no charge](/docs/computer/limits-and-billing#the-browser): what a browsing agent pays for is the tokens it spends driving it.

The agent never receives the underlying connect URL or the live-view URL — only the action results.

## Session creation

Attaching a browser opens a **session**. Creation is **two-phase and orphan-safe**: Vetta writes a `creating` row before asking the browser automation interface for an upstream session, then promotes it to `active` on success or marks it `error` on failure. If the process dies mid-create, the `creating` row makes the orphan recoverable rather than leaking a live session.

<Steps>
  <Step title="creating">A row is written first, before any upstream session exists.</Step>
  <Step title="active">The upstream session is up; the row is promoted and the agent can drive it.</Step>
  <Step title="error">Creation failed; the row records it so nothing is orphaned.</Step>
</Steps>

## Attach a browser

Enable a browser when you create the computer. `allowed_domains` is required — it scopes every page the browser navigates to.

<CodeGroup>
  ```bash CLI theme={"system"}
  vetta computer create --name box --browser \
    --allowed-domains "app.example.com,*.example.com" \
    --browser-timeout 20 \
    --allow-writes
  ```

  ```typescript TypeScript theme={"system"}
  const computer = await vetta.computers.create({
    name: "box",
    browser: {
      allowedDomains: ["app.example.com", "*.example.com"],
      timeoutMinutes: 20,
      allowWrites: true,
      allowExtract: false,
    },
  });
  ```

  ```bash cURL theme={"system"}
  curl https://api.vetta.sh/v1/computers \
    -H "Authorization: Bearer $VETTA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "box",
      "browser": {
        "allowed_domains": ["app.example.com", "*.example.com"],
        "timeout_minutes": 20,
        "allow_writes": true
      }
    }'
  ```
</CodeGroup>

## Actions

| Action       | What it does                                                                                                        |
| ------------ | ------------------------------------------------------------------------------------------------------------------- |
| `goto`       | Go to a URL.                                                                                                        |
| `click`      | Click the element a CSS selector names.                                                                             |
| `type`       | Type text into the element a CSS selector names.                                                                    |
| `extract`    | Read the page's text, or just the part a selector names.                                                            |
| `screenshot` | Capture a PNG. It is stored as a [file](/docs/capabilities/files) and the agent is given the `fil_` id, never the bytes. |

### Domain re-validation on every action

Every action **re-validates the current page URL** against `allowed_domains` at call time — not just at `goto`. A redirect or a link that lands off the allow-list is blocked. Regardless of the allow-list, the browser **always blocks private, loopback, and metadata hosts** (link-local, internal ranges, and cloud metadata endpoints), including hostnames that *resolve* into them.

<Warning>
  The allow-list is checked on the **page URL** — the document the browser navigates to. Subresources a page loads on its own (`fetch`/XHR, images, iframes) are **not** individually checked against `allowed_domains` today. Treat it as control over where the agent goes, not as an exfiltration boundary for a page that is already open.
</Warning>

<Warning>
  `"*"` disables the allow-list check but does **not** disable the private/loopback/metadata block, and every action under `"*"` is logged. Prefer a scoped list.
</Warning>

## Credentials & saved logins

Credentials are **never entered through `type`**. A guard blocks credential-shaped input, so the agent cannot type a password or token into a field via a normal action.

Instead, saved logins are entered through a **dedicated login flow** that injects values from the [vault](/docs/identity/vault) as **opaque variables** — the agent drives the flow but never sees the raw secret.

<Info>
  **Coming soon.** Vault-backed injection into the browser's login flow is not wired yet: the login flow and the credential guard exist, and the [vault](/docs/identity/vault) API is live, but the substitution path between them — the egress boundary that resolves an opaque placeholder into the real value — does not exist yet.
</Info>

### Saved logins are default-deny

A saved login ("context") is **default-deny**. An agent cannot reuse one just by naming it — it needs an **explicit grant**, by **agent id** or by **role**. Without a grant, `context_name` is refused.

### Human-first login

Set `human_login` to run a **human-first** flow: a person completes the login once, then `save_login` persists the context for later reuse. During the flow a **15-minute lock** is held on the context until `save_login` completes, so two flows can't race the same login.

## Session lifetime & what's withheld

* Each session runs under `timeout_minutes` — default **15 minutes**, maximum **360** (6 hours). See [Limits & billing](/docs/computer/limits-and-billing#the-browser).
* Sessions [carry no charge of their own](/docs/computer/limits-and-billing#the-browser), residential [proxy](#proxy-residential-egress) egress included.
* **Withheld from the agent:** the raw connect URL and the live-view URL. The agent works only through actions and their results.

## Configuration reference

<ParamField path="allowed_domains" type="string[]" required>
  The domains the browser may reach. **Required.** `"*"` means unrestricted **but is logged**. Using a [proxy](#proxy-residential-egress) requires a scoped list — `"*"` is not allowed with a proxy.
</ParamField>

<ParamField path="timeout_minutes" type="integer" default="15">
  Per-session timeout. Range **1–360** minutes (up to **6 hours**).
</ParamField>

<ParamField path="region" type="string" default="us-west">
  Geographic region the browser runs in: `us-west`, `us-east`, `eu-central`, or `ap-southeast`. Pick the one closest to the target site.
</ParamField>

<ParamField path="keep_alive" type="boolean" default="false">
  Keep the session alive across brief disconnects instead of closing it. Useful for long, resumable flows.
</ParamField>

<ParamField path="persist_context" type="boolean" default="false">
  Persist cookies and local storage into the named `context_name` when the session ends, so a later session can resume the same logged-in state.
</ParamField>

<ParamField path="viewport" type="object">
  `{ width, height }` in pixels for the browser viewport.
</ParamField>

<ParamField path="os" type="string">
  Emulated platform fingerprint: `windows`, `mac`, `linux`, `mobile`, or `tablet`.
</ParamField>

<ParamField path="block_ads" type="boolean" default="false">
  Block ad and tracker requests.
</ParamField>

<ParamField path="solve_captchas" type="boolean" default="true">
  Attempt automated CAPTCHA solving on supported challenges.
</ParamField>

<ParamField path="stealth" type="boolean" default="false">
  Enable advanced anti-bot evasion (stealth / verified fingerprint).
</ParamField>

<ParamField path="allow_writes" type="boolean" default="false">
  When `false`, a heuristic **blocks write-looking actions** (submits, purchases, mutations). Set `true` to permit them.
</ParamField>

<ParamField path="allow_extract" type="boolean" default="false">
  Gates `extract` and `screenshot` **on saved-login sessions**. Off by default so a reused login can't silently exfiltrate page content.
</ParamField>

<ParamField path="context_name" type="string">
  Reopen a **saved login** ("context") by name. Subject to the default-deny grant model below.
</ParamField>

<ParamField path="human_login" type="boolean" default="false">
  Start a **human-first login flow**. Takes a 15-minute lock on the context until `save_login` completes.
</ParamField>

<ParamField path="proxy" type="boolean | object" default="false">
  Route egress through a **residential** path. Requires a scoped `allowed_domains` list (not `"*"`).
</ParamField>

<Card title="Next: snapshots & volumes" icon="camera" href="/docs/computer/snapshots-and-volumes">
  Checkpoint a running VM, fork from it, and keep state on a persistent volume.
</Card>
