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

# Browsers

> Drive a browser from an automation with Playwright: this machine's own browser, watchable on its Desktop, or the Chrome on your laptop.

`@boxd/run` gives a script two browsers, both driven with [Playwright](https://playwright.dev). You get a standard Playwright `Browser` back, and everything after that is ordinary Playwright: pages, locators, screenshots, downloads. The broader picture, what a coding agent should use, `agent-browser`, the desktop, is on [Launch a Browser](/guides/launch-a-browser).

## This machine's browser: `browser.launch()`

```ts theme={"theme":"github-dark"}
import { browser } from "@boxd/run";

const b = await browser.launch();          // headed on the machine's Desktop, stealth on
const page = await b.newPage();
await page.goto("https://example.com");
console.log(await page.title());
await b.close();
```

* **Visible by default.** The browser opens on the machine's [Desktop](/guides/desktop). Open the machine in the console and choose **Open → Desktop** to watch it, and click into it to help (type a password, solve a captcha). The desktop is brought up automatically. Pass `{ headless: true }` for an invisible run.
* **Stealth by default.** The machine ships a Chromium build with anti-bot fingerprinting, and every launch gets a fresh fingerprint. Pass `{ stealth: false }` to turn it off.
* **Playwright options pass through.** `proxy`, `timeout`, `args`, and so on are accepted. Your `args` are added last, so they win, and `excludeArgs` drops any default you don't want.
* **Don't set a viewport for the headed browser.** It's a real on-screen window, so contexts default to `viewport: null`. Pass one only if you specifically want emulation.

Each launch starts with a clean profile. For a persistent, logged-in profile on the machine, use the desktop's own browser via `agent-browser`. See [Launch a Browser](/guides/launch-a-browser#the-machines-browser).

## Your laptop's browser: `boxd.local.device().browser.connect()`

```ts theme={"theme":"github-dark"}
import { boxd } from "@boxd/run";

const laptop = boxd.local.device();               // the laptop that ran `run`, or your newest-connected one
const b = await laptop.browser.connect();         // starts Chrome on it if needed, then attaches
const page = await b.newPage();
await page.goto("https://mail.google.com");       // the boxd profile on your laptop; log in once, it persists
```

This drives a Chrome on **your own computer**, on your own screen and network, in a dedicated profile that boxd keeps separate from your everyday Chrome (log in once and it persists). It needs the [client utilities](/guides/client-utilities) enabled on that computer (`boxd config set client-utils.enable true`), and it only works from your personal and private machines, never from shared or isolated ones.

* `connect()` opens the browser headed (visible on your screen) unless you pass `{ headless: true }`.
* Several computers connected? `await boxd.local.devices()` lists them. `boxd.local.device("desktop")` picks one by label, id or unique prefix and never falls back to another.
* Lower-level: `laptop.browser.open()`, `.info()`, `.cdpUrl()` and `.close()` are there if you want to drive the CDP endpoint with a different client.

If no laptop is reachable, the call fails with *device not connected*. A script with no laptop context at all gets *no laptop in this context - pick one explicitly: `await local.devices()` lists them, `local.device("<label|id>")` binds one*. When the browser doesn't come up, the message says client utilities must be enabled on it.

## Which one?

`browser.launch()` is the default. Reach for the laptop only in the row that names it.

| Need                                                                                                                              | Use                                                                                                  |
| --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Anything ordinary: scraping, forms, screenshots, checking a page                                                                  | this machine's browser                                                                               |
| Isolation, a clean profile, stealth, many in parallel                                                                             | this machine's browser                                                                               |
| Someone to act mid-task (log in, approve, solve a captcha)                                                                        | this machine's browser: open its [Desktop](/guides/desktop) and act in the browser the script opened |
| **The request must come from your network**: datacenter IPs blocked, a VPN-only service, an IP allow-list, geo-restricted content | your laptop's browser                                                                                |

Note what is *not* a reason to use your laptop's browser: getting at your logins. It runs in a dedicated boxd profile, separate from your everyday Chrome, so it starts signed out.

Background jobs that reach your laptop keep addressing the computer you started them from, across restarts. That still makes a scheduled automation depend on that laptop being awake and online at 3am, which is another reason to prefer the machine's own browser for anything unattended.
