Concepts
Sessions
A session is one run of a profile on one machine — its lifecycle, attach tickets and how it ends.
A session is a profile open on a machine. A profile has at most one live session at a time, and every session is fenced: a machine that lost its claim can no longer act for it.
Apps that run many accounts can hold a profile's browser instead of starting and stopping it themselves — see Hold a browser from your app.
Lifecycle
| State | Meaning | What to do |
|---|---|---|
queued | Accepted, waiting for the machine | Wait |
preflight | Checking network, proxy and profile data | Wait |
starting | Launching the browser | Wait |
ready | Browser running; attach is possible | Attach or watch |
quiescing | Finishing before stop (data being saved) | Wait |
stopping | Closing the browser | Wait |
closed | Ended; no browser process remains | Done |
failed | Could not start or ended with an error | Read the reason, then start again |
recovery_required | Ended uncertainly; the profile needs a decision | Recover, then start again |
Poll sessions.get, or subscribe to the session.ready, session.failed and session.closed webhooks. The SDK's waitForSession and the CLI's sessions wait only wait: stopping the wait never stops the session.
Starting
sessions.start needs a profile_id, a device_id and a command_id. Typed refusals:
BUSY— the profile is already open;error.detailsnames that session.SYNC_PENDING— another machine still holds newer data for this profile.RECOVERY_REQUIRED— the last session ended uncertainly;error.detailsnames it. See Recovering.QUOTA_EXCEEDED— the workspace already runs every concurrent session its limit allows.
Attaching
sessions.attach issues a ticket for one ready session, valid for ttl_seconds (30–900, default 300), together with the machine's local broker address. Connect from that machine with the ticket as a bearer header — see Attach with Playwright. Closing your Playwright connection does not stop the session.
Stopping
sessions.stop is the only call that ends a session. It is reported closed only after the machine proves no browser process is left; profile data is then sealed and uploaded.
Recovering
A session ends uncertainly when its machine stops confirming it — powered off, offline, or wiped — or reports a stop it cannot prove. Browlix never guesses: the session becomes recovery_required and the profile stays closed everywhere, so two browsers can never write the same profile.
When you know the machine is gone, call sessions.recover with a command_id. The session is settled as failed with reason RECOVERED, the profile can open again (with a higher fence) and a late report from the old machine is refused; if the old browser comes back it is told to stop. The call needs device.manage — owner or admin, and a key with that scope — and is audited. While the machine still confirms the session it answers CONFLICT: stop it instead.
curl -s -X POST "$BROWLIX_API/sessions/$SESSION_ID/recover" \
-H "Authorization: Bearer $BROWLIX_API_KEY" -H "Content-Type: application/json" \
-d "{\"command_id\":\"$(uuidgen)\"}"If the machine also held profile data it never uploaded, opening elsewhere still answers SYNC_PENDING; profiles.sync.release drops that machine's copy on purpose.
History
sessions.list with scope=live returns open sessions; scope=recent returns the last 7 days, optionally for one profile with profile=<profile id>.
