Closing Sessions
Properly closing sessions is essential for resource management and cost optimization. This guide covers both automatic cleanup for browser sessions and explicit deletion for Session API.
Browser Session Cleanup
Browser sessions using Browserless.reconnect
are automatically managed by Browserless. Sessions expire when their timeout period elapses.
Automatic Cleanup
Browser sessions are automatically cleaned up when:
- Reconnection timeout reached - Sessions using
Browserless.reconnect
expire after the configured timeout - Browser instance terminates - Sessions end when the browser process closes
Manual Cleanup (Optional)
While Browserless.reconnect
handles automatic cleanup, you can manually clear data before session expiration:
- Logout Pattern
- Conditional Cleanup
- Immediate Cleanup
import puppeteer from 'puppeteer-core';
const cleanupSession = async (reconnectEndpoint) => {
const browser = await puppeteer.connect({
browserWSEndpoint: reconnectEndpoint || 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN',
});
const page = await browser.newPage();
try {
// Perform logout to clear server-side sessions
await page.goto('https://app.example.com/logout');
await page.waitForNavigation();
// Clear local storage and cookies
await page.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
});
// Clear all cookies
const cookies = await page.cookies();
await page.deleteCookie(...cookies);
console.log('Session cleaned up successfully');
} catch (error) {
console.error('Cleanup error:', error);
} finally {
await browser.close(); // Automatic cleanup when browser closes
}
};
// Use in your workflow
await cleanupSession();
// Clean up based on workflow completion
const conditionalCleanup = async (shouldPreserve = false) => {
if (shouldPreserve) {
console.log('Preserving session - reconnection timeout will handle cleanup');
return;
}
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN',
});
const page = await browser.newPage();
// Clear sensitive data but preserve general state
await page.evaluate(() => {
// Remove sensitive keys
const sensitiveKeys = ['authToken', 'userCredentials', 'paymentInfo'];
sensitiveKeys.forEach(key => localStorage.removeItem(key));
});
await browser.close();
console.log('Session partially cleaned - browser process terminated');
};
// Immediately terminate session by closing without reconnection setup
const immediateCleanup = async () => {
// Connect without reconnection setup - session will terminate immediately on close
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN',
});
const page = await browser.newPage();
// Clear all data
await page.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
});
// Clear cookies
const cookies = await page.cookies();
await page.deleteCookie(...cookies);
await browser.close(); // Session terminates immediately
console.log('Session immediately terminated');
};
// Usage
await immediateCleanup();
Session API Stopping
This section covers stopping sessions created with the Sessions API (REST API for explicit session management). For Browser Sessions using Browserless.reconnect
CDP command, sessions automatically clean up when their timeout expires.
Session API requires explicit stopping to terminate the session and free resources immediately. Sessions will also auto-expire when their TTL is reached.
Manual Session Stopping
- JavaScript
- Python
- cURL
const stopSession = async (sessionId) => {
try {
const response = await fetch(
`https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
stop: sessionId
})
}
);
if (response.ok) {
const result = await response.json();
console.log(`Session ${sessionId} stopped:`, result);
return true;
} else {
console.error(`Failed to stop session ${sessionId}:`, response.status);
return false;
}
} catch (error) {
console.error(`Error stopping session ${sessionId}:`, error);
return false;
}
};
// Usage
await stopSession('session-abc123');
import requests
def stop_session(session_id, api_token):
try:
response = requests.post(
'https://production-sfo.browserless.io/session',
params={'token': api_token},
json={'stop': session_id}
)
if response.ok:
result = response.json()
print(f'Session {session_id} stopped: {result}')
return True
else:
print(f'Failed to stop session {session_id}: {response.status_code}')
return False
except Exception as error:
print(f'Error stopping session {session_id}: {error}')
return False
# Usage
stop_session('session-abc123', 'YOUR_API_TOKEN')
# Stop a specific session
curl -X POST "https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"stop": "session-abc123"}'
# Response: { "stopped": true }
Automatic TTL Expiration
Session API automatically expires when TTL (Time To Live) is reached:
// Session created with 5-minute TTL
const createSessionWithTTL = async () => {
const response = 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 in milliseconds
stealth: true
}),
});
const { sessionId } = await response.json();
console.log(`Session ${sessionId} will auto-expire in 5 minutes`);
return sessionId;
};
// Monitor session status
const monitorSession = async (sessionId) => {
const checkStatus = async () => {
try {
const response = await fetch(
`https://production-sfo.browserless.io/session/${sessionId}?token=YOUR_API_TOKEN`
);
if (response.ok) {
const sessionInfo = await response.json();
console.log('Session active:', sessionInfo);
return true;
} else {
console.log('Session expired or not found');
return false;
}
} catch (error) {
console.log('Session no longer accessible:', error.message);
return false;
}
};
// Check every minute
const interval = setInterval(async () => {
const isActive = await checkStatus();
if (!isActive) {
clearInterval(interval);
}
}, 60000);
};
Advanced Session Stopping Patterns
- Graceful Shutdown
- Stop with Retry
- Bulk Stopping
// Gracefully close session after completing current operations
const gracefulSessionShutdown = async (sessionId) => {
try {
// First, connect to complete any pending operations
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io/session/connect/${sessionId}?token=YOUR_API_TOKEN`,
});
const page = await browser.newPage();
// Perform any final operations
await page.evaluate(() => {
// Save important data before shutdown
const importantData = localStorage.getItem('workflowProgress');
if (importantData) {
// Could send to your server here
console.log('Saving workflow progress:', importantData);
}
});
// Close browser connection first
await browser.close();
// Then stop the session
const response = await fetch(
`https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ stop: sessionId })
}
);
const result = await response.json();
console.log('Session gracefully shutdown:', result);
} catch (error) {
console.error('Error during graceful shutdown:', error);
// Force stop the session anyway
await fetch(
`https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ stop: sessionId })
}
);
}
};
// Stop session with retry logic
const stopSessionWithRetry = async (sessionId, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(
`https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ stop: sessionId })
}
);
if (response.ok) {
const result = await response.json();
console.log(`Session ${sessionId} stopped on attempt ${attempt}`);
return result;
} else if (response.status === 404) {
console.log(`Session ${sessionId} already stopped or expired`);
return { stopped: true, note: 'Already stopped' };
} else {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
} catch (error) {
console.log(`Stop attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
console.error(`Failed to stop session ${sessionId} after ${maxRetries} attempts`);
throw error;
}
// Wait before retry (exponential backoff)
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt - 1)));
}
}
};
// Stop multiple sessions efficiently
const bulkStopSessions = async (sessionIds) => {
const stopPromises = sessionIds.map(async (sessionId) => {
try {
const response = await fetch(
`https://production-sfo.browserless.io/session?token=YOUR_API_TOKEN`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ stop: sessionId })
}
);
if (response.ok) {
const result = await response.json();
return { sessionId, status: 'stopped', result };
} else if (response.status === 404) {
return { sessionId, status: 'not_found' };
} else {
return { sessionId, status: 'error', error: response.statusText };
}
} catch (error) {
return { sessionId, status: 'error', error: error.message };
}
});
const results = await Promise.allSettled(stopPromises);
// Process results
const successful = results.filter(r => r.status === 'fulfilled' && r.value.status === 'stopped');
const failed = results.filter(r => r.status === 'rejected' || r.value.status === 'error');
console.log(`Bulk stop complete: ${successful.length} stopped, ${failed.length} failed`);
return { successful, failed };
};
// Usage
const sessionIds = ['session-1', 'session-2', 'session-3'];
await bulkStopSessions(sessionIds);
Next Steps
- Creating Sessions - Learn how to create new sessions
- Managing Sessions - Understand session connection and state management
- Best Practices - Comprehensive guide to session management optimization and security