Skip to main content
Version: v2

Session Management Best Practices

Effective session management is crucial for optimizing performance, controlling costs, and ensuring security. This guide covers best practices for both Browser Sessions and Session API approaches.

Session Lifecycle Management

// Implement session lifecycle tracking
class SessionManager {
constructor() {
this.activeSessions = new Map();
}

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

const { sessionId } = await response.json();
this.activeSessions.set(sessionId, {
created: Date.now(),
ttl: config.ttl,
config
});

return sessionId;
}

async deleteSession(sessionId) {
if (this.activeSessions.has(sessionId)) {
await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`,
{ method: 'DELETE' }
);
this.activeSessions.delete(sessionId);
}
}

async cleanupExpiredSessions() {
const now = Date.now();
for (const [sessionId, info] of this.activeSessions) {
if (now - info.created > info.ttl) {
await this.deleteSession(sessionId);
}
}
}

async shutdown() {
// Clean up all active sessions
const deletePromises = Array.from(this.activeSessions.keys()).map(
sessionId => this.deleteSession(sessionId)
);
await Promise.all(deletePromises);
}
}

Error Handling

// Comprehensive error handling for session deletion
const safeDeleteSession = async (sessionId) => {
try {
// First check if session exists
const statusResponse = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`
);

if (statusResponse.status === 404) {
console.log(`Session ${sessionId} already expired or deleted`);
return { success: true, reason: 'already_deleted' };
}

if (!statusResponse.ok) {
throw new Error(`Session status check failed: ${statusResponse.status}`);
}

// Proceed with deletion
const deleteResponse = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`,
{ method: 'DELETE' }
);

if (deleteResponse.ok) {
const result = await deleteResponse.json();
return { success: true, result };
} else {
throw new Error(`Delete failed: ${deleteResponse.status} ${deleteResponse.statusText}`);
}

} catch (error) {
console.error(`Error deleting session ${sessionId}:`, error);
return { success: false, error: error.message };
}
};

Resource Optimization

  • Delete sessions immediately after workflow completion to free resources
  • Set appropriate timeouts based on actual workflow duration
  • Monitor session usage to optimize costs and performance
  • Implement cleanup routines for application shutdown

Security Considerations

  • Clear sensitive data before ending sessions
  • Rotate session identifiers regularly for long-running applications
  • Log session deletions for audit trails
  • Handle deletion failures gracefully to prevent resource leaks

Cost Management

Monitor Session Usage

// Track session costs and usage
const trackSessionUsage = async (sessionId) => {
const startTime = Date.now();

// Your session operations here

const endTime = Date.now();
const durationMinutes = (endTime - startTime) / 60000;

console.log(`Session ${sessionId} active for ${durationMinutes.toFixed(2)} minutes`);

// Estimated cost calculation (adjust based on your plan)
const costPerMinute = 0.01; // Example rate
const estimatedCost = durationMinutes * costPerMinute;

console.log(`Estimated cost: $${estimatedCost.toFixed(4)}`);
};

Optimization Tips

  • Use browser sessions for simple workflows where automatic cleanup is sufficient
  • Use Session API only when you need explicit control over session lifecycle
  • Set conservative timeouts and extend only when necessary
  • Clean up immediately after workflow completion

Next Steps

Implement proper session lifecycle tracking to monitor and control your browser sessions effectively.

Session Manager Pattern

// Implement session lifecycle tracking
class SessionManager {
constructor() {
this.activeSessions = new Map();
}

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

const { sessionId } = await response.json();
this.activeSessions.set(sessionId, {
created: Date.now(),
ttl: config.ttl,
config
});

return sessionId;
}

async deleteSession(sessionId) {
if (this.activeSessions.has(sessionId)) {
await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`,
{ method: 'DELETE' }
);
this.activeSessions.delete(sessionId);
}
}

async cleanupExpiredSessions() {
const now = Date.now();
for (const [sessionId, info] of this.activeSessions) {
if (now - info.created > info.ttl) {
await this.deleteSession(sessionId);
}
}
}

