ScreenshotNeo

BlogHow-to

Puppeteer Browsers API: Install and Manage Chrome for Automation

Install the Chrome build your automation needs, manage Puppeteer’s browser cache, and choose between managed, self-managed, and remote browser workflows.

By the ScreenshotNeo team4 October 20269 min read

@puppeteer/browsers installs, lists, clears, and launches browser binaries from a command line or JavaScript API. To install the current stable Chrome for Testing build, run npx @puppeteer/browsers install chrome@stable. Use puppeteer when you want Puppeteer to download its compatible browser automatically; use puppeteer-core with an explicit executable when you manage Chrome yourself or connect to a remote browser. The [official Browsers API guide](https://pptr.dev/browsers-api) documents the CLI and programmatic workflows.

1. Choose who manages Chrome

Setup Who installs the browser? Use it when Trade-off
puppeteer Puppeteer’s install process You want its managed browser and standard local workflow. Package install scripts must run and the downloaded browser must be available at runtime.
puppeteer-core with local Chrome Your project or host You control the binary, cache, or system Chrome channel. You must configure the executable and validate compatibility.
puppeteer-core with remote Chrome A separate browser host The browser runs outside the application process. You must provide and secure a valid DevTools connection endpoint.

Puppeteer says its bundled browser is the guaranteed compatibility path. An independently managed executable may work, but compatibility is your responsibility. See the [installation guide](https://pptr.dev/guides/installation) and [launch options](https://pptr.dev/api/puppeteer.launchoptions).

2. Install a browser from the CLI

Use the CLI when you want to manage Chrome separately from a project’s Puppeteer dependency. Install a stable Chrome for Testing build, then list what is in the cache:

npx @puppeteer/browsers install chrome@stable
npx @puppeteer/browsers list

For a repeatable build, pin a specific version or build ID instead of following the moving stable channel:

npx @puppeteer/browsers install chrome@<version-or-build-id>

The guide also demonstrates milestone selection such as chrome@117. Its concrete version examples are documentation examples, not a recommendation to install those old builds. See the [CLI reference and examples](https://pptr.dev/browsers-api).

Check options supported by the version installed in your environment before scripting less common flags:

npx @puppeteer/browsers --help
npx @puppeteer/browsers install --help
npx @puppeteer/browsers list --help
npx @puppeteer/browsers clear --help

3. Launch the installed browser

For project automation, puppeteer is the simplest managed setup. It downloads a compatible Chrome during package installation. This complete Node.js example navigates to a page and writes a screenshot:

npm install puppeteer

// save as capture.mjs
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({headless: true});
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'networkidle2'});
  await page.screenshot({path: 'example.png', fullPage: true});
} finally {
  await browser.close();
}

Run it with node capture.mjs. For self-managed Chrome, install puppeteer-core and give it the actual executable path for your host:

npm install puppeteer-core

// save as capture-managed.mjs
import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: process.env.CHROME_PATH,
  headless: true,
});
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'networkidle2'});
  await page.screenshot({path: 'example.png', fullPage: true});
} finally {
  await browser.close();
}

Set CHROME_PATH to the executable path reported by your installation or system package. Do not assume that installing through the Browsers API automatically configures every Puppeteer project to launch that binary. The official guide recommends an explicit executablePath or a standard channel for a browser you manage.

4. Install programmatically

The API’s install() function takes a browser, build ID, and cache directory. Pick and pin a valid build ID for your target platform from your release process; the value below is deliberately supplied through an environment variable so it cannot silently pretend to be a current version.

npm install @puppeteer/browsers

// save as install-chrome.mjs
import {Browser, install} from '@puppeteer/browsers';

const buildId = process.env.CHROME_BUILD_ID;
if (!buildId) {
  throw new Error('Set CHROME_BUILD_ID to the Chrome build selected for this project.');
}

const installed = await install({
  browser: Browser.CHROME,
  buildId,
  cacheDir: process.env.PUPPETEER_CACHE_DIR ?? `${process.env.HOME}/.cache/puppeteer`,
});

