Watch a session without signing in
Mint a login-free watch link for a running session: read-only by default, valid up to an hour, with the ticket in the URL fragment so it never reaches a log.
Last updated:
Two links, two audiences
A session can be watched two ways. GET /v1/sessions/:id/live-view returns a dashboard deep link: whoever opens it signs in, and an owner can take the mouse. POST /v1/sessions/:id/watch-link returns a watch link that needs no account: a viewer page the control plane serves, driven by a ticket that lives in the URL fragment. The fragment is never sent to a server, so the ticket appears in no access log, and the page exchanges it for the sixty-second socket tokens the fleet actually checks — which is why the link survives a dropped connection where a raw socket ticket would not.
/v1/sessions/:id/watch-link
Mints a watch link for a session you own. Requires a configured public base URL (`watch` in `GET /v1/me` features).
Body
| Name | Type | Description |
|---|---|---|
ttlSeconds
|
integer | How long the link opens the viewer, 60 to 3600. Default 3600. |
allowTakeover
|
boolean | Default `false`: the viewer can watch and nothing else. `true` lets the holder request the write lease, exactly as an owner in the dashboard would. The MCP tool never sets this. |
Response
| Name | Type | Description |
|---|---|---|
url
|
string | `{base}/watch/{sessionId}#w=<ticket>`. Share it as a whole; the fragment is the credential. |
expiresAt
|
timestamp | When the ticket stops opening the viewer. The session’s own lifetime is separate. |
readOnly
|
boolean | What the link permits. |
Mint a link
import { Browserberg } from '@browserberg/sdk';
const bb = new Browserberg({
apiKey: process.env.BROWSERBERG_API_KEY!,
baseUrl: 'https://browserberg.com',
});
await using session = await bb.sessions.create({ ttlSeconds: 600 });
// Read-only by default, valid an hour. The ticket travels in the URL fragment,
// so it never reaches a server log; hand the link to a person.
const link = await bb.sessions.watchLink(session.id, { ttlSeconds: 900 });
console.log('url:', link.url.replace(/#w=.*$/, '#w=<ticket>'));
console.log('readOnly:', link.readOnly);
console.log('expires:', link.expiresAt > new Date().toISOString() ? 'in the future' : 'already');
import os
from browserberg import Browserberg
bb = Browserberg(os.environ["BROWSERBERG_API_KEY"], base_url="https://browserberg.com")
with bb.sessions.create(ttl_seconds=600) as session:
link = bb.sessions.watch_link(session.id, ttl_seconds=900)
print("url:", link.url.split("#")[0] + "#w=<ticket>")
print("read_only:", link.read_only)
url: https://browserberg.com/watch/6jx-s0XFblsf4840RhsATQ#w=<ticket>
readOnly: true
expires: in the future
Warning · A link is a credential
Anyone holding the URL can watch the session until `expiresAt`, and drive it if you allowed takeover. Send it to the person who needs it, over a channel you trust, and keep the TTL as short as the hand-off needs.