api reference.
Three endpoints. JSON in, JSON out, and a CDP websocket where the browser lives. Everything below works with curl.
# basics
base url https://api.guise.sh
auth x-api-key: <key> (get one at guise.sh/keys)
content application/json────────────────────────────────────────────────────────────────
POST/v1/sessions
Create a browser. One session is one browser — warm, wired to its egress, handed over as a CDP websocket. ~150ms end to end.
proxystringEgress tier:"residential"(default) or"dc". You can omit this — residential is the right answer for almost everything.ttlSecnumberSelf-destruct timer, 30–3600 seconds. Default 900. The browser is destroyed when it fires — nothing idle to babysit.
# request
curl -s -X POST https://api.guise.sh/v1/sessions \
-H "x-api-key: $GUISE_KEY" \
-d '{"ttlSec":1800}'# response — 200
{
"id": "0d66042b-e723-4fa7-9d7d-c7ef61317bd8",
"status": "ready",
"browser": "Chrome/151.0.7922.34",
"connectUrl": "https://api.guise.sh/v1/sessions/0d66042b-…/cdp",
"wsUrl": "wss://api.guise.sh/v1/sessions/0d66042b-…/cdp",
"egress": { "ip": "203.0.113.42", "tier": "residential" },
"createdAt": "2026-08-17T01:48:40.965Z",
"expiresAt": "2026-08-17T02:18:40.965Z"
}GET/v1/sessions
List your live sessions.
# response — 200 · a bare array
[ { "id": "93a8f457-…", "status": "ready",
"browser": "Chrome/151.0.7922.34",
"connectUrl": "https://api.guise.sh/v1/sessions/93a8f457-…/cdp",
"egress": { "ip": "203.0.113.17", "tier": "residential" },
"createdAt": "…", "expiresAt": "…" } ]GET/v1/sessions/:id
Status of one session: connectUrl, tier, and time left before the TTL reaper takes it.
DELETE/v1/sessions/:id
Kill it now. The browser is destroyed — disk and all — never recycled. Returns { "deleted": "<id>" }.
────────────────────────────────────────────────────────────────
## connect
connectUrl is a plain CDP websocket. Anything that speaks CDP works — no SDK, no wrapper.
# playwright (node)
const b = await chromium.connectOverCDP(session.connectUrl);
const page = await b.contexts()[0].newPage();
await page.goto("https://example.com");# puppeteer
const b = await puppeteer.connect({ browserWSEndpoint: session.connectUrl });
const page = await b.newPage();# playwright (python)
b = playwright.chromium.connect_over_cdp(session["connectUrl"])
page = b.contexts[0].new_page()────────────────────────────────────────────────────────────────
## proxy tiers
"residential"Sticky residential exit, one per session, held for the session’s lifetime. The default — right for anything that checks who you are."dc"Datacenter egress. For APIs, scrapes that don’t care, and dev loops.
────────────────────────────────────────────────────────────────
## errors
400malformed body — check proxy tier and ttlSec bounds401missing or unknown x-api-key404no such session — already reaped or never existed429slow down — retry with backoff503pool momentarily empty — retry-after header tells you when