console.log('Installed browser:', installed.browser);
console.log('Build:', installed.buildId);
console.log('Executable:', installed.executablePath);

Run it with CHROME_BUILD_ID=<chosen-build-id> node install-chrome.mjs. In production, configure an absolute cache path appropriate to the service account rather than relying on HOME being set. The default cache shown here matches Puppeteer’s documented default on Unix-like systems. The API also supports platform selection, download base URL, build aliases, expected SHA-256, providers, progress callbacks, and downloading without unpacking; consult the current [InstallOptions reference](https://pptr.dev/browsers-api/browsers.installoptions) for exact types and defaults. An expectedHash can make installation fail if the archive checksum differs. Without it, that explicit integrity check is not performed.

5. Configure the cache and package downloads

Puppeteer stores managed browsers in ~/.cache/puppeteer by default. Keep the cache path consistent between the install step and the runtime step, and ensure the runtime user can read and execute the installed files. Configuration can be set in a project Puppeteer config file or through documented environment overrides. See [Puppeteer configuration](https://pptr.dev/guides/configuration).

Setting Purpose Operational note
cacheDirectory / PUPPETEER_CACHE_DIR Choose where Puppeteer caches browsers. Build and runtime must agree on the path.
executablePath Point launch at a particular local binary. Verify that it exists in the runtime environment.
defaultBrowser Choose Puppeteer’s configured default browser. Check the current config reference for supported values.
skipDownload / PUPPETEER_SKIP_DOWNLOAD Suppress install-time browser downloads. Use only when another step provisions the browser.

For example, a project can configure a shared cache explicitly:

// .puppeteerrc.cjs
module.exports = {
  cacheDirectory: '/opt/puppeteer-cache',
};

When using puppeteer-core, Puppeteer does not download Chrome and does not assume a default browser configuration. Provision the executable yourself and pass its path when launching.

6. Inspect, remove, and provision dependencies

List installed browser records before debugging a launch. Clear the managed cache only when you intend to remove its installed browsers:

npx @puppeteer/browsers list
npx @puppeteer/browsers clear

The programmatic API exposes getInstalledBrowsers({cacheDir}) for metadata and uninstall() for removing a specific installation. The returned installation record includes the browser, build ID, platform, installation path, and executable path. See the [installed browser API](https://pptr.dev/browsers-api/browsers.installedbrowser).

On Debian or Ubuntu, the Puppeteer CLI can attempt to install Chrome’s system dependencies:

npx puppeteer browsers install chrome --install-deps

This dependency installation is supported only for Chrome on Debian/Ubuntu and requires root privileges. It is a host setup operation, not a general solution for every Linux distribution or container image.

7. Remote browser connections

Use puppeteer-core when connecting to a browser that is already running elsewhere. The browser host must provide a valid DevTools WebSocket endpoint. The endpoint is deployment-specific; do not put a made-up or public endpoint in application code.

npm install puppeteer-core

// save as remote.mjs
import puppeteer from 'puppeteer-core';

const endpoint = process.env.BROWSER_WS_ENDPOINT;
if (!endpoint) throw new Error('Set BROWSER_WS_ENDPOINT to the remote browser WebSocket URL.');

const browser = await puppeteer.connect({browserWSEndpoint: endpoint});
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'networkidle2'});
  console.log(await page.title());
} finally {
  await browser.disconnect();
}

disconnect() closes Puppeteer’s connection without asking the remote browser process to shut down. Use close() only when your process owns that browser and should terminate it. Treat a WebSocket endpoint like a credential: restrict access and avoid logging its secret components.

