INTEGRITY Cloudflare Docs

Reuse sessions

By default, each Browser Sessions request launches a new browser instance. Reusing sessions eliminates cold-start time and improves performance by reconnecting to an existing browser instead of launching a new one.

This feature applies to Browser Sessions (Puppeteer, Playwright, and CDP). Quick Actions handle session lifecycle automatically.

There are two approaches to reusing sessions:

1. Create a Worker project

Cloudflare Workers provides a serverless execution environment that allows you to create new applications or augment existing ones without configuring or maintaining infrastructure. Your Worker application is a container to interact with a headless browser to do actions, such as taking screenshots.

Create a new Worker project named browser-worker by running:

npm create cloudflare@latest -- browser-worker

For setup, select the following options:

2. Install Puppeteer

In your browser-worker directory, install Cloudflare's fork of Puppeteer:

npm i -D @cloudflare/puppeteer

3. Configure the Wrangler configuration file

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "browser-worker",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"compatibility_flags": ["nodejs_compat"],
	"browser": {
		"binding": "MYBROWSER",
	},
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "browser-worker"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"
compatibility_flags = [ "nodejs_compat" ]

[browser]
binding = "MYBROWSER"

4. Code

The script below starts by fetching the current running sessions. If there are any that do not already have a worker connection, it picks a random session ID and attempts to connect (puppeteer.connect(..)) to it. If that fails or there were no running sessions to start with, it launches a new browser session (puppeteer.launch(..)). Then, it goes to the website and fetches the dom. Once that is done, it disconnects (browser.disconnect()), making the connection available to other workers.

Take into account that if the browser is idle, i.e. does not get any command, for more than the current limit, it will close automatically, so you must have enough requests per minute to keep it alive.

import puppeteer from "@cloudflare/puppeteer";

export default {
	async fetch(request, env) {
		const url = new URL(request.url);
		let reqUrl = url.searchParams.get("url") || "https://example.com";
		reqUrl = new URL(reqUrl).toString(); // normalize

		// Pick random session from open sessions
		let sessionId = await this.getRandomSession(env.MYBROWSER);
		let browser, launched;
		if (sessionId) {
			try {
				browser = await puppeteer.connect(env.MYBROWSER, sessionId);
			} catch (e) {
				// another worker may have connected first
				console.log(`Failed to connect to ${sessionId}. Error ${e}`);
			}
		}
		if (!browser) {
			// No open sessions, launch new session
			browser = await puppeteer.launch(env.MYBROWSER);
			launched = true;
		}

		sessionId = browser.sessionId(); // get current session id

		// Do your work here
		const page = await browser.newPage();
		const response = await page.goto(reqUrl);
		const html = await response.text();

		// All work done, so free connection (IMPORTANT!)
		browser.disconnect();

		return new Response(
			`${launched ? "Launched" : "Connected to"} ${sessionId} \n-----\n` + html,
			{
				headers: {
					"content-type": "text/plain",
				},
			},
		);
	},

	// Pick random free session
	// Other custom logic could be used instead
	async getRandomSession(endpoint) {
		const sessions = await puppeteer.sessions(endpoint);
		console.log(`Sessions: ${JSON.stringify(sessions)}`);
		const sessionsIds = sessions
			.filter((v) => {
				return !v.connectionId; // remove sessions with workers connected to them
			})
			.map((v) => {
				return v.sessionId;
			});
		if (sessionsIds.length === 0) {
			return;
		}

		const sessionId =
			sessionsIds[Math.floor(Math.random() * sessionsIds.length)];

		return sessionId;
	},
};
import puppeteer from "@cloudflare/puppeteer";

interface Env {
	MYBROWSER: Fetcher;
}

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const url = new URL(request.url);
		let reqUrl = url.searchParams.get("url") || "https://example.com";
		reqUrl = new URL(reqUrl).toString(); // normalize

		// Pick random session from open sessions
		let sessionId = await this.getRandomSession(env.MYBROWSER);
		let browser, launched;
		if (sessionId) {
			try {
				browser = await puppeteer.connect(env.MYBROWSER, sessionId);
			} catch (e) {
				// another worker may have connected first
				console.log(`Failed to connect to ${sessionId}. Error ${e}`);
			}
		}
		if (!browser) {
			// No open sessions, launch new session
			browser = await puppeteer.launch(env.MYBROWSER);
			launched = true;
		}

		sessionId = browser.sessionId(); // get current session id

		// Do your work here
		const page = await browser.newPage();
		const response = await page.goto(reqUrl);
		const html = await response!.text();

		// All work done, so free connection (IMPORTANT!)
		browser.disconnect();

		return new Response(
			`${launched ? "Launched" : "Connected to"} ${sessionId} \n-----\n` + html,
			{
				headers: {
					"content-type": "text/plain",
				},
			},
		);
	},

	// Pick random free session
	// Other custom logic could be used instead
	async getRandomSession(endpoint: puppeteer.BrowserWorker): Promise<string> {
		const sessions: puppeteer.ActiveSession[] =
			await puppeteer.sessions(endpoint);
		console.log(`Sessions: ${JSON.stringify(sessions)}`);
		const sessionsIds = sessions
			.filter((v) => {
				return !v.connectionId; // remove sessions with workers connected to them
			})
			.map((v) => {
				return v.sessionId;
			});
		if (sessionsIds.length === 0) {
			return;
		}

		const sessionId =
			sessionsIds[Math.floor(Math.random() * sessionsIds.length)];

		return sessionId!;
	},
};

Besides puppeteer.sessions(), we have added other methods to facilitate Session Management.

5. Test

Run npx wrangler dev to test your Worker locally.

To test go to the following URL:

<LOCAL_HOST_URL>/?url=https://example.com

6. Deploy

Run npx wrangler deploy to deploy your Worker to the Cloudflare global network and then to go to the following URL:

<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/?url=https://example.com