Skip to main content

Session API Integration

The Session API provides explicit programmatic control over browser session lifecycle while enabling BQL (BrowserQL) query execution against persistent sessions. This approach is ideal for advanced automation workflows that require maintaining browser state across multiple script runs, user authentication persistence, and precise session management.

Stealth Sessions Required

BQL functionality is only available for stealth sessions. When creating a session, you must set stealth: true to receive the browserQL property in the response.

How Session API with BQL Works

When you create a stealth session through the Session API, Browserless returns a browserQL property containing a fully-qualified URL for running BQL queries against that specific session. This enables you to:

  • Maintain browser state including cookies, localStorage, sessionStorage, and navigation state
  • Apply session properties like proxy settings, stealth mode, and other configurations to all BQL queries
  • Disconnect and reconnect to resume automation from the exact same point
  • Manage session lifecycle programmatically with explicit creation and deletion

Creating a Session with BQL Support

const sessionConfig = {
ttl: 300000, // 5 minutes
stealth: true, // Required for BQL support
browser: 'chromium',
proxy: {
type: 'residential',
country: 'us',
sticky: true
}
};

const response = await fetch(
'https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(sessionConfig),
}
);

if (!response.ok) {
throw new Error(`Failed to create session: ${response.status}`);
}

const session = await response.json();
console.log('Session created:', session.id);
console.log('BrowserQL URL:', session.browserQL);
console.log('WebSocket URL:', session.connect);
console.log('Stop URL:', session.stop);

Session Response Schema

The session creation response includes the following properties:

PropertyTypeDescription
idstringUnique session identifier
connectstringWebSocket URL for CDP-based libraries (Puppeteer, Playwright)
browserQLstringFully-qualified URL for running BQL queries (stealth sessions only)
stopstringURL for session termination via DELETE request
ttlnumberSession time-to-live in milliseconds

Running BQL Queries Against Sessions

Once you have a session with BQL support, use the browserQL URL to execute GraphQL mutations. All session properties (proxy settings, stealth mode, etc.) automatically apply to BQL queries.

// Using the browserQL URL from session creation
const browserQLURL = session.browserQL;

const firstQuery = `
mutation FirstQuery {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
title {
title
}
evaluate(content: "localStorage.setItem('testData', 'persistent-value')") {
value
}
}
`;

const firstResponse = await fetch(browserQLURL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: firstQuery })
});

const firstResult = await firstResponse.json();
console.log('First query result:', firstResult.data);

Session State Persistence and Reconnection

One of the key benefits of Session API with BQL is the ability to disconnect and reconnect while maintaining all browser state. This includes localStorage, cookies, navigation state, and any other browser data.

// Complete example showing session creation, usage, and reconnection
const sessionResponse = await fetch('https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
ttl: 300000, // 5 minutes
stealth: true,
browser: 'chromium'
})
});

const session = await sessionResponse.json();
console.log('Session created');
console.log('Session ID:', session.id);
console.log('BrowserQL URL:', session.browserQL);

// Wait for session to be ready
console.log('Waiting for session to be ready...');
await new Promise(resolve => setTimeout(resolve, 2000));

console.log('Setting localStorage...');

const firstQuery = `
mutation FirstQuery {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
title {
title
}
evaluate(content: "localStorage.setItem('testData', 'persistent-value'); return localStorage.getItem('testData');") {
value
}
}
`;

console.log('Making first BrowserQL query...');
const firstResponse = await fetch(session.browserQL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: firstQuery })
});

const firstResult = await firstResponse.json();
console.log('First query result:', firstResult.data);

// Wait before next query
await new Promise(resolve => setTimeout(resolve, 2000));

// Check if localStorage persists
console.log('Checking if localStorage persists...');

const checkQuery = `
mutation CheckQuery {
goto(url: "https://example.com", waitUntil: networkIdle) {
status
}
evaluate(content: "localStorage.getItem('testData') || 'no-data-found'") {
value
}
url {
url
}
title {
title
}
}
`;

console.log('Making check BrowserQL query...');
const checkResponse = await fetch(session.browserQL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: checkQuery })
});

const checkResult = await checkResponse.json();
console.log('Check Query Result:');
console.log('Raw response:', JSON.stringify(checkResult, null, 2));

console.log('localStorage value:', checkResult.data?.evaluate?.value);
console.log('Current URL:', checkResult.data?.url?.url);
console.log('Page title:', checkResult.data?.title?.title);

console.log('Cleaning up...');
await new Promise(resolve => setTimeout(resolve, 1000));

const deleteResponse = await fetch(session.stop, {
method: 'DELETE'
});

if (deleteResponse.ok) {
const deleteResult = await deleteResponse.json();
console.log('Session deleted successfully:', deleteResult.message);
} else {
console.log('Session deletion failed:', deleteResponse.status);
}

const checkValue = checkResult.data?.evaluate?.value;
console.log('Final localStorage check:', checkValue);

Session Configuration Options

All session configuration options apply to both WebSocket connections and BQL queries:

ParameterTypeDefaultDescription
ttlnumber300000Time-to-live in milliseconds (max varies by plan)
stealthbooleanfalseRequired for BQL support - enables stealth mode
headlessbooleantrueRun browser in headless mode
browserstring'chromium'Browser type ('chromium' or 'chrome')
blockAdsbooleanfalseEnable ad-blocking
argsstring[][]Additional Chrome launch arguments
proxyobjectnullProxy configuration (applies to all BQL queries)

Proxy Configuration

When proxy settings are configured for a session, they automatically apply to all BQL queries executed against that session:

const sessionWithProxy = {
ttl: 300000,
stealth: true,
proxy: {
type: 'residential',
country: 'us',
state: 'california',
city: 'san-francisco',
sticky: true
}
};

// All BQL queries will use the configured proxy settings

Session Management

Checking Session Status

You can verify session status by making a simple BQL query:

const statusQuery = `
mutation CheckStatus {
url {
url
}
}
`;

const response = await fetch(session.browserQL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: statusQuery })
});

if (response.ok) {
console.log('Session is active');
} else {
console.log('Session may have expired');
}

Terminating Sessions

Sessions automatically expire after their TTL, but you can manually terminate them:

// Using the stop URL from session creation
const stopResponse = await fetch(session.stop, {
method: 'DELETE'
});

if (stopResponse.ok) {
console.log('Session terminated successfully');
}

Comparison with BQL Reconnect

The Session API approach differs from the standard BQL reconnect mutation:

FeatureSession API + BQLBQL Reconnect
Session CreationExplicit via REST APIImplicit with first query
Lifecycle ControlProgrammatic start/stopTimeout-based only
State ManagementPersistent across disconnectionsRequires active connection
Proxy ConfigurationSet once, applies to all queriesPer-query configuration
Stealth RequirementRequired for BQL supportAvailable for all BQL queries

Best Practices

  1. Always use stealth mode when you need BQL functionality
  2. Set appropriate TTL based on your workflow duration
  3. Handle session expiration gracefully in your applications
  4. Reuse sessions for multiple related operations to maintain state
  5. Configure proxy settings at session creation for consistent behavior
  6. Monitor session status before executing long-running operations

Next Steps