8. Host requirements, proxies, and debugging

  • Use a Node.js version supported by the installed Puppeteer release; check the current [system requirements](https://pptr.dev/guides/system-requirements).
  • Chrome archive extraction requires unzip on Linux/macOS and tar.exe on Windows. Other browser archives may need additional platform utilities.
  • The CLI honors HTTP_PROXY, HTTPS_PROXY, and NO_PROXY when the proxy-agent package is installed.
  • For verbose install and launch diagnostics, use the documented Node debug channels:
env NODE_DEBUG="puppeteer:browsers:*" npx @puppeteer/browsers install chrome@stable

Available channels include puppeteer:browsers:cache, puppeteer:browsers:fileUtil, puppeteer:browsers:install, and puppeteer:browsers:launcher. See the [Browsers API guide](https://pptr.dev/browsers-api).

9. Common errors and fixes

Symptom Likely cause What to check or change
Could not find Chrome (ver. ...) The package manager blocked Puppeteer’s install script, or no browser was provisioned. Run npx puppeteer browsers install (or the equivalent for your package manager), or allow Puppeteer’s install script. Confirm the cache path.
Executable path does not exist The path points to another machine, user, container layer, or cache directory. Print the configured path; check the file exists and is executable inside the runtime environment.
Browser starts locally but fails in a container Host libraries or archive utilities are missing, or the browser was installed in a different build stage. Install the required system dependencies for that OS, preserve the browser cache in the runtime image, and use install logs to find the missing component.
Download times out or cannot connect Network policy, proxy settings, or an unavailable download source. Check outbound access and proxy variables; install proxy-agent for the documented CLI proxy behavior.
Remote connect() rejects the endpoint The WebSocket URL is absent, invalid, expired, or unreachable from the app. Check the browser host’s current endpoint and network access; verify the expected endpoint type.
Chrome launches but behaves unexpectedly A self-managed browser version may not match Puppeteer’s expectations. Prefer Puppeteer’s bundled browser, or pin and validate the executable version with your own workflow.
Install fails while unpacking A required extraction utility is missing or the filesystem lacks space/permissions. Install the platform’s required archive tool; check available space and write access to the cache directory.

The official [installation guide](https://pptr.dev/guides/installation) covers blocked install scripts and the “Could not find Chrome” case. Use the [troubleshooting guide](https://pptr.dev/troubleshooting) for host-specific browser launch issues.

10. Performance, reliability, and cost

  • Build time and storage: Browser archives are large, so avoid downloading a new copy on every build. Cache or provision the browser deliberately, while keeping its version aligned with the project.
  • Reproducibility: A stable channel moves over time. Pin a build ID when reproducible runs matter, and update it on a deliberate schedule.
  • Runtime consistency: Install and launch under compatible operating systems and user permissions. A cache path that exists only during image build will not help a separate runtime container.
  • Integrity: Supply the expected archive hash when your installation process requires checksum verification.
  • Compatibility: Puppeteer guarantees compatibility with its bundled browser. System Chrome, custom providers, and other binary sources need your own validation. The docs describe custom providers as unsupported; you own their compatibility, testing, and maintenance.
  • Direct cost: The API is an open-source browser management package; the practical costs are browser download bandwidth, disk, build time, and the compute needed to run Chrome. The dossier provides no vendor pricing for hosted browser services.

11. Or skip the browser setup

If the task is to capture a website rather than automate an entire browser session, [ScreenshotNeo](https://screenshotneo.com) provides a website screenshot API and MCP server. One GET request returns an image or PDF; see the [API documentation](https://screenshotneo.com/docs/) for parameters and response details.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.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);

ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. [Create a free account](https://screenshotneo.com/account/sign-up/).

12. Frequently asked questions

Does installing @puppeteer/browsers install Puppeteer too?

No. The package manages browser binaries. Add puppeteer or puppeteer-core separately if your application needs Puppeteer’s automation API.

Should I use chrome@stable in CI?

Use it when following the current stable release is intended. Pin a build ID when repeatable browser behavior across runs matters.

Can I use a system-installed Chrome?

Yes. Use puppeteer-core and pass executablePath or a supported channel. Validate compatibility because the bundled browser is Puppeteer’s guaranteed option.

When is puppeteer-core the right package?

Choose it when another process manages the browser binary or when you connect to a remote DevTools-compatible browser. It does not download Chrome.