Robust browser session management for Playwright & Browser.cash.
Powered by Browser.cash remote browsers.
Features β’ Installation β’ Usage β’ Configuration β’ Contributing
π‘ Pro Tip: See this library in action in Teracrawl and Browser SERP.
Browser Pool is a specialized library designed to manage pools of remote browser sessions. It handles the lifecycle of Playwright browsers connected to Browser.cash, ensuring your application always has a healthy browser ready to perform tasks.
It abstracts away the complexity of connection management, error recovery, and session recycling, making it ideal for building high-concurrency scrapers and automation tools.
- Automatic Pooling: Maintains a fixed number of active browser sessions.
- Target-Aware Pooling: Specify exactly how many browsers you want per node, country, or node type.
- Self-Healing: Automatically detects and replaces dead or disconnected browsers.
- Health Checks: Periodically verifies browser responsiveness.
- Concurrency Control: Queues requests when all sessions are busy.
- Type-Safe: Written in TypeScript with full type definitions.
npm install @browsercash/poolNote: You must also have playwright-core installed as a peer dependency.
import { chromium } from "playwright-core";
import { SessionPool, type PoolConfig } from "@browsercash/pool";
const cfg: PoolConfig = {
apiKey: process.env.BROWSER_API_KEY,
chromium,
targets: [
{ id: "us-hosted", count: 2, country: "US", type: "hosted" },
{ id: "de-consumer", count: 1, country: "DE", type: "consumer_distributed" },
{ id: "pinned-node", count: 1, nodeId: "node_123" },
],
enableHealthCheck: true,
waitQueueTimeoutMs: 30_000,
};
// 1. Create the pool
const pool = new SessionPool(cfg);
// 2. Initialize
await pool.init();
// 3. Acquire a session (waits if none available)
const session = await pool.acquire();
try {
// Use the standard Playwright browser instance
const page = await session.browser.newPage();
await page.goto("https://example.com");
console.log(await page.title());
} finally {
// 4. Always release the session back to the pool
// Pass 'true' as second arg if the session encountered a fatal error
pool.release(session);
}
// 5. Cleanup on shutdown
await pool.shutdown();There is also a dedicated example config file in
examples/browser-pool.config.mjs.
If you just want the old behavior, size still works:
const pool = new SessionPool({
apiKey: process.env.BROWSER_API_KEY,
chromium,
size: 3,
});import { chromium } from "playwright-core";
import { type PoolConfig } from "@browsercash/pool";
export const browserPoolCfg: PoolConfig = {
apiKey: process.env.BROWSER_API_KEY!,
chromium,
targets: [
{ id: "us-primary", count: 2, country: "US", type: "hosted" },
{ id: "eu-fallback", count: 2, country: "DE", type: "consumer_distributed" },
{ id: "pinned-fraud-node", count: 1, nodeId: "node_123" },
],
maxUses: 25,
maxAgeMs: 10 * 60 * 1000,
maxIdleMs: null,
enableHealthCheck: true,
healthCheckIntervalMs: 30_000,
sessionReadyTimeoutMs: 30_000,
cdpConnectTimeoutMs: 15_000,
waitQueueTimeoutMs: 60_000,
};Equivalent standalone file:
// examples/browser-pool.config.mjs
import { chromium } from "playwright-core";
export const browserPoolCfg = {
apiKey: process.env.BROWSER_API_KEY,
chromium,
targets: [
{ id: "de-consumer", count: 1, country: "DE", type: "consumer_distributed" },
],
maxUses: 25,
maxAgeMs: 10 * 60 * 1000,
maxIdleMs: null,
enableHealthCheck: true,
healthCheckIntervalMs: 30_000,
sessionReadyTimeoutMs: 30_000,
cdpConnectTimeoutMs: 15_000,
waitQueueTimeoutMs: 60_000,
};For a larger production mix, expand targets with more entries such as hosted US nodes or pinned nodeId targets.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
Required | Your Browser.cash API key. |
chromium |
ChromiumModule |
Required | The Playwright Chromium module. |
size |
number |
1 |
Backward-compatible shortcut for a single default target group. |
targets |
PoolTarget[] |
[] |
Explicit target mix. Sum of count values becomes the pool size. |
maxUses |
number |
50 |
Max times a browser is reused before recycling. |
maxAgeMs |
number |
300000 |
Max age (ms) of a session before recycling. |
maxIdleMs |
number | null |
null |
Max idle time before recycling. null or 0 disables idle recycling. |
enableHealthCheck |
boolean |
false |
Enable background remote health checks. |
healthCheckIntervalMs |
number |
30000 |
Interval for health checks (ms). |
healthCheckTimeoutMs |
number |
min(interval, 10000) |
Timeout for each health-check request. |
sessionReadyTimeoutMs |
number |
20000 |
How long to wait for Browser.cash to return a usable CDP URL. |
cdpConnectTimeoutMs |
number |
15000 |
Timeout for Playwright connectOverCDP. |
enableWaitQueue |
boolean |
true |
Queue acquire requests if pool is full. |
waitQueueTimeoutMs |
number |
60000 |
Max time an acquire call will wait in queue. |
enableDisconnectHandling |
boolean |
true |
Replace sessions when the CDP connection disconnects. |
createPage |
boolean |
false |
Pre-create a page for each pooled session. |
debug |
boolean |
false |
Enable verbose logging. |
logger |
(message, data) => void |
console.log |
Custom logger used when debug is enabled. |
type PoolTarget = {
id?: string;
count: number;
nodeId?: string;
country?: string;
type?: "consumer_distributed" | "hosted";
sessionOptions?: Record<string, unknown>;
};- Use
countto pin how many sessions should exist for that target. - Use
nodeIdwhen you want a specific Browser.cash node. - Use
countryandtypewhen you want the pool to maintain a regional mix. - Use
sessionOptionsas a pass-through for newer Browser.cash session-create fields.
Contributions are welcome! We appreciate your help in making Browser Pool better.
- Fork the Project: click the 'Fork' button at the top right of this page.
- Create your Feature Branch:
git checkout -b feature/AmazingFeature - Commit your Changes:
git commit -m 'Add some AmazingFeature' - Push to the Branch:
git push origin feature/AmazingFeature - Open a Pull Request: Submit your changes for review.
This project is licensed under the MIT License - see the LICENSE file for details.