ScreenshotNeo

BlogGuides

Puppeteer Browser Management Options Explained

Choose who installs and owns the browser Puppeteer uses, then manage browser lifetime and task isolation deliberately.

By the ScreenshotNeo team4 October 20268 min read

Puppeteer browser management comes down to who installs and starts the browser. Use puppeteer when you want Puppeteer to download a compatible browser as part of installation. Use puppeteer-core when your environment manages the browser or when you connect to a browser that is already running. Separately, choose how long the browser process should live and whether tasks need isolated browser contexts.

For most new projects, start with puppeteer and its downloaded browser. Choose puppeteer-core when you need control over the browser executable, deployment image, or remote browser lifecycle. For task isolation, use a BrowserContext; it separates cookies and local storage within one browser process.

1. Choose who manages the browser

Setup Who obtains and starts the browser? Use it when Main consideration
puppeteer with its downloaded browser Puppeteer’s installation workflow obtains a compatible Chrome for Testing build. You want the documented default setup with a browser version aligned to Puppeteer. Package-manager policies can block install scripts and prevent the browser download.
puppeteer-core with a local browser Your workstation, container image, or deployment process installs the browser. Your environment already owns browser installation and updates. Set executablePath or a supported channel, and check compatibility.
puppeteer-core connected to a running browser An external launcher or service starts and supervises the browser. You receive a WebSocket endpoint from another process or environment. Use disconnect() when your client should detach without ending the browser.

These choices control browser ownership. They do not by themselves determine task isolation or process lifetime. A BrowserContext is an isolated context inside a browser process, not a separate browser process.

2. Default setup: let Puppeteer download a compatible browser

Install the full package when you want Puppeteer to obtain its browser as part of installation:

npm install puppeteer

Then launch and close a browser with a minimal script:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());
} finally {
  await browser.close();
}

The downloaded browser is the convenient choice when its version and installation location suit your application. If installation completed but launch reports that no browser is available, first check whether your package manager skipped Puppeteer’s install script. Installation guidance documents running npx puppeteer browsers install to install the browser manually. See the official Puppeteer installation guide.

3. Self-manage a local browser with puppeteer-core

puppeteer-core does not download Chrome. Install it when your system, container image, or browser management workflow supplies the executable. Provide its path explicitly, or use a supported Chrome channel installed in a standard location.

npm install puppeteer-core

Example using an explicit executable path:

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: '/usr/bin/google-chrome',
  headless: true,
});
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());
} finally {
  await browser.close();
}

Replace the path with the browser executable installed in your environment. Paths differ across operating systems, package sources, and container images. You can instead configure a supported channel, for example channel: 'chrome', when the corresponding Chrome installation is present in a standard location:

const browser = await puppeteer.launch({ channel: 'chrome', headless: true });

Use executablePath when you need to select a specific local build or its location is nonstandard. Use channel when you want Puppeteer to locate an installed, supported browser channel. Consult the configuration guide and the supported browsers table; browser compatibility is version-sensitive, so check the mapping for the Puppeteer version your application uses.

4. Connect to a browser that is already running

When another process starts Chrome and provides its DevTools WebSocket endpoint, use puppeteer-core and connect(). Set the endpoint from your runtime configuration rather than hard-coding a live credential into source code.

import puppeteer from 'puppeteer-core';

const browserWSEndpoint = process.env.BROWSER_WS_ENDPOINT;
if (!browserWSEndpoint) throw new Error('Set BROWSER_WS_ENDPOINT');

const browser = await puppeteer.connect({ browserWSEndpoint });
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());
} finally {
  // Detach this Puppeteer client; leave the externally managed browser running.
  await browser.disconnect();
}

The external launcher or service owns startup, executable selection, and process shutdown. Protect the endpoint as an access credential: anyone who can use it may be able to control the browser. The official browser management guide documents connection and disconnection behavior.

5. Manage browser binaries with @puppeteer/browsers

For workflows that need explicit browser installation and launching, the @puppeteer/browsers tooling provides CLI and programmatic browser management. Its CLI documents install, list, launch, and clear workflows. This can make browser setup an explicit deployment step instead of relying on the full puppeteer package’s install workflow.

npx @puppeteer/browsers --help

Use the CLI help and the @puppeteer/browsers API reference for current command syntax and options. Pin the browser build through your deployment process where repeatable environments matter, and ensure the Puppeteer version supports that browser build.

6. Choose process lifetime and task isolation

Close versus disconnect

