Appearance
Connecting automation tools
POST /profiles/{id}/start returns where the browser can be controlled:
json
{
"id": "40df428e",
"status": "running",
"already_running": false,
"device_id": "2ebxdzmior",
"pid": 5120,
"debug_port": 49821,
"cdp_url": "http://127.0.0.1:49821",
"ws_endpoint": null
}Use cdp_url (or debug_port) from the computer where the profile is running.
| Tool | How to connect |
|---|---|
| Playwright (Node) | chromium.connectOverCDP(run.cdp_url) |
| Playwright (Python) | p.chromium.connect_over_cdp(run["cdp_url"]) |
| Puppeteer | puppeteer.connect({ browserURL: run.cdp_url, defaultViewport: null }) |
| Selenium | options.debugger_address = "127.0.0.1:<debug_port>" |
ws_endpoint is the full WebSocket address when the app reports it; older app versions return null. cdp_url always works.
Rules that keep profiles safe
- Use the existing context.
browser.contexts()[0]is the profile. A new context is a clean, separate session without the profile's cookies. - Do not set a viewport or user agent from your script. They belong to the profile's fingerprint. In Puppeteer pass
defaultViewport: null. - Disconnect, then stop.
browser.close()on a CDP connection only disconnects. Callprofiles.stop(id)so the app closes the browser and saves the profile. - Calling start twice is safe. If the profile is already running on that device, you get the same
cdp_urlwithalready_running: true.
Slow first start
The first start of a browser version downloads its core. The request waits up to timeout seconds (default 120). If the browser is still not up, the API answers 202 with "status": "starting"; poll GET /profiles/{id}/status until running_on is filled. The SDKs do this for you.
More than one computer
If several of your computers are online, pass device_id to start. List them with GET /devices. A profile can be started on any of your devices; its data follows it.