How to Launch and Manage a Browser with Puppeteer’s Browsers API
Learn when to use @puppeteer/browsers versus puppeteer.launch(), then install, launch, connect to, isolate, and clean up browser processes.
Short answer: use @puppeteer/browsers to install, locate, list, launch, or remove browser binaries; use Puppeteer’s puppeteer.launch() when you want an automation session and a Browser object to control pages. They are related but distinct APIs. A reliable workflow is: manage the binary, launch it, do work in pages or isolated contexts, then close it—or disconnect if another process owns the browser.
This guide follows the Puppeteer documentation available for version 25.12.0 in the cited reference pages. Check the documentation matching your installed package before relying on defaults or options; the browser management guide and some individual pages may carry different version labels.
1. Choose the API for the job
| Need | Use |
|---|---|
| Install a specific browser build or resolve a channel/build | @puppeteer/browsers |
| Find the path of a managed browser, list installations, or uninstall one | @puppeteer/browsers |
| Start an automation session and create pages | puppeteer.launch(), which returns a Puppeteer Browser |
| Control a browser started by another process | puppeteer.connect() using its WebSocket endpoint |
The @puppeteer/browsers reference describes a CLI and programmatic API for managing browser binaries and drivers. The Puppeteer launch API starts a browser for automation. The package also has a launch function, but its launch options and process-management responsibilities are distinct from Puppeteer’s generic LaunchOptions.
2. Install and locate a managed browser
For one-off CLI use, inspect the commands supported by the version you plan to use:
npx @puppeteer/browsers --help
npx @puppeteer/browsers install --help
npx @puppeteer/browsers list
The CLI provides install, list, and clear commands. Use each command’s built-in help for the exact browser, build, and channel syntax supported by that package version. In application code, the package exposes functions including install, canInstall, launch, and executable-path helpers. Its official reference documents the current signatures and examples.
When you need a known executable path, resolve it from the installation metadata or the package helper rather than hard-coding a machine-specific cache location. A managed binary is useful when deployments need predictable browser selection; a system browser can be useful when the environment owns browser installation. The reference notes that launching system browsers through this package is only supported for Chrome/Chromium.
3. Launch a browser and automate a page
For a standard Puppeteer install, the package’s downloaded Chrome for Testing is the compatibility-safe default. This runnable ESM example opens a page, captures a screenshot, and closes the process even if navigation or capture fails:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: true,
timeout: 30_000,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto('https://example.com', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
await page.screenshot({ path: 'example.png', fullPage: true });
} finally {
await browser.close();
}
Install the full puppeteer package when you want its browser download and default configuration. With puppeteer-core, supply executablePath or channel; it does not choose/download a browser for you. Puppeteer works best with its downloaded Chrome for Testing version and does not guarantee compatibility with arbitrary Chrome versions. See PuppeteerNode.launch() and the LaunchOptions reference.
Use a system Chrome with puppeteer-core
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.launch({
channel: '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();
}
Alternatively, pass an absolute executablePath. Set the browser option as appropriate when selecting an executable. The host must have that browser installed and runnable, and version mismatch can cause protocol or feature failures.
4. Configure launch behavior
Options are version-dependent. The following are the main Puppeteer launch settings documented in the generic launch reference:
| Option | Purpose and cautions |
|---|---|
browser, channel, executablePath |
Select browser family, an installed channel, or an executable. With puppeteer-core, provide channel or executablePath. |
headless |
Choose headless execution. Use headful mode when diagnosing rendering or interaction differences. |
devtools |
Open DevTools and force headful mode. |
args |
Add browser command-line arguments. Validate arguments against the selected browser. |
ignoreDefaultArgs |
Suppress some or all Puppeteer defaults. Use carefully because defaults configure browser automation. |
userDataDir |
Use a profile directory. Do not concurrently share a writable profile between browser processes. |
env |
Set environment variables visible to the browser process. |
pipe |
Use pipe transport where supported instead of the usual WebSocket connection. |
timeout |
Set the startup timeout; increase it when constrained hosts need more time, while still handling failures. |
handleSIGHUP, handleSIGINT, handleSIGTERM |
Control Puppeteer’s signal handling and browser cleanup behavior. |
dumpio |
Forward browser stdout and stderr to Node’s output for diagnosis. |
Do not copy the @puppeteer/browsers package’s process options into puppeteer.launch() blindly. The package-level launcher has its own options, including process lifecycle settings such as detached, onExit, signal handling, dumpio, env, and pipe. Refer to its launch options page for exact types and semantics.
5. Isolate sessions with BrowserContext
Each browser has a default context. Create a separate context per independent user, job, or test when cookies and local storage must not leak between tasks. Pages inside one context share that context’s session state. Closing a context closes its pages; Puppeteer’s default context cannot be closed.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const context = await browser.createBrowserContext();
try {
const page = await context.newPage();
await page.goto('https://example.com');
// Work in this isolated session.
} finally {
await context.close();
}
} finally {
await browser.close();
}
Use browser.defaultBrowserContext() when you intentionally need the default session, for example to configure context permissions. Separate contexts isolate browser storage; they do not by themselves isolate operating-system resources or make untrusted pages safe.
6. Connect, disconnect, or close
When an external supervisor or service owns the browser process, connect using its WebSocket endpoint. Save the endpoint from the process that launches the browser; it is not a stable URL to guess.
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT,
});
try {
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.title());
} finally {
// Detach this client. The process owner must eventually shut down the browser.
browser.disconnect();
}
Keep browser.wsEndpoint() when you need to reconnect to a browser launched through Puppeteer. Choose cleanup based on process ownership:
await browser.close()shuts down the browser and closes associated pages.browser.disconnect()detaches Puppeteer but leaves the process and pages running. The process owner is responsible for later cleanup.
The Puppeteer browser management guide states: “Unlike browser.close(), browser.disconnect() does not shut down the browser or close any pages.” See Browser management and Browser.disconnect().
7. Reliability, performance, and cost
- Reuse deliberately: launching a browser for every small operation adds process startup and memory overhead. For repeated work, reuse a browser and create/close contexts per isolated job, with limits appropriate to available memory.
- Bound waits: navigation can hang on long-lived requests. Set navigation and launch timeouts and choose a readiness condition that matches the page;
networkidlecan be a poor fit for sites with persistent connections or continuous polling. - Always clean up: use
try/finallyfor browsers and contexts. A detached browser can outlive the script and consume resources if no process owner reaps it. - Pin dependencies and browser selection: deploying the same Puppeteer package and managed browser build reduces environment drift. System Chrome upgrades may introduce compatibility changes.
- Plan host resources: each browser process and active page uses CPU and memory. Concurrency should be bounded and measured in your own deployment; this guide does not claim a universal throughput number.
- Account for download and runtime requirements: managed browser downloads consume cache/storage and require platform utilities. The official browsers reference lists archive tools such as
unzipon Linux/macOS for Chrome andtar.exeon Windows; consult it for current platform-specific requirements.
8. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
puppeteer-core fails because no executable was provided |
Core does not select/download a browser automatically. | Set channel or an absolute executablePath, and verify that browser exists on the host. |
| Browser executable cannot be found after install | Install and runtime use different cache directories, user accounts, or package versions. | Resolve the path through the package helper; align cache configuration and deployment identity. |
| Install fails while extracting an archive | Required OS unpacking utility is absent or the download was interrupted. | Install the utility listed for your platform in the official reference, then retry and inspect install logs. |
| Browser starts locally but exits in deployment | Host libraries, permissions, sandbox constraints, environment, or arguments differ. | Enable dumpio, inspect stderr, confirm platform prerequisites and executable permissions, and remove unnecessary custom arguments. |
| Protocol or browser target errors | The selected browser version may not match the Puppeteer version’s expectations. | Prefer Puppeteer’s managed Chrome for Testing or align the system browser and Puppeteer versions. |
| Script exits but Chromium remains running | The code disconnected or failed before closing, or a package launcher was configured to detach. | Use close() when your process owns the browser; if detached, ensure the designated owner tracks and stops it. |
| WebSocket connection fails | Endpoint is stale, unreachable, or not the browser’s actual WebSocket endpoint. | Obtain the endpoint from the launching process, check network reachability, and reconnect while the browser is still alive. |
| Install works only on some hosts or behind a proxy | Platform prerequisites or proxy configuration differ. | Check the package guide’s current prerequisites and proxy instructions. It documents proxy environment variables when proxy-agent is installed. |
For package-level diagnostics, the browsers guide documents NODE_DEBUG channels for cache, file utilities, installation, and launcher operations. Enable only the channel relevant to the failure and review output for paths and subprocess errors.
9. Or skip the browser setup
If your goal is a website screenshot rather than browser automation, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF, without provisioning a browser in your app:
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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before capture; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
10. FAQ
Can I use @puppeteer/browsers without Puppeteer?
Yes. It is a browser management package with a CLI and programmatic functions. Add Puppeteer when you need its page automation API.
Can I close the default browser context?
No. Create and close additional contexts for isolated sessions; the default context remains attached to the browser.
Does disconnect kill Chrome?
No. Disconnect detaches the client. The process owner must close the browser when it is no longer needed.
Should I use WebSocket or pipe?
Use the default connection style unless your deployment specifically needs pipe transport and the chosen launcher supports it. Both ends of a connection must agree on the transport.
Where should I check option defaults?
Use the official Puppeteer and browsers references for the exact versions in your lockfile; options and defaults can change between releases.


