For AI agents: a documentation index is available at /llms.txt
Skip to main content

Reconnect to Session

The reconnect mutation lets you reuse a running browser session across multiple BrowserQL queries instead of launching a new browser for every request. The session preserves cookies, cache, and all page state between requests, which cuts proxy bandwidth, eliminates redundant page loads, and reduces the chance of triggering bot detection.

Prerequisites

How reconnects work

The reconnect mutation returns a browserQLEndpoint URL. You send your next query to that URL to reuse the same browser. Each reconnect also resets the session's idle timer, so the browser stays alive as long as you keep reconnecting before the timeout expires.

reconnect(timeout: 30000) {
browserQLEndpoint
}

The timeout value is in milliseconds. The response includes the endpoint URL for your next query.

Response

{
"data": {
"reconnect": {
"browserQLEndpoint": "https://production-sfo.browserless.io/e/53.../chromium/bql/05..."
}
}
}

Start a Session

Send your first query to open a browser session. Include the reconnect mutation to get a reusable endpoint URL.

import fetch from 'node-fetch';

const API_KEY = "YOUR_API_TOKEN";
const BQL_ENDPOINT = `https://production-sfo.browserless.io/chromium/bql?token=${API_KEY}`;

const sessionQuery = `
mutation StartSession {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserQLEndpoint
}
}`;

async function startSession() {
const response = await fetch(BQL_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: sessionQuery }),
});

const data = await response.json();
const reconnectUrl = data.data.reconnect.browserQLEndpoint;
console.log("Reconnect URL:", reconnectUrl);
return reconnectUrl;
}

startSession();

Use the Reconnect URL

Send your next query to the reconnect URL instead of the original endpoint.

API Token Required

The browserQLEndpoint returned by the reconnect mutation does not include your API token. Append ?token=YOUR_API_TOKEN to the reconnect URL before sending subsequent requests.

const RECONNECT_BQL_ENDPOINT = "YOUR_RECONNECT_BQL_ENDPOINT" + "?token=YOUR_API_TOKEN";

const scrapeQuery = `
mutation FetchData {
text(selector: ".product-title") {
text
}
}`;

async function fetchData() {
const response = await fetch(RECONNECT_BQL_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: scrapeQuery }),
});

const data = await response.json();
console.log("Fetched Data:", data.data.text.text);
}

fetchData();

Full Example

This example starts a session, scrapes multiple pages, and periodically reconnects to extend the session timeout. Each call to reconnect resets the idle timer, so you can keep the browser alive indefinitely by reconnecting before the timeout expires.

import fetch from 'node-fetch';

const API_KEY = "YOUR_API_TOKEN";
const BQL_ENDPOINT = `https://production-sfo.browserless.io/chromium/bql?token=${API_KEY}`;

const sessionQuery = `
mutation StartSession {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
reconnect(timeout: 30000) {
browserQLEndpoint
}
}`;

async function startSession() {
const response = await fetch(BQL_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: sessionQuery }),
});

const data = await response.json();
return data.data.reconnect.browserQLEndpoint;
}

async function fetchData(reconnectUrl) {
const scrapeQuery = `
mutation FetchData {
text(selector: ".product-title") {
text
}
}`;

const response = await fetch(reconnectUrl + "?token=" + API_KEY, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: scrapeQuery }),
});

const data = await response.json();
console.log("Fetched Data:", data.data.text.text);
}

// Reconnect before the timeout to extend the session
async function refreshSession(reconnectUrl) {
const refreshQuery = `
mutation RefreshSession {
reconnect(timeout: 30000) {
browserQLEndpoint
}
}`;

const response = await fetch(reconnectUrl + "?token=" + API_KEY, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: refreshQuery }),
});

const data = await response.json();
return data.data.reconnect.browserQLEndpoint;
}

(async () => {
let reconnectUrl = await startSession();
let pagesScraped = 0;
const REFRESH_INTERVAL = 20;

for (let i = 0; i < 100; i++) {
// Reconnect periodically to reset the idle timer
if (pagesScraped >= REFRESH_INTERVAL) {
reconnectUrl = await refreshSession(reconnectUrl);
pagesScraped = 0;
}

await fetchData(reconnectUrl);
console.log(`Scraped page ${i + 1}`);
pagesScraped++;
}
})();

Reconnect Timeout Limits

The timeout parameter in the reconnect mutation controls how long the browser stays alive waiting for a reconnect. The maximum allowed value depends on your plan:

PlanMaximum Reconnection TTL
Free10 seconds (10,000ms)
Prototyping (20k)30 seconds (30,000ms)
Starter (180k)60 seconds (60,000ms)
Scale (500k) and above5 minutes (300,000ms)
Enterprise (self-hosted)Custom

Passing a timeout above your plan's limit returns an immediate error:

"Reconnect timeout (Xms) exceeds the maximum allowed limit (Yms)."
Reconnect Timeout vs Session Timeout

The reconnect timeout is not the same as your session timeout. Session timeouts control how long a BrowserQL session runs in total. The reconnect timeout only controls how long the browser waits idle between disconnects.

Terminate sessions after reconnecting

After your work is done, send a DELETE request to terminate the session immediately. Sessions that are not explicitly closed continue to occupy a concurrency slot until the timeout expires, which can cause 429 Too Many Requests errors when you run many sessions in a loop.

Build the terminate URL from the browserQLEndpoint by replacing the browser-type segment (/chromium/bql/, /chrome/bql/, or /stealth/bql/) with /browser/<browserId>. Keep the /e/<encodedToken>/ prefix intact. The path swap happens inside that prefix, not at the root:

# browserQLEndpoint (returned by reconnect)
https://<host>/e/<encodedToken>/chromium/bql/<browserId>

# terminateURL (replace only the inner path segment)
https://<host>/e/<encodedToken>/browser/<browserId>
const TOKEN = process.env.BROWSERLESS_TOKEN;
const HOST = 'https://production-sfo.browserless.io';

const res = await fetch(`${HOST}/chromium/bql?token=${TOKEN}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `mutation {
goto(url: "https://example.com", waitUntil: networkIdle) { status }
reconnect(timeout: 60000) { browserQLEndpoint }
}`,
}),
});

const { data } = await res.json();
const { browserQLEndpoint } = data.reconnect;

// ... do your work using browserQLEndpoint ...

const browserId = browserQLEndpoint.split('/').pop();
const terminateURL = browserQLEndpoint.replace(/\/(chromium|chrome|stealth)\/bql\/[^/]+$/, `/browser/${browserId}`);

await fetch(`${terminateURL}?token=${TOKEN}`, { method: 'DELETE' });

Reconnect to Puppeteer or Playwright

reconnect also returns a browserWSEndpoint you can pass to puppeteer.connect() or playwright.chromium.connectOverCDP() to attach a CDP-based library to the same session, with all state carried over.

See Reconnect using Puppeteer & Playwright for the full guide.

FAQ & Troubleshooting

My reconnect endpoint returns a connection error

The session has expired. Each reconnect resets the idle timer, but if the timeout elapses before your next request, the browser is terminated. Increase the timeout value or reconnect more frequently.

Can I reconnect to a session from a different machine?

Yes. The browserQLEndpoint URL is fully qualified and includes the session identifier. Any client that can reach the Browserless API can send queries to it.

Next steps