Sessions & connections
Create, connect, and release an isolated browser.
With SDK imports from the Quickstart:
const client = new TabSail();
await client.withSession({ timeoutSeconds: 300 }, async (session) => {
const grant = await client.sessions.connections.create(session.id, { type: "cdp" });
// Connect your browser client using grant.url.
});The owned scope creates, waits for readiness, then closes and confirms release.
Create parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
timeoutSeconds | integer | No | Instance default | Running lifetime, 60–3,600 seconds |
idleTimeoutSeconds | integer or null | No | null | Idle expiry, 60–3,600 seconds; null disables |
browser | object | No | {} | Browser configuration |
profile | object | No | None | Saved browser state |
region | string | No | auto | auto, west, or asia |
viewport | object | No | Instance default | Width and height, each 320–4,096 |
metadata | object | No | {} | Up to 10 string entries; keys ≤64, values ≤256 characters |
Python uses timeout_seconds. Unknown creation fields are rejected.
Lifecycle
starting → ready → closing → closed
└─────────────→ failed| State / field | Meaning |
|---|---|
starting | Accepted; startup is in progress |
ready | Available; inspect controller before control |
closing | Stop requested; still occupies capacity |
closed / failed | Management outcome; release may still be pending |
releasedAt | Non-null confirms resource release |
Running lifetime begins at readiness. Startup and grant deadlines are separate. Disconnecting a client does not stop the remote browser.
Explicit ownership
With an initialized client:
const session = await client.sessions.create({ timeoutSeconds: 300 });
try {
await client.sessions.waitUntilReady(session.id);
// Connect and run your workflow.
} finally {
await client.sessions.close(session.id);
await client.sessions.waitUntilReleased(session.id);
}Persist the session ID and creation key when work spans processes.
Connections
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | cdp or live |
mode | string | For Live | view or control |
handoffId | string | For control | Active handoff ID |
CDP requires automation control; Live control requires a handoff. Treat the URL as a credential. expiresAt limits new handshakes.
Reconnect
If the session is ready and automation controls it, request a fresh grant and reconnect to its existing context and pages. A new session does not inherit the old browser's memory.
Extend or keep alive
await client.sessions.update(sessionId, {
timeoutSeconds: 600, // New total lifetime from startedAt.
idleTimeoutSeconds: 120,
});
await client.sessions.touch(sessionId); // Explicit idle keepalive.
await client.sessions.update(sessionId, { idleTimeoutSeconds: null });Python: sessions.update(id, timeout_seconds=600, idle_timeout_seconds=120) and sessions.touch(id). HTTP: PATCH /v1/browser-sessions/{id} and POST /v1/browser-sessions/{id}/touch with an empty body.
The total lifetime cannot decrease or exceed 3,600 seconds. An extension reserves only the additional credit budget; insufficient credits leave the old lifetime unchanged. Repeating the same total lifetime adds no second reservation. An ended session cannot be revived.
Idle activity includes explicit touch, browser actions, page evaluation, and Live control input. GET, SSE, CDP setup, and read-only Live viewing do not renew it. Idle timeout also applies during human handoff. The paid lifetime remains the upper bound. Inspect lastActivityAt and closeReason (timeout or idle_timeout).
See configuration, capacity waiting, and resource fields.