How Puppeteer Finds a System Browser Executable
Puppeteer normally uses its downloaded Chrome for Testing. Learn when it finds system Chrome, how to set an exact executable path, and how to fix missing-browser errors.
Puppeteer does not normally search your computer for any browser and pick one automatically. The standard puppeteer package downloads a compatible Chrome for Testing build and uses that managed browser by default. To use an installed release of Chrome, set channel; to use a browser at a specific location, set executablePath. The PUPPETEER_EXECUTABLE_PATH environment variable can override the configured executable path. puppeteer-core does not download a browser or apply Puppeteer configuration defaults, so your application must supply browser management and selection.
This guide covers those choices, installation, deployment, and common failures. For version-specific details, check the Puppeteer documentation for the version installed in your project: LaunchOptions, Installation, and Configuration.
1. Know which browser-selection method you need
| Method | How Puppeteer identifies the browser | Who manages installation | Good fit |
|---|---|---|---|
Default puppeteer |
Uses the computed path to its managed browser | Puppeteer downloads and caches Chrome for Testing | You want Puppeteer’s documented default setup |
channel |
Looks for a regular Chrome installation at known system locations for that release channel | You install and update Chrome | Chrome is conventionally installed and you want a recognized channel |
executablePath |
Uses the path you specify | Your application or deployment | The browser has a known or nonstandard location |
puppeteer-core |
Uses the browser choice your application provides | Your application or remote-browser provider | You deliberately manage the browser or use a remote one |
Puppeteer guarantees compatibility with its bundled browser. A system browser or custom binary may work, but you are responsible for checking compatibility with your installed Puppeteer version. The available channel values are version-dependent; use the API reference for the version in your lockfile.
2. Default: use Puppeteer’s managed Chrome
Install the full puppeteer package and let it manage the browser download. Its computed default executable path points to the managed browser cache; it does not mean Puppeteer scans all installed browsers. The installation guide documents a Chrome for Testing download and, since Puppeteer v21.6.0, a chrome-headless-shell binary as well. The guide gives approximate download sizes of 170 MB on macOS, 282 MB on Linux, and 280 MB on Windows; these are estimates and can change. By default, downloads are cached under $HOME/.cache/puppeteer, a default introduced in v19.0.0. Configuration can change the cache directory.
npm install puppeteer
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();
}
Run this as an ES module, for example in a file named capture.mjs with node capture.mjs. The browser download is usually a separate install-time concern; a successful package install alone does not prove that an install script downloaded the browser.
3. Use an installed Chrome release channel
Choose channel when you want Puppeteer to resolve a standard system installation of a recognized Chrome release channel. This uses Puppeteer’s known-location lookup. It is distinct from passing an arbitrary executable path.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
channel: 'chrome',
});
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.title());
} finally {
await browser.close();
}
Install the desired Chrome release on the machine where this code runs. The exact supported channel names depend on the Puppeteer version; check LaunchOptions. System discovery checks known locations, so a portable, custom-packaged, or otherwise nonstandard browser may not be found this way. The documented system-browser lookup is for Chrome/Chromium, not a general search for every browser.
4. Set an explicit executable path
Use executablePath when you control the browser installation and know its location, such as in a managed container or a custom deployment. Supply the actual executable path on the target host. Paths vary by operating system, package format, installation method, and release channel, so do not copy a path from a different machine without checking it.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
executablePath: '/absolute/path/to/chrome',
});
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 example with the executable path that exists in your runtime environment. Puppeteer also documents browser as a launch option; set it where appropriate if the path is for a browser other than the default Chrome choice. The API reference explains the available values and the compatibility caveat.
Environment variable override
PUPPETEER_EXECUTABLE_PATH overrides the configured executable path. If a launch unexpectedly uses a different binary, inspect this environment variable in the process environment, along with any Puppeteer configuration. Avoid assuming a value set in your interactive shell is also set in a service, container, CI job, or production process.
# Example for a Unix-like shell; replace the path for your host.
PUPPETEER_EXECUTABLE_PATH=/absolute/path/to/chrome node capture.mjs
5. Use puppeteer-core when your application owns the browser
puppeteer-core does not download Chrome and does not use Puppeteer configuration files or environment-variable configuration. Your application must provide a browser executable or connect through the browser setup it manages. For a local executable, pass executablePath explicitly:
npm install puppeteer-core
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.launch({
executablePath: '/absolute/path/to/chrome',
});
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.title());
} finally {
await browser.close();
}
This package is useful when a deployment image, another tool, or a remote-browser provider is responsible for browser lifecycle. Make that ownership explicit: provision the expected browser version, make the executable available to the process, and configure the application to use it. Do not expect the full puppeteer package’s browser download or configuration behavior from puppeteer-core.
6. Install the managed browser after package installation
A frequent cause of “Could not find Chrome” is that the package manager skipped dependency install scripts, including Puppeteer’s browser postinstall step. If you intend to use Puppeteer’s managed browser, install it explicitly with the supported CLI command for your installed version, or configure your package manager to allow the postinstall script. Check the current installation guide for the command and package-manager instructions for that version.
If the deployment intentionally uses system Chrome instead, select a supported channel or set executablePath; installing a managed browser is not necessary for that setup. Keep the chosen method consistent between local development, CI, and production.
7. Troubleshoot browser discovery
| Symptom | Likely cause | What to check or change |
|---|---|---|
Could not find Chrome (ver. ...) |
The managed browser was not downloaded, often because install scripts were blocked | Confirm the package is puppeteer; run the supported browser install command or allow its postinstall script. If using a system browser, configure channel or executablePath. |
puppeteer-core launches without finding a browser |
puppeteer-core does not download one or apply Puppeteer configuration defaults |
Install/manage a browser yourself and provide its executable path or the appropriate connection configuration. |
| A Chrome channel is not found | That release is absent, installed in a nonstandard location, or unsupported by the installed version | Install a recognized channel, check version-specific channel support, or pass the actual path with executablePath. |
| The wrong browser path is used | PUPPETEER_EXECUTABLE_PATH or project configuration overrides the expected setting |
Inspect the environment of the running process and Puppeteer configuration; remove or correct the conflicting value. |
| Launch fails after finding an executable | The binary may be incompatible with Puppeteer or lack runtime dependencies/permissions | Check executable permissions and host dependencies, then compare the browser version with the Puppeteer version. The bundled browser is the compatibility-guaranteed choice. |
| Works locally, fails in CI or production | The runtime has a different filesystem, user, environment, or install-script policy | Verify the browser is present in that runtime, the process can execute it, and the configured path and environment are supplied there. |
- Identify whether the application imports
puppeteerorpuppeteer-core. - Decide whether Puppeteer downloads the browser, a channel resolves installed Chrome, or your deployment provides an exact path.
- Check the actual runtime environment for the executable and any
PUPPETEER_EXECUTABLE_PATHoverride. - Confirm that the selected browser is compatible with the installed Puppeteer version; when in doubt, use the bundled browser.
8. Reliability, performance, and cost considerations
- Version consistency: The bundled browser is Puppeteer’s guaranteed compatibility target. System browsers can update independently, so pin or control their lifecycle when repeatable automation matters.
- Build and deployment size: Browser downloads add time and storage to installation or image builds. Puppeteer’s guide provides approximate platform-specific download sizes; treat them as changeable estimates.
- Cache and permissions: The default browser cache is under the home directory, which may differ for a service account or container. Ensure the install and runtime processes can access the same configured cache, or package the browser at a known path.
- Startup reliability: Install-time downloads can fail or be skipped. Provision the browser during a controlled build step and verify that the runtime can execute the resulting file.
- System channel updates: A regular Chrome installation may change without a code deployment. That can affect reproducibility; the bundled browser keeps the browser version tied more closely to the Puppeteer install.
- Direct monetary cost: The documented setup involves software downloads and machine storage/compute; the dossier does not specify a Puppeteer license price or hosting cost, so calculate costs from your own environment.
9. Or skip the browser setup
If you only need a screenshot of a URL, ScreenshotNeo provides a website screenshot API, so your application does not need to locate and operate a local browser. Its API returns a screenshot or PDF from one GET request. 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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Replace YOUR_API_KEY with your key and change the target URL. The Node.js example uses Bun’s file writer; in Node.js, save the response body with your preferred file-writing method. ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets Claude, Cursor, and other MCP clients take screenshots. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. ScreenshotNeo is made by Yorker Media. Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.
10. Frequently asked questions
Does Puppeteer search my PATH for Chrome?
The documented system Chrome channel lookup checks known system locations. For a browser in a custom location, provide its path explicitly with executablePath.
Is Chromium interchangeable with Chrome?
Do not assume an arbitrary Chromium build is guaranteed to work. Puppeteer’s compatibility guarantee applies to its bundled browser; validate other binaries against your version.
Should I use a channel or executablePath?
Use a channel for a recognized Chrome release installed conventionally. Use executablePath when you know the exact executable location or manage a custom install.
Where does Puppeteer cache its downloaded browser?
The installation guide documents $HOME/.cache/puppeteer as the default since v19.0.0, with configuration available to change the cache directory.


