# Dashboard

Part of the Oya Browser docs. All of it: https://oyabrowser.com/docs.md

## Dashboard

**Browsers, commands, and CDP sessions**
A browser is a running desktop or cloud instance. REST commands, including curl requests to `/api/browsers/:id/command`, appear in that browser’s Activity history and count toward Usage. A CDP session is a persistent client connection through `/connect`, typically from Playwright or Puppeteer. Find these under Control → CDP sessions.

The [dashboard](https://oyabrowser.com/dashboard) at `/dashboard` is the control panel. It shows your connected browsers and lets you interact with them.

Built to hold a thousand browsers and let you act on any one of them:

- **Browsers**: a health strip (every number is a filter) over a dense table: health, persona, provider, current page, commands · errors, seen, uptime. Select a row to open the panel: URL bar, a bounded *interactive* live view, screenshot, elements, stats, and the activity log, what that browser has been doing, newest first.
- **Personas**: one identity each. Create with a chosen device and a live fingerprint preview; edit name, cap, proxy pin and MFA; the device itself is locked, with *Clone* for when you want a different one.
- **Control**: health, gateway sessions, providers and routing, per-key usage, the audit trail, recordings.

### Adding a provider

Open **Control → Providers → Add provider**. Give the route a unique name, choose a vendor, and enter its API key. A credential already saved in Settings can be reused. For your own Chrome, supply its CDP WebSocket URL instead.

Set the session capacity and routing priority (0 goes first). Providers and your routing strategy are saved for your Oya key across restarts; credentials and connection URLs are encrypted. Saving a provider does not launch a browser or verify its credentials. Its first connection does that. End active sessions before removing a route.

These routes serve new CDP connections to `/connect?token=YOUR_OYA_KEY`. The **Start browser** action uses your provider selection in **Settings → Browsers**. Attaching with `?browser=ID` connects to that existing browser.

### Driving a browser from the live view

Choose **Stream** in a browser panel, or **Open live stream in a tab** from its menu, to open an interactive viewer in a separate tab. Your dashboard key authorizes the viewer. The `/api/live/:id` endpoint is the raw event stream for integrations.

Click to control. Clicks land at the page pixel under the cursor, a drag is a drag, the wheel scrolls, typing is batched into `keyboard_type` and the named keys go as `press_key`. `Esc` hands the keyboard back. What was typed is never written to the activity log, it records *2 chars*, not the text.

### Connect to a browser that is already running

Right-click any row (or press **Connect** in the panel) for code that targets that exact browser: SDK, CLI, an MCP config, curl, and for CDP-backed browsers a Playwright `connectOverCDP` URL. Snippets are written for this deployment and your key; the key is masked until you ask, and copy always copies the real one.

```
// Attach through the gateway to one browser in the fleet. Closing your
// client leaves the browser running.
const browser = await chromium.connectOverCDP(
  "wss://<host>/connect?token=<api-key>&browser=<browser-id>",
);
```

Only CDP-backed browsers (Browserbase, Steel, Anchor, your own Chrome) have an endpoint to attach to; an Oya client is driven over its own socket, so use the SDK, CLI or MCP for those.

### Stop means stop

One button, one endpoint (`POST /browsers/:id/stop`). A cloud browser's sandbox is destroyed so billing ends; a CDP browser is handed back to its provider; a desktop browser disconnects. The confirm says which. Bulk stop takes `{ids: [...]}` or `{all: true}`.

### Keyboard

| Key | Does |
| --- | --- |
| ⌘/Ctrl 1 · 2 · 3 | Browsers · Personas · Control |
| n | Start a browser |
| / | Filter the fleet |
| ↑ ↓ or j k | Move the selection |
| x | Stop the selected browser(s) |
| l · r · s | URL bar · reload · screenshot |
| Esc | Close the panel, or release the keyboard from the live view |
| ? | The full list |

You can sign in with an account, or by pasting an API key: a self-hosted deployment with `API_KEYS` and no database has no accounts, and still needs its own UI.

### Onboarding

A key that has not been set up gets a two-step page. Everything it asks is stored against that key, nothing lands in an environment variable, and nothing is inherited from an account.

1. **Desktop**: one click opens the desktop browser signed in to the project
2. **AI model**: Claude, OpenAI or Gemini and your key, which Ask in the desktop needs. Ask also asks for it inline if it is missing

Where browsers run, CAPTCHA solving and the model itself are all in Settings, and `oya init` sets them up in a terminal.

### Dev Panel (Desktop App)

The desktop app's dev panel (`{}` button in the toolbar) has four tabs:

- **Chat**: natural language browser control with formatted responses and tool badges
- **Actions**: quick-fire buttons and input fields for every command: analyze, screenshot, navigate, click by element #, type, press keys, hover, scroll, wait, tab management
- **Network**: live WebSocket traffic with IN/OUT badges, expandable payloads, filter by direction or type (All, In, Out, Commands, Results)
- **Source**: view the page as AI sees it: toggle between Markdown (analyzePage output) and HTML source, refresh on demand

### Live View

Select a browser on the Browsers tab to watch it work. Frames stream as JPEG over SSE at ~2fps. `browser.liveViewUrl()` is the console deep link for a person to open; `await browser.liveStreamUrl()` gives you the same frames to embed, with a single-use ticket that expires in 60 seconds, EventSource cannot set headers, and a URL that ends up in browser history should not be a permanent credential.

### Settings

The gear icon next to the API key bar. Everything here belongs to that key: model provider and credential, default model, browser provider and its credential, CAPTCHA solver, and the one-click desktop sign-in.

Credentials are sealed at rest with AES-256-GCM and always read back masked. Saving the masked placeholder never overwrites the real value.

A key that has set nothing falls back to the deployment-wide defaults. Changing *those* affects every key that has not set its own, so it needs `OYA_OPERATOR_TOKEN` via `POST /config/host` rather than any API key.
