# Hermes Browsers > Hosted headless browsers over the Chrome DevTools Protocol (CDP). Connect Puppeteer, Playwright or chromedp to a WebSocket URL with an API token and get a fresh, isolated browser (Lightpanda, Chrome or CloakBrowser) that is destroyed when you disconnect. You can also create long-lived sessions over REST or from the dashboard, reconnect to them, watch and control them live, record them to MP4 and keep logins in persistent Chrome profiles. Dashboard: https://app.hermesbrowsers.com ## Quick start 1. Sign up at https://app.hermesbrowsers.com/signup. 2. Create a token at https://app.hermesbrowsers.com/tokens (you can show and copy the full 40-character token there anytime) and store it as `HERMES_TOKEN`. 3. Connect to `wss://cdp.hermesbrowsers.com/ws?token=$HERMES_TOKEN`. ## Connection URL `wss://cdp.hermesbrowsers.com/ws?token=&browser=&proxy=&country=&timeout=&profile=&record=1` | Parameter | Required | Meaning | | --- | --- | --- | | `token` | yes | API token from the Tokens page | | `browser` | no | `lightpanda` (default; fast, low memory, partial Web API coverage), `chrome` (full rendering) or `cloak` (CloakBrowser stealth Chromium: spoofed fingerprint, `navigator.webdriver` false, presents as Windows) | | `proxy` | no | Name of a shared proxy or of one of your dedicated proxies (Proxies page) | | `country` | no | Two-letter country code for proxies that support it | | `timeout` | no | Session lifetime in minutes, 1-15 (default 15) | | `profile` | no | Chrome/cloak only. Persistent profile name (`[A-Za-z0-9_-]{1,64}`); cookies, storage and logins survive between sessions (cloak also keeps the same fingerprint). Created on first use; one running session per profile | | `record` | no | Chrome/cloak only. `1` records the session to MP4 (kept 7 days) | Regions: - `eu` (Europe): wss://cdp.hermesbrowsers.com/ws ## Examples Puppeteer: ```js import puppeteer from "puppeteer-core"; const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cdp.hermesbrowsers.com/ws?token=${process.env.HERMES_TOKEN}&browser=lightpanda` }); const page = await browser.newPage(); await page.goto("https://example.com"); console.log(await page.title()); await browser.disconnect(); ``` Playwright (CDP only, Chromium API): ```js import { chromium } from "playwright-core"; const browser = await chromium.connectOverCDP(`wss://cdp.hermesbrowsers.com/ws?token=${process.env.HERMES_TOKEN}&browser=chrome`); const page = await browser.contexts()[0].newPage(); await page.goto("https://example.com"); await browser.close(); ``` chromedp (Go): ```go ctx, cancel := chromedp.NewRemoteAllocator(context.Background(), "wss://cdp.hermesbrowsers.com/ws?token="+os.Getenv("HERMES_TOKEN"), chromedp.NoModifyURL) defer cancel() ctx, cancel = chromedp.NewContext(ctx) defer cancel() var title string err := chromedp.Run(ctx, chromedp.Navigate("https://example.com"), chromedp.Title(&title)) ``` Automation > Script generator in the dashboard builds these snippets with your token, browser and proxy filled in. ## Agents AI agents use the same URL. Pick Chrome for them (full Web APIs and screenshots): `wss://cdp.hermesbrowsers.com/ws?token=&browser=chrome`, written `` below. - **Hermes Agent**: `/browser connect ` in chat, or set `browser.cdp_url` (or `BROWSER_CDP_URL`). - **OpenClaw**: add a remote profile, `browser.profiles.hermes.cdpUrl: ""`. - **Claude Code**: `claude mcp add hermes -- npx @playwright/mcp@latest --cdp-endpoint ""` - **Codex**: `codex mcp add hermes -- npx @playwright/mcp@latest --cdp-endpoint ""` - **Kilo Code, Cline, Strix and omp**: add Playwright MCP to the agent's MCP servers file (Kilo Code and Cline: MCP settings; Strix: `~/.strix/mcp-servers.json`; omp: `~/.omp/agent/mcp.json`, after setting `browser.enabled: false`, since omp hides browser MCP servers while its own browser is on): ```json { "mcpServers": { "hermes": { "command": "npx", "args": ["@playwright/mcp@latest", "--cdp-endpoint", ""] } } } ``` - **pi**: has no MCP by design; ask it to run a Puppeteer or Playwright script that connects to `` (see Examples). ## REST API (persistent sessions) Base URL `https://cdp.hermesbrowsers.com`. Authenticate with `Authorization: Bearer ` (or `X-API-Key`). A session created over REST stays alive across disconnects until you stop it or `timeout` is reached, so you can reconnect to `cdp_url` any number of times (one client at a time recommended). | Method | Path | Meaning | | --- | --- | --- | | POST | `/v1/browsers` | Start a session. JSON body: `browser`, `proxy`, `country`, `region`, `timeout`, `profile`, `record` (same meaning as above). 201 with the session | | GET | `/v1/browsers` | Running sessions of the token's account | | GET | `/v1/browsers/{id}` | One session | | DELETE | `/v1/browsers/{id}` | Stop it (409 if not running) | | GET | `/v1/browsers/{id}/recording` | The MP4 once `recording` is `ready` | Session object: `id`, `status` (`running`/`closed`/`error`), `browser`, `proxy`, `country`, `region`, `profile`, `persistent`, `recording` (`recording`/`ready`/`failed`/`expired`/null), `started_at`, `timeout_at`, `ended_at`, `close_reason`, `cdp_url` (connect here; null once closed), `live_url` (Chrome/cloak only), `recording_url`. ```bash curl -s -X POST https://cdp.hermesbrowsers.com/v1/browsers -H "Authorization: Bearer $HERMES_TOKEN" -H 'content-type: application/json' \ -d '{"browser":"chrome","profile":"shop-login","record":true,"timeout":10}' ``` ```js const s = await (await fetch("https://cdp.hermesbrowsers.com/v1/browsers", { method: "POST", headers: { authorization: `Bearer ${process.env.HERMES_TOKEN}`, "content-type": "application/json" }, body: JSON.stringify({ browser: "chrome" }) })).json(); const browser = await puppeteer.connect({ browserWSEndpoint: s.cdp_url }); // ... later, from any process: await fetch(`https://cdp.hermesbrowsers.com/v1/browsers/${s.id}`, { method: "DELETE", headers: { authorization: `Bearer ${process.env.HERMES_TOKEN}` } }); ``` ## Live view Every running Chrome/cloak session has a `live_url`: a page that streams the browser screen and lets whoever opens it click, type, paste (Cmd/Ctrl+V sends your local clipboard), scroll and navigate (human-in-the-loop for logins, 2FA or CAPTCHAs). On a slow link it skips frames instead of falling behind, so what you see stays current. It is a bearer link: anyone holding it can control the browser until the session ends. It is shown on the Browsers and session pages in the dashboard and returned by the REST API. ## Proxies HTTP proxies only. Shared proxies: - `residential`: Residential (residential), accepts `country` Shared proxy traffic is prepaid: every account gets 1 GB free, then $0.27/GB. Used and remaining GB are on the Subscription & billing page. With the balance at zero new sessions on a shared proxy are refused (402) and running ones are closed. Dedicated proxies are not billed. Dedicated proxies: add `host:port` with optional username/password on the Proxies page, then pass its name as `proxy`. ## Limits | Plan | Concurrent sessions | Browser hours / month | | --- | --- | --- | | Explorer (free) | 5 | 10 | | Builder | 30 | 300 | - Each token also has its own concurrency limit (set on the Tokens page). - A session is closed after 15 minutes, or after its `timeout`. ## Connection errors The WebSocket upgrade is rejected with an HTTP status and a JSON body `{"error": "..."}`: | Status | Error | Fix | | --- | --- | --- | | 401 | `missing token` / `invalid token` | Pass a valid `token` | | 403 | `token disabled` | Re-enable the token on the Tokens page | | 400 | `unknown browser: x` / `unknown proxy: x` | Use `lightpanda`/`chrome`/`cloak`, or an existing proxy name | | 403 | `browser=cloak is not enabled for this account` | Use `chrome`, or ask the operator to enable CloakBrowser | | 429 | `token concurrency limit reached` / `plan concurrency limit reached` | Close other sessions or raise the limit | | 402 | `monthly browser hours exhausted` | Wait for next month or upgrade | | 402 | `residential proxy balance exhausted` | Contact support to add proxy GB | ## Dashboard - [Browsers](https://app.hermesbrowsers.com/browsers): launch a Chrome or CloakBrowser browser (proxy, country, profile) without code, open its live view, stop it - [Sessions](https://app.hermesbrowsers.com/sessions): every session with duration, bandwidth, close reason and its CDP message log - [Tokens](https://app.hermesbrowsers.com/tokens): create, show/copy, disable, delete and limit API tokens - [Proxies](https://app.hermesbrowsers.com/proxies): shared and dedicated proxies - [Profiles](https://app.hermesbrowsers.com/profiles): persistent Chrome profiles; import cookies (Cookie-Editor/EditThisCookie export or Puppeteer/Playwright JSON) to start one already signed in, they load on its next session; delete one to wipe its data - [Scripts](https://app.hermesbrowsers.com/playground/scripts): write TypeScript scripts in the browser and run them on demand on the console's servers (Run button only, no schedule, 2-minute limit); `process.env.CDP_WS_URL` is preset. Run history is under Script runs - [Script generator](https://app.hermesbrowsers.com/tools/script-generator): ready-to-run connection snippets for your own machine or server (use these for cron jobs or longer runs) Session pages show live view and share link, a Stop button and the recording player.