Reconnecting to sessions in BAP
reconnect() keeps the browser alive after your connection closes and hands you the endpoints to come back to it. That's how a session survives a client restart, moves between processes, or gets handed from BAP to Puppeteer mid-run.
- A Browserless API token from your account dashboard
- The BAP SDK installed and connecting, from the BAP Quickstart
How reconnects work
Normally the browser shuts down when your page's WebSocket closes. Calling reconnect() changes that: after you disconnect, the browser stays up for the timeout you passed (default 30000 milliseconds) waiting for a new connection. The call returns the URLs a future connection needs. Nothing about your current connection changes, so you keep working on the page and disconnect whenever you're ready.
- TypeScript
- Python
import Browserless from "@browserless.io/bap-ts";
const TOKEN = "YOUR_API_TOKEN_HERE";
const browser = Browserless.connect({
browserWSEndpoint: "wss://production-sfo.browserless.io/chromium/bql",
token: TOKEN,
});
try {
const page = await browser.newPage();
await page.goto("https://example.com/dashboard");
// After close(), the browser now survives for 60 seconds waiting for us.
const session = await page.reconnect({ timeout: 60_000 });
console.log(session.browserQLEndpoint);
} finally {
// Safe either way: after a successful reconnect() the keep-alive window
// outlives this close; before one, closing prevents a leaked session.
await browser.close();
}
import bap.sync_api as bap
TOKEN = "YOUR_API_TOKEN_HERE"
with bap.Browserless.connect(
browser_ws_endpoint="wss://production-sfo.browserless.io/chromium/bql",
token=TOKEN,
) as browser:
with browser.page() as page:
page.goto("https://example.com/dashboard")
# After the block exits, the browser survives for 60 seconds waiting for us.
session = page.reconnect(timeout=60000)
print(session["browserQLEndpoint"])
Response:
https://production-sfo.browserless.io/chromium/bql/e4f5a6b7-c8d9-4012-a3b4-c5d6e7f8a9b0
The endpoints you get back
The response carries four URLs, each for a different way back in. None of them include your token, so append it when you connect.
| Field | Reconnects | Use it with |
|---|---|---|
browserQLEndpoint | The BrowserQL session | BAP and raw BQL queries |
browserWSEndpoint | The browser over CDP | Puppeteer or Playwright connect() |
devtoolsFrontendUrl | Chrome DevTools remotely | A regular browser, for inspection |
webSocketDebuggerUrl | One page over CDP | Libraries that attach to a page instead of a browser |
Continue the session from BAP
browserQLEndpoint comes back as an https:// URL for HTTP-based BQL queries. BAP talks BrowserQL over WebSocket, so swap the scheme to wss:// and connect a fresh browser to it:
- TypeScript
- Python
// The returned endpoint is https://; BAP connects over WebSocket.
const endpoint = session.browserQLEndpoint!.replace(/^https/, "wss");
const resumed = Browserless.connect({
browserWSEndpoint: endpoint,
token: TOKEN,
});
try {
const samePage = await resumed.newPage();
// Still on the dashboard: this is the same browser, same state.
console.log(await samePage.url());
} finally {
await resumed.close();
}
# The returned endpoint is https://; BAP connects over WebSocket.
endpoint = session["browserQLEndpoint"].replace("https", "wss", 1)
with bap.Browserless.connect(
browser_ws_endpoint=endpoint,
token=TOKEN,
) as resumed:
with resumed.page() as same_page:
# Still on the dashboard: this is the same browser, same state.
print(same_page.url())
Response:
https://example.com/dashboard
Cookies, storage, and the open page all persist, because it's the same browser process that never shut down.
Hand the session to Puppeteer or Playwright
browserWSEndpoint is a CDP URL, which means a session that BAP set up, solved a CAPTCHA in, or navigated through a login can be finished by CDP tooling:
import puppeteer from "puppeteer-core";
const TOKEN = "YOUR_API_TOKEN_HERE";
// The endpoint BAP's reconnect() returned, plus your token.
const browser = await puppeteer.connect({
browserWSEndpoint: `${session.browserWSEndpoint}?token=${TOKEN}`,
});
const [page] = await browser.pages();
console.log(await page.title());
// Terminate the session when done; a browser left to wait out its
// reconnect timeout still bills and holds a concurrency slot.
await browser.close();
This is the escape hatch for the methods BAP deliberately doesn't have, such as arbitrary evaluate() with argument passing. Do the protected part in BAP, then reconnect into Puppeteer for the rest.
Timeout limits and billing
The maximum reconnect TTL equals your plan's maximum session duration:
| Plan | Maximum Session Duration |
|---|---|
| Free | 2 minutes |
| Prototyping (20k) | 15 minutes |
| Starter (180k) | 30 minutes |
| Scale (500k) | 60 minutes |
| Enterprise (self-hosted) | Custom |
Passing a timeout above your plan's maximum fails immediately:
"Reconnect timeout (Xms) exceeds the maximum allowed limit (Yms)."
The maximum is an upper bound, not a way to reset the session clock:
- The TTL is an idle grace period: how long the browser is held after you disconnect, waiting for you to come back.
- Your plan's maximum session duration is an absolute deadline measured from when the browser started. A reconnect is always cut short by that deadline, so a 60-minute reconnect requested 50 minutes into a Scale session holds the browser for 10 minutes, not 60.
- Repeated reconnects cannot push that deadline out. A session cannot be kept alive past its original maximum by reconnecting again.
- Each reconnect is a new browser connection, so it's billed like any other connection.
- Terminate the session as soon as you are done. A browser held open for its remaining TTL still occupies a concurrency slot.
FAQ & Troubleshooting
My reconnect endpoint stopped working after a minute
The timeout you passed is an idle grace period measured from disconnect. Once it elapses with no new connection, the browser terminates and the endpoint dies. Call reconnect() again on each new connection to keep the chain going, within your plan's maximum session duration.
I get an authorization error connecting to the returned endpoint
Returned endpoints never include token information. Pass your token the same way as a normal connection: the token option in BAP, or ?token= appended to the URL for Puppeteer and Playwright.
Does the session keep billing while nobody is connected?
Yes. A browser waiting out its reconnect timeout occupies a concurrency slot like any connected session, and each reconnection is billed as a new connection. Close sessions you're done with instead of letting the timeout expire.
Can I raise the timeout above my plan's session limit?
No. A timeout beyond the plan maximum fails immediately with Reconnect timeout (Xms) exceeds the maximum allowed limit (Yms)., and reconnecting never extends the absolute deadline measured from when the browser started.