async shutdown() {
// Clean up all active sessions
const deletePromises = Array.from(this.activeSessions.keys()).map(
sessionId => this.deleteSession(sessionId)
);
await Promise.all(deletePromises);
}
}

Browser Session Timeout Management

// Dynamically adjust timeout based on workflow complexity
const getOptimalTimeout = (workflowType) => {
const timeoutPresets = {
'simple-scrape': 30000, // 30 seconds
'form-submission': 60000, // 1 minute
'multi-page-flow': 180000, // 3 minutes
'complex-automation': 300000 // 5 minutes
};

return timeoutPresets[workflowType] || 60000; // Default 1 minute
};

const createOptimizedSession = async (workflowType) => {
const timeout = getOptimalTimeout(workflowType);

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 optimized timeout
const { browserWSEndpoint } = await cdp.send('Browserless.reconnect', {
timeout,
});

return { browser, page, reconnectEndpoint: browserWSEndpoint, timeout };
};

Error Handling and Resilience

Implement robust error handling to ensure graceful degradation and proper resource cleanup.

Safe Session Operations

// Comprehensive error handling for session deletion
const safeDeleteSession = async (sessionId) => {
try {
// First check if session exists
const statusResponse = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`
);

if (statusResponse.status === 404) {
console.log(`Session ${sessionId} already expired or deleted`);
return { success: true, reason: 'already_deleted' };
}

if (!statusResponse.ok) {
throw new Error(`Session status check failed: ${statusResponse.status}`);
}

// Proceed with deletion
const deleteResponse = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`,
{ method: 'DELETE' }
);

if (deleteResponse.ok) {
const result = await deleteResponse.json();
return { success: true, result };
} else {
throw new Error(`Delete failed: ${deleteResponse.status} ${deleteResponse.statusText}`);
}

} catch (error) {
console.error(`Error deleting session ${sessionId}:`, error);
return { success: false, error: error.message };
}
};

Connection Retry Logic

// Retry session connection with exponential backoff
const connectWithRetry = async (endpoint, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const browser = await puppeteer.connect({
browserWSEndpoint: endpoint,
});

// Test connection
await browser.newPage();
return browser;

} catch (error) {
console.log(`Connection attempt ${attempt} failed:`, error.message);

if (attempt === maxRetries) {
throw new Error(`Failed to connect after ${maxRetries} attempts: ${error.message}`);
}

// Exponential backoff
const delay = 1000 * Math.pow(2, attempt - 1);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};

Resource Optimization

Optimize resource usage to control costs and improve performance.

Cost Management

// Track session costs and usage
const trackSessionUsage = async (sessionId) => {
const startTime = Date.now();

// Your session operations here

const endTime = Date.now();
const durationMinutes = (endTime - startTime) / 60000;

console.log(`Session ${sessionId} active for ${durationMinutes.toFixed(2)} minutes`);

// Estimated cost calculation (adjust based on your plan)
const costPerMinute = 0.01; // Example rate
const estimatedCost = durationMinutes * costPerMinute;

console.log(`Estimated cost: $${estimatedCost.toFixed(4)}`);
};

// Budget-aware session management
class BudgetAwareSessionManager {
constructor(dailyBudget = 10.00) {
this.dailyBudget = dailyBudget;
this.dailySpend = 0;
this.lastResetDate = new Date().toDateString();
}

checkBudget() {
const today = new Date().toDateString();
if (today !== this.lastResetDate) {
this.dailySpend = 0;
this.lastResetDate = today;
}

return this.dailySpend < this.dailyBudget;
}

recordCost(amount) {
this.dailySpend += amount;
}

async createSessionIfBudgetAllows(config) {
if (!this.checkBudget()) {
throw new Error('Daily budget exceeded');
}

// Proceed with session creation
return this.createSession(config);
}
}

Memory and Performance