Call Effect Use it when
browser.close() Shuts down the browser Puppeteer launched. Your script owns the browser process and has finished using it.
browser.disconnect() Detaches Puppeteer from a connected browser without shutting down that browser or closing its pages. The browser is externally managed and should continue running.

Do not call close() on a browser process that a separate supervisor expects to keep alive. Conversely, make sure a process you launched is eventually closed; otherwise it can remain running after the task ends.

Isolate tasks with BrowserContexts

BrowserContexts isolate cookies and local storage between automation tasks. Closing a context closes its pages. They are useful when tasks should share the browser process but not their browser storage.

const context = await browser.createBrowserContext();
try {
  const page = await context.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());
} finally {
  await context.close();
}

Create and close a context for each isolated task as appropriate. Contexts are not a substitute for process-level separation when tasks require separate browser processes or independent process supervision. See the official BrowserContexts documentation.

7. A practical decision checklist

  1. Start with puppeteer if its downloaded compatible browser and installation workflow fit your workstation or deployment.
  2. Use puppeteer-core with executablePath or channel if your environment installs and updates the local browser.
  3. Use puppeteer-core with connect() if a separate process or service already runs the browser and provides a WebSocket endpoint.
  4. Choose the owner of shutdown: close a browser process your script launched; disconnect from a browser another system owns.
  5. Choose isolation separately: use BrowserContexts for separate cookies and local storage within one browser process.
  6. Check compatibility: consult the supported browser mapping for the Puppeteer version deployed, especially when selecting your own browser build.

8. Troubleshooting

Symptom Likely cause Fix
Launch says the browser executable cannot be found. The browser download was skipped or puppeteer-core has no executable configured. For puppeteer, check whether package install scripts were blocked and run npx puppeteer browsers install. For puppeteer-core, set a valid executablePath or a supported installed channel.
The chosen browser launches but Puppeteer behaves incompatibly. The browser build may not match the Puppeteer version’s supported mapping. Check the supported browsers table for the version in use; select a compatible browser or update the Puppeteer and browser pairing deliberately.
A shared browser unexpectedly exits after a task. The client used browser.close() on an externally managed process. Use browser.disconnect() to detach without shutting down the connected browser.
Cookies or local storage leak between tasks. Tasks reused the same context. Give isolated tasks separate BrowserContexts and close each context when its task completes.
Browser processes remain after a script finishes. A launched browser was not closed, often because cleanup did not run after an error. Place task work in try and browser cleanup in finally; close owned processes and disconnect from externally owned ones.
Connection to an existing browser fails. The endpoint may be missing, invalid, unreachable, or no longer served by the browser process. Confirm the launcher supplied the current WebSocket endpoint and that the Puppeteer process can reach it. Let the external owner handle browser startup and availability.

9. Performance, reliability, and cost

The official Puppeteer documentation does not provide a head-to-head performance, reliability, or cost benchmark for these management patterns. Choose based on ownership and operational fit rather than assuming one is faster or cheaper.

  • Installation and deployment: the full package obtains a compatible browser through its installation workflow; self-managed setups make browser installation an explicit responsibility. Package managers that block scripts can interrupt the former workflow.
  • Reproducibility: align Puppeteer and browser versions and verify the supported mapping. A self-managed executable gives deployment control, while also making that compatibility check your responsibility.
  • Lifecycle reliability: make cleanup explicit. Close browser processes your code launched, and disconnect from externally owned processes so a task does not accidentally stop shared infrastructure.
  • Task isolation: BrowserContexts separate cookies and local storage within a process. They do not create separate browser processes.
  • Cost: the cited Puppeteer documentation establishes no comparative price for these patterns. Account for your own compute, browser hosting, and operational requirements rather than attributing an undocumented price difference to the package choice.

Or skip the browser setup

If your task is to capture a website screenshot rather than operate a browser directly, ScreenshotNeo provides a website screenshot API and MCP server. It makes one GET request and returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie banners, popups, and chat widgets are removed before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and responses report the page verdict and billing status. Its MCP server lets Claude, Cursor, and other MCP clients use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for 1,000 free screenshots a month with no card.

FAQ

Does puppeteer-core install Chrome?

No. It is intended for setups where you manage the browser or connect to one that is already running.

Does disconnecting close browser tabs?

No. Disconnect detaches Puppeteer and leaves the connected browser and its pages running.

Are BrowserContexts separate Chrome processes?

No. They isolate browser storage within one browser process.

Where should I check which browser version to use?

Use Puppeteer’s supported browsers mapping for the specific Puppeteer version you deploy.