Persisting State
For more control over session lifecycle, you can use the REST API to explicitly create and manage sessions through HTTP endpoints. This approach provides programmatic session management with advanced control over session configuration and monitoring, and is designed for use cases requiring persistent state across longer periods of time. This method allows you to persist data for multiple days, depending on your plan, even when the browser is closed.
This document covers the Sessions API (REST API for explicit session management). For Browser Sessions using Browserless.reconnect
CDP command, see Standard Sessions.
Persisting State Workflow
Create Session
Create a new session using the REST API with the desired configuration. You can save the session object returned in your database so you can manage these sessions for multiple days (Depending on your plan).
- JavaScript
- Python
- cURL
import fetch from 'node-fetch';
async function createSession(apiKey, sessionConfig) {
try {
const response = await fetch(`https://production-sfo.browserless.io/session?token=${apiKey}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(sessionConfig),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const session = await response.json();
return session;
} catch (error) {
console.error("Error creating session:", error.message);
throw error;
}
}
(async () => {
try {
const sessionConfig = {
ttl: 180000,
stealth: true,
headless: false,
};
const session = await createSession("YOUR_API_TOKEN_HERE", sessionConfig);
console.log("Session created: ", session);
} catch (error) {
console.error("Failed to create session:", error);
}
})();import requests
import json
async def create_session(api_key, session_config):
try:
response = requests.post(
f"https://production-sfo.browserless.io/session?token={api_key}",
headers={
"Content-Type": "application/json",
},
json=session_config
)
if not response.ok:
raise Exception(f"HTTP error! status: {response.status_code}")
session = response.json()
print("Session created:", session)
return session
except Exception as error:
print(f"Error creating session: {error}")
raise error
# Create session using async function
import asyncio
async def main():
try:
session_config = {
"ttl": 180000,
"stealth": True,
"headless": False,
}
session = await create_session("YOUR_API_TOKEN_HERE", session_config)
print(f"Session ID: {session['id']}")
print(f"Connect URL: {session['connect']}")
except Exception as error:
print(f"Failed to create session: {error}")
asyncio.run(main())#!/bin/bash
# Function to create session with error handling
create_session() {
local api_key="$1"
local session_config='{
"ttl": 180000,
"stealth": true,
"headless": false
}'
echo "Creating session..."
response=$(curl -s -w "\n%{http_code}" -X POST "https://production-sfo.browserless.io/session?token=${api_key}" \
-H "Content-Type: application/json" \
-d "$session_config")
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | head -n -1)
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
echo "Session created successfully:"
echo "$body" | jq '.'
# Extract session details
session_id=$(echo "$body" | jq -r '.id')
connect_url=$(echo "$body" | jq -r '.connect')
echo "Session ID: $session_id"
echo "Connect URL: $connect_url"
else
echo "Error creating session (HTTP $http_code):"
echo "$body"
exit 1
fi
}
# Usage
create_session "YOUR_API_TOKEN_HERE"Connect to Session
Use the session connect URL from step 1 to connect your automation library to the created session:
- Puppeteer
- Python
import puppeteer from "puppeteer-core";
async function connectToSession(connectUrl) {
try {
const browser = await puppeteer.connect({
browserWSEndpoint: connectUrl,
});
const pages = await browser.pages();
const page = pages[0] || await browser.newPage();
return { browser, page };
} catch (error) {
console.error("Error connecting to session:", error.message);
throw error;
}
}
// Use the WSS from step 1
const connectUrl = "wss://production-sfo.browserless.io/e/53...f2/session/connect/27...11?token=...";
const { browser, page } = await connectToSession(connectUrl);
await page.goto("https://example.com");
await page.close();import asyncio
from playwright.async_api import async_playwright
async def connect_to_session(connect_url):
try:
async with async_playwright() as p:
# Connect to the existing session
browser = await p.chromium.connect_over_cdp(connect_url)
context = browser.contexts[0] # Use existing browser context
page = await context.new_page()
return { "browser": browser, "page": page }
except Exception as error:
print(f"Error connecting to session: {error}")
raise error
# Use the WSS from step 1
connect_url = "wss://production-sfo.browserless.io/e/53...f2/session/connect/27...11?token=..."
browser_data = await connect_to_session(connect_url)
browser = browser_data["browser"]
page = browser_data["page"]
await page.goto("https://example.com")
await browser.close()Close Session
When you're finished with your session, properly close it to free up resources. Use the
session.stop
URL from the previous steps as thesessionCloseURL
:- Javascript
- Python
import fetch from 'node-fetch';
const stopSession = async (sessionCloseURL) => {
try {
const urlWithForce = `${sessionCloseURL}&force=true`; //force is optional
console.log('Stopping session with URL:', urlWithForce);
const response = await fetch(urlWithForce, {
method: 'DELETE',
});
if (response.ok) {
const result = await response.json();
return true;
} else {
console.error(`Failed to stop session ${sessionCloseURL}:`, response.status);
const errorText = await response.text();
console.error('Error response:', errorText);
return false;
}
} catch (error) {
console.error(`Error stopping session ${sessionCloseURL}:`, error);
return false;
}
};
// Use stop URL from step 1
await stopSession('https://production-sfo.browserless.io/e/57..09/session/57..09?token=...');import requests
async def stop_session(session_close_url):
try:
url_with_force = f"{session_close_url}&force=true" # force is optional
print('Stopping session with URL:', url_with_force)
response = requests.delete(url_with_force)
if response.ok:
result = response.json()
return True
else:
print(f"Failed to stop session {session_close_url}:", response.status_code)
print('Error response:', response.text)
return False
except Exception as error:
print(f"Error stopping session {session_close_url}:", error)
return False
# Use stop URL from step 1
await stop_session('https://production-sfo.browserless.io/e/57..09/session/57..09?token=...')
Complete Example
Here's a complete example that demonstrates the full session lifecycle - creating a session, connecting to it, persisting data, and properly cleaning up once you no longer need to reconnect to it.
- JavaScript
- Python
import fetch from 'node-fetch';
import puppeteer from "puppeteer-core";
const apiKey = "YOUR_API_TOKEN_HERE"; // Replace with your actual API key
const sessionConfig = {
ttl: 180000,
stealth: true,
headless: false,
};
async function createSession(apiKey, sessionConfig) {
try {
const response = await fetch(`https://production-sfo.browserless.io/session?token=${apiKey}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(sessionConfig),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const session = await response.json();
return session;
} catch (error) {
console.error("Error creating session:", error.message);
throw error;
}
}
async function connectToSession(connectUrl) {
try {
const browser = await puppeteer.connect({
browserWSEndpoint: connectUrl,
});
const pages = await browser.pages();
const page = pages[0] || await browser.newPage();
return { browser, page };
} catch (error) {
console.error("Error connecting to session:", error.message);
throw error;
}
}
const stopSession = async (sessionCloseURL) => {
try {
const urlWithForce = `${sessionCloseURL}&force=true`;
console.log('Stopping session with URL:', urlWithForce);
const response = await fetch(urlWithForce, {
method: 'DELETE',
});
if (response.ok) {
const result = await response.json();
return true;
} else {
console.error(`Failed to stop session ${sessionCloseURL}:`, response.status);
const errorText = await response.text();
console.error('Error response:', errorText);
return false;
}
} catch (error) {
console.error(`Error stopping session ${sessionCloseURL}:`, error);
return false;
}
};
(async () => {
try {
const session = await createSession(apiKey, sessionConfig);
const { connect: connectUrl, stop: stopUrl } = session;
console.log("Step 1: Created session and saved connect WSS and stop URL:", connectUrl);
const { browser, page } = await connectToSession(connectUrl);
console.log("Step 2: Connected to the session using Puppeteer:", page);
await page.goto("https://docs.browserless.io/");
await page.click('.toggle_vylO.colorModeToggle_x44X');
await page.screenshot({path:"FirstRun.jpg"});
console.log("Toggled dark mode and took a screenshot");
await browser.close();
const { browser: browser2, page: page2 } = await connectToSession(session.connect);
console.log("Connected to the session again.");
await page2.goto("https://docs.browserless.io/");
await page2.screenshot({path:"SecondRun.jpg"});
console.log("Took a screenshot and see the dark mode persisted");
await browser2.close();
await new Promise(resolve => setTimeout(resolve, 1000));
// Step 3: Only run this stopSession function once you are ready to destroy it and don't plan on connecting to this session again.
await stopSession(stopUrl);
console.log("Session stopped, you won't be able to reconnect to this session again.");
} catch (error) {
console.error("Failed to complete session workflow:", error.message);
}
})();
import asyncio
import aiohttp
from playwright.async_api import async_playwright
api_key = "YOUR_API_TOKEN_HERE" # Replace with your actual API key
session_config = {
"ttl": 180000,
"stealth": True,
"headless": False,
}
async def create_session(api_key, session_config):
try:
async with aiohttp.ClientSession() as session:
async with session.post(
f"https://production-sfo.browserless.io/session?token={api_key}",
headers={"Content-Type": "application/json"},
json=session_config
) as response:
if not response.ok:
raise Exception(f"HTTP error! status: {response.status}")
return await response.json()
except Exception as error:
print(f"Error creating session: {error}")
raise error
async def connect_to_session(connect_url):
try:
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(connect_url)
context = browser.contexts[0]
page = await context.new_page()
return {"browser": browser, "page": page}
except Exception as error:
print(f"Error connecting to session: {error}")
raise error
async def stop_session(session_close_url):
try:
url_with_force = f"{session_close_url}&force=true" # force is optional
print('Stopping session with URL:', url_with_force)
async with aiohttp.ClientSession() as session:
async with session.delete(url_with_force) as response:
if response.ok:
result = await response.json()
return True
else:
print(f"Failed to stop session {session_close_url}:", response.status)
error_text = await response.text()
print('Error response:', error_text)
return False
except Exception as error:
print(f"Error stopping session {session_close_url}:", error)
return False
async def main():
try:
session = await create_session(api_key, session_config)
connect_url = session['connect']
stop_url = session['stop']
print("Step 1: Created session and saved connect WSS and stop URL:", connect_url)
browser_data = await connect_to_session(connect_url)
browser = browser_data["browser"]
page = browser_data["page"]
print("Step 2: Connected to the session using Playwright:", page)
await page.goto("https://docs.browserless.io/")
await page.click('.toggle_vylO.colorModeToggle_x44X')
await page.screenshot(path="FirstRun.jpg")
print("Toggled dark mode and took a screenshot")
await browser.close()
browser_data2 = await connect_to_session(session['connect'])
browser2 = browser_data2["browser"]
page2 = browser_data2["page"]
print("Connected to the session again.")
await page2.goto("https://docs.browserless.io/")
await page2.screenshot(path="SecondRun.jpg")
print("Took a screenshot and see the dark mode persisted")
await browser2.close()
# Wait a moment for the session to be ready for stopping
await asyncio.sleep(1)
# Step 3: Only run this stop_session function once you are ready to destroy it and don't plan on connecting to this session again.
await stop_session(stop_url)
print("Session stopped, you won't be able to reconnect to this session again.")
except Exception as error:
print(f"Failed to complete session workflow: {error}")
asyncio.run(main())
Persisted session data duration
The data that can be persisted includes cache, cookies, localStorage, and session data. The length of time this data can be persisted depends on your plan:
Plan | Persisted Session Duration |
---|---|
Free | 1 day |
Prototyping | 7 days |
Starter | 30 days |
Scale | 90 days |
Enterprise | Custom |
You can also limit the time you want the data to be persisted by passing a ttl
option to the session API, which will expire the session data before the plan limit if desired.
Session Configuration Options
Parameter | Type | Default | Description |
---|---|---|---|
ttl | number | 300000 | Time-to-live in ms (When the session data will expire) |
stealth | boolean | false | Enable stealth mode to avoid detection |
headless | boolean | true | Run browser in headless mode |
args | string[] | [] | Additional Chrome launch arguments |
proxy | object | null | Proxy configuration |
For the complete list of all available session configuration parameters, see the Session API documentation.
Next Steps
Ready to take your session management to the next level? Explore these key areas: