Documentation
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
- Sign up at https://app.hermesbrowsers.com/signup.
- 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. - Connect to
wss://cdp.hermesbrowsers.com/ws?token=$HERMES_TOKEN.
Connection URL
wss://cdp.hermesbrowsers.com/ws?token=<token>&browser=<lightpanda|chrome|cloak>&proxy=<name>&country=<cc>&timeout=<min>&profile=<name>&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:
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):
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):
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=<token>&browser=chrome, written <url> below.
- Hermes Agent:
/browser connect <url>in chat, or setbrowser.cdp_url(orBROWSER_CDP_URL). - OpenClaw: add a remote profile,
browser.profiles.hermes.cdpUrl: "<url>". - Claude Code:
claude mcp add hermes -- npx @playwright/mcp@latest --cdp-endpoint "<url>" - Codex:
codex mcp add hermes -- npx @playwright/mcp@latest --cdp-endpoint "<url>" - 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 settingbrowser.enabled: false, since omp hides browser MCP servers while its own browser is on):
{
"mcpServers": {
"hermes": { "command": "npx", "args": ["@playwright/mcp@latest", "--cdp-endpoint", "<url>"] }
}
}- pi: has no MCP by design; ask it to run a Puppeteer or Playwright script that connects to
<url>(see Examples).
REST API (persistent sessions)
Base URL https://cdp.hermesbrowsers.com. Authenticate with Authorization: Bearer <token> (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.
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}'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), acceptscountry
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: launch a Chrome or CloakBrowser browser (proxy, country, profile) without code, open its live view, stop it
- Sessions: every session with duration, bandwidth, close reason and its CDP message log
- Tokens: create, show/copy, disable, delete and limit API tokens
- Proxies: shared and dedicated proxies
- 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: 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_URLis preset. Run history is under Script runs - 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.