// Comprehensive cleanup to prevent memory leaks
const performCleanup = async (page) => {
try {
// Clear large objects from memory
await page.evaluate(() => {
// Clear intervals and timeouts
const highestTimeoutId = setTimeout(() => {}, 0);
for (let i = 0; i < highestTimeoutId; i++) {
clearTimeout(i);
clearInterval(i);
}

// Clear large variables
window.largeDataStructures = null;
window.cachedResults = null;

// Force garbage collection (if available)
if (window.gc) {
window.gc();
}
});

// Clear browser cache
const client = await page.target().createCDPSession();
await client.send('Network.clearBrowserCache');
await client.send('Network.clearBrowserCookies');

} catch (error) {
console.warn('Cleanup error (non-critical):', error.message);
}
};

Security Best Practices

Implement security measures to protect sensitive data and prevent unauthorized access.

Data Protection

// Secure handling of sensitive session data
const secureSessionCleanup = async (page) => {
await page.evaluate(() => {
// Clear sensitive data from localStorage
const sensitiveKeys = [
'authToken', 'accessToken', 'refreshToken',
'password', 'creditCard', 'ssn',
'userCredentials', 'paymentInfo', 'personalData'
];

sensitiveKeys.forEach(key => {
localStorage.removeItem(key);
sessionStorage.removeItem(key);
});

// Clear form data
document.querySelectorAll('input[type="password"], input[type="email"]').forEach(input => {
input.value = '';
});

// Clear any global variables that might contain sensitive data
if (window.userData) window.userData = null;
if (window.sessionData) window.sessionData = null;
});

// Clear cookies containing sensitive data
const cookies = await page.cookies();
const sensitiveCookies = cookies.filter(cookie =>
/auth|token|session|login/i.test(cookie.name)
);

if (sensitiveCookies.length > 0) {
await page.deleteCookie(...sensitiveCookies);
}
};

Monitoring and Alerting

Set up monitoring to track session health and performance.

Health Checks

// Monitor session health
const performHealthCheck = async (sessionId) => {
try {
const response = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`
);

if (response.ok) {
const sessionInfo = await response.json();
return {
healthy: true,
sessionInfo,
uptime: Date.now() - new Date(sessionInfo.created).getTime()
};
} else {
return {
healthy: false,
status: response.status,
message: response.statusText
};
}
} catch (error) {
return {
healthy: false,
error: error.message
};
}
};

// Automated health monitoring
const startHealthMonitoring = (sessionIds, intervalMs = 30000) => {
const healthChecks = sessionIds.map(sessionId => {
return setInterval(async () => {
const health = await performHealthCheck(sessionId);

if (!health.healthy) {
console.warn(`Session ${sessionId} unhealthy:`, health);
// Trigger alerts or remediation
}
}, intervalMs);
});

return () => healthChecks.forEach(clearInterval);
};

Optimization Guidelines

When to Use Browser Sessions vs Session API

ScenarioRecommendationReason
Simple scraping workflowsBrowser SessionsAutomatic cleanup, simpler setup
Short-duration tasks (< 5 min)Browser SessionsReconnection timeout handles lifecycle efficiently
Multi-step workflowsSession APIBetter control over session state
Production applicationsSession APIExplicit lifecycle management
Batch processingSession APIProgrammatic session control
Development/testingBrowser SessionsFaster iteration, less complexity

Timeout Optimization

  • Conservative approach: Start with shorter timeouts and increase as needed
  • Monitor actual usage: Track how long sessions are actually needed
  • Plan-based limits: Respect your plan's maximum timeout limits
  • Workflow-based: Different timeouts for different workflow types

Resource Management

  • Delete sessions immediately after workflow completion to free resources
  • Set appropriate timeouts based on actual workflow duration
  • Monitor session usage to optimize costs and performance
  • Implement cleanup routines for application shutdown

Security Guidelines

  • Clear sensitive data before ending sessions
  • Rotate session identifiers regularly for long-running applications
  • Log session deletions for audit trails
  • Handle deletion failures gracefully to prevent resource leaks

Next Steps