Managing Sessions
Once you've created a session, you can reconnect to it multiple times to continue your automation workflows while preserving browser state. This guide covers both browser session reconnection using the Browserless.reconnect
CDP command and Session API management.
Reconnecting to Browser Sessions
Browser sessions use the Browserless.reconnect
CDP command to maintain state between connections and keep browsers alive after disconnection.
Basic Reconnection
- Puppeteer
- Playwright
import puppeteer from 'puppeteer-core';
const queryParams = new URLSearchParams({
token: 'YOUR_API_TOKEN',
timeout: 60000,
}).toString();
// First connection - perform login and set up reconnection
const browser1 = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io?${queryParams}`,
});
const page1 = await browser1.newPage();
const cdp = await page1.createCDPSession();
await page1.goto('https://example.com/login');
await page1.type('#username', 'user@example.com');
await page1.type('#password', 'password123');
await page1.click('#login-button');
await page1.waitForNavigation();
// Enable reconnection - browser will stay alive for 60 seconds after disconnect
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 60000,
});
await browser1.close();
// Reconnect using the returned endpoint
const browser2 = await puppeteer.connect({
browserWSEndpoint: `${browserWSEndpoint}?${queryParams}`,
});
const [page2] = await browser2.pages();
// You're still logged in! Navigate to protected area
await page2.goto('https://example.com/dashboard');
await browser2.close();
import { chromium } from 'playwright';
const queryParams = new URLSearchParams({
token: 'YOUR_API_TOKEN',
timeout: 60000,
}).toString();
// First connection - perform login and set up reconnection
const browser1 = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io?${queryParams}`
);
const page1 = await browser1.newPage();
const cdpSession = await page1.context().newCDPSession(page1);
await page1.goto('https://example.com/login');
await page1.fill('#username', 'user@example.com');
await page1.fill('#password', 'password123');
await page1.click('#login-button');
await page1.waitForNavigation();
// Enable reconnection - browser will stay alive for 60 seconds after disconnect
const { browserWSEndpoint } = await cdpSession.send('Browserless.reconnect', {
timeout: 60000,
});
await browser1.close();
// Reconnect using the returned endpoint
const browser2 = await chromium.connectOverCDP(
`${browserWSEndpoint}?${queryParams}`
);
const page2 = await browser2.newPage();
await page2.goto('https://example.com/dashboard'); // Still logged in
await browser2.close();
Timeout-Based Sessions
You can use the Browserless.reconnect
CDP command to automatically keep browsers alive after disconnection:
- Puppeteer
- Playwright
import puppeteer from 'puppeteer-core';
// Connect and set up reconnection
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN',
});
const page = await browser.newPage();
const cdp = await page.createCDPSession();
await page.goto('https://example.com/login');
// ... perform login
// Enable reconnection - browser will stay alive for 60 seconds after disconnect
const { error, browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 60000,
});
if (error) throw error;
console.log('Reconnection endpoint:', browserWSEndpoint);
await browser.disconnect(); // Browser stays alive for 60 seconds
// Reconnect within the timeout window
const reconnectedBrowser = await puppeteer.connect({
browserWSEndpoint: `${browserWSEndpoint}?token=YOUR_API_TOKEN`,
});
import { chromium } from 'playwright';
// Connect and set up reconnection
const browser = await chromium.connectOverCDP(
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN'
);
const page = await browser.newPage();
const cdpSession = await page.context().newCDPSession(page);
await page.goto('https://example.com/login');
// ... perform login
// Enable reconnection - browser will stay alive for 60 seconds after disconnect
const { error, browserWSEndpoint } = await cdpSession.send('Browserless.reconnect', {
timeout: 60000,
});
if (error) throw new Error(error);
console.log('Reconnection endpoint:', browserWSEndpoint);
await browser.disconnect(); // Browser stays alive for 60 seconds
// Reconnect within the timeout window
const reconnectedBrowser = await chromium.connectOverCDP(
`${browserWSEndpoint}?token=YOUR_API_TOKEN`
);
Timeout and Plan Limitations
Reconnection functionality has timeout limits based on your subscription plan:
Plan | Maximum Reconnect Timeout |
---|---|
Free | 10 seconds (10,000ms) |
Prototyping/Starter | 1 minute (60,000ms) |
Scale | 5 minutes (300,000ms) |
Default timeout: 30 seconds (30,000ms) if not specified
Reconnecting to Sessions
Sessions maintain their state between connections using the Browserless.reconnect
CDP command. Here are common reconnection patterns:
Multi-Step Workflows Perfect for breaking complex automation into manageable steps:
import puppeteer from 'puppeteer-core';
let reconnectEndpoint = null;
// Step 1: Authentication
const authenticateUser = async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN&timeout=60000',
});
const page = await browser.newPage();
const cdp = await page.createCDPSession();
await page.goto('https://app.example.com/login');
await page.type('#username', 'user@example.com');
await page.type('#password', 'password123');
await page.click('#login-button');
await page.waitForNavigation();
// Set up reconnection for next step
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 60000, // 1 minute timeout
});
reconnectEndpoint = browserWSEndpoint;
await browser.close();
console.log('Authentication complete');
};
// Step 2: Data Collection
const collectData = async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: `${reconnectEndpoint}?token=YOUR_API_TOKEN&timeout=60000`,
});
const [page] = await browser.pages();
// Still authenticated from previous step
await page.goto('https://app.example.com/dashboard');
const data = await page.evaluate(() => {
return document.querySelector('#user-data').textContent;
});
await browser.close();
console.log('Data collected:', data);
return data;
};
// Execute workflow
await authenticateUser();
const userData = await collectData();
Session Recovery with Reconnection
Handle interruptions using Browserless.reconnect
to maintain session state:
const resumeWorkflow = async (existingEndpoint = null) => {
let browserEndpoint = existingEndpoint || 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN';
const browser = await puppeteer.connect({
browserWSEndpoint: browserEndpoint,
});
const page = await browser.newPage();
const cdp = await page.createCDPSession();
// Check current state
await page.goto('https://app.example.com');
const isLoggedIn = await page.$('#user-menu') !== null;
if (!isLoggedIn) {
console.log('Session expired, re-authenticating...');
await page.goto('https://app.example.com/login');
// ... perform login
} else {
console.log('Session still active, continuing...');
await page.goto('https://app.example.com/dashboard');
}
// Set up reconnection before closing
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 60000,
});
await browser.close();
return browserWSEndpoint; // Return for potential reconnection
};
Long-Running Processes with Reconnection
Use Browserless.reconnect
for session persistence during long operations:
const processLargeDataset = async (startPage = 1) => {
// Connect and set up reconnection for maintaining session between chunks
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN',
});
const page = await browser.newPage();
const cdp = await page.createCDPSession();
// Set up reconnection with 5 minute timeout
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 300000, // 5 minutes
});
// Resume from where we left off
await page.goto(`https://app.example.com/data?page=${startPage}`);
let currentPage = startPage;
const maxPages = 100;
while (currentPage <= maxPages) {
console.log(`Processing page ${currentPage}`);
// Process current page data
const pageData = await page.evaluate(() => {
return Array.from(document.querySelectorAll('.data-item')).map(item => item.textContent);
});
// Save progress
await page.evaluate((page) => {
localStorage.setItem('lastProcessedPage', page.toString());
}, currentPage);
// Navigate to next page
currentPage++;
if (currentPage <= maxPages) {
await page.goto(`https://app.example.com/data?page=${currentPage}`);
}
}
await browser.close(); // Reconnection keeps session alive for potential reconnection
};
Managing Session API
Session API provides explicit control over session lifecycle with WebSocket connections for automation libraries.
Connecting to Session API
After creating a session with the Session API, use the WebSocket endpoint to connect your automation library:
- Puppeteer
- Playwright
- Python
import puppeteer from 'puppeteer-core';
// Assume you have a sessionId from session creation
const sessionId = 'session-abc123';
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io/session/connect/${sessionId}?token=YOUR_API_TOKEN`,
});
const page = await browser.newPage();
await page.goto('https://example.com');
// Session state is maintained by the Session API
await page.evaluate(() => {
localStorage.setItem('myData', 'api-session-value');
});
await browser.close(); // Session remains active
import { chromium } from 'playwright';
const sessionId = 'session-abc123';
const browser = await chromium.connectOverCDP(
`wss://production-sfo.browserless.io/session/connect/${sessionId}?token=YOUR_API_TOKEN`
);
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto('https://example.com');
await browser.close(); // Session persists
import asyncio
from playwright.async_api import async_playwright
session_id = "session-abc123"
async def main():
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(
f"wss://production-sfo.browserless.io/session/connect/{session_id}?token=YOUR_API_TOKEN"
)
context = browser.contexts[0]
page = await context.new_page()
await page.goto("https://example.com")
await browser.close() # Session remains active
asyncio.run(main())
Session State Persistence
Both session types preserve browser state, but handle it differently:
- Browser Sessions
- Session API
// Browser sessions persist state using Browserless.reconnect
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN',
});
const page = await browser.newPage();
const cdp = await page.createCDPSession();
await page.goto('https://example.com');
// Set various types of state
await page.evaluate(() => {
// Local storage persists
localStorage.setItem('user_pref', 'dark_mode');
// Session storage persists
sessionStorage.setItem('temp_data', 'workflow_state');
// IndexedDB persists
const request = indexedDB.open('myDB', 1);
// ... IndexedDB operations
});
// Cookies are automatically saved
await page.setCookie({
name: 'session_token',
value: 'abc123',
domain: 'example.com'
});
// Set up reconnection before closing
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 60000,
});
await browser.close();
// All state is preserved for reconnection within timeout window
// Use browserWSEndpoint for reconnection
// Session API maintains state through explicit session management
const sessionId = 'session-xyz789';
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io/session/connect/${sessionId}?token=YOUR_API_TOKEN`,
});
const page = await browser.newPage();
await page.goto('https://example.com');
// State is preserved within the session's timeout period
await page.evaluate(() => {
localStorage.setItem('api_session_data', 'preserved_value');
});
await browser.close();
// Reconnect to the same session
const browser2 = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io/session/connect/${sessionId}?token=YOUR_API_TOKEN`,
});
const page2 = await browser2.newPage();
const data = await page2.evaluate(() =>
localStorage.getItem('api_session_data')
); // Returns 'preserved_value'
await browser2.close();
Reconnection with Retry Logic
Implement retry logic for reliable session connections:
- Standard Session Retry
- Session API Retry
import puppeteer from 'puppeteer-core';
async function connectWithRetry(browserEndpoint, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const browser = await puppeteer.connect({
browserWSEndpoint: browserEndpoint,
});
return browser;
} catch (error) {
console.log(`Connection attempt ${i + 1} failed:`, error.message);
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
// Usage with reconnection setup
try {
const browser = await connectWithRetry('wss://production-sfo.browserless.io?token=YOUR_API_TOKEN');
const page = await browser.newPage();
const cdp = await page.createCDPSession();
// Set up reconnection
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout: 60000,
});
// ... your automation
await browser.close();
// Use browserWSEndpoint for potential reconnection
} catch (error) {
console.error('Failed to connect after retries:', error);
}
async function connectToApiSession(sessionId, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
// First check if session exists
const statusResponse = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`
);
if (!statusResponse.ok) {
throw new Error(`Session ${sessionId} not found or expired`);
}
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io/session/connect/${sessionId}?token=YOUR_API_TOKEN`,
});
return browser;
} catch (error) {
console.log(`Connection attempt ${i + 1} failed:`, error.message);
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
}
}
}
Next Steps
- Closing Sessions - Learn how to properly terminate sessions and clean up resources