How to Install Chrome and Other Browsers with Puppeteer
Install Puppeteer with its compatible Chrome for Testing browser, or manage Chrome, Chromium, and Firefox yourself. Includes launch examples and fixes for common setup errors.
The shortest way to install Puppeteer and a compatible browser is to install the puppeteer package. Its install process normally downloads Chrome for Testing and chrome-headless-shell, which are matched to that Puppeteer release. If you want to manage the browser yourself, use puppeteer-core and provide a supported browser channel, executable path, or remote browser connection.
Use the bundled browser for the most predictable local setup. Choose a separately installed Chrome or Chromium when your environment already manages browser updates, and consult Puppeteer’s supported browser table before choosing Firefox or pinning a browser version.
1. Check the prerequisites
Puppeteer’s current system requirements list Node.js 22.12 or later, and TypeScript 5.0.1 or later if you use TypeScript. Check the current system requirements before installing, especially on Linux: required system libraries vary by distribution. Supported environments listed by Puppeteer include Windows x64, macOS x64 and arm64, and Debian/Ubuntu, openSUSE, and Fedora Linux on x64 and arm64.
Installing the default browser also requires disk space and a working download path. Puppeteer’s installation guide gives approximate browser download sizes of 170 MB on macOS, 282 MB on Linux, and 280 MB on Windows; these values can change. In containers and CI, account for the browser files and Linux libraries in the image or cache.
2. Install Puppeteer and its bundled Chrome
Run one command in your Node.js project with the package manager you use:
# npm
npm install puppeteer
# Yarn
yarn add puppeteer
# pnpm
pnpm add puppeteer
# Bun
bun add puppeteer
Remove the leading space before yarn if copying the command; it is only shell whitespace and does not affect execution.
The package’s install process normally downloads a recent Chrome for Testing build and chrome-headless-shell. Puppeteer documents its paired Chrome as the browser guaranteed to work with that Puppeteer release. See the official installation guide for package-manager-specific install-script behavior.
Run a first screenshot
Save this as screenshot.mjs, then run node screenshot.mjs https://example.com. It uses the installed Puppeteer package and its downloaded browser:
import puppeteer from 'puppeteer';
const targetUrl = process.argv[2] ?? 'https://example.com';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto(targetUrl, {
waitUntil: 'networkidle2',
timeout: 30_000,
});
await page.screenshot({ path: 'page.png', fullPage: true });
console.log(`Saved page.png from ${targetUrl}`);
} finally {
await browser.close();
}
For a simpler readiness condition, use waitUntil: 'domcontentloaded' or 'load'. Network idle can wait indefinitely on sites that keep requests open, such as pages using long polling. Set a navigation timeout and choose the readiness condition that matches what the page needs before capture.
3. Install the browser manually if the download was skipped
Some package-manager configurations block dependency install scripts. Puppeteer may then install successfully without downloading its browser, and launch can fail with a missing Chrome error. Install the browser explicitly from the project directory:
npx puppeteer browsers install
For other package managers, use the equivalent supported command or allow Puppeteer’s install script in that package manager’s project configuration. The exact setting differs among npm, pnpm, Yarn Berry, Bun, and Deno, so follow the current Puppeteer installation instructions for your manager rather than copying a setting from another one.
You can also use @puppeteer/browsers when you want explicit control over browser installation. Its CLI and API support installing Chrome for Testing by channel or exact version. The package documents a Debian/Ubuntu Chrome command that can attempt to install system dependencies as well; that operation requires root privileges. See the @puppeteer/browsers documentation for exact commands and options.
4. Choose the right package and browser
| Setup | Who installs and updates the browser? | When to use it |
|---|---|---|
puppeteer |
Puppeteer’s install process downloads its paired browser. | Local development, scripts, or CI where the bundled browser is acceptable. |
puppeteer-core with channel or executablePath |
Your operating system, container, or deployment process. | You already manage a browser installation or need to choose its path. |
puppeteer-core with connect() |
A remote browser service or another process that launched Chrome. | The browser runs separately from the Node.js application. |
puppeteer-core does not download a browser. Its launch call must identify one with a channel or executable path. Puppeteer cautions that it guarantees compatibility with its bundled browser, not every external binary. For version selection, check the supported browsers table and the launch options API.
Use the bundled Chrome with puppeteer
This is the default from the first example. Do not set executablePath unless you need to override the bundled browser.
Use an installed Chrome channel
If Chrome is installed in a standard location, install puppeteer-core and choose a supported channel. For example, save this as channel.mjs and run node channel.mjs:
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();
}
A channel selects a locally installed Chrome channel; it does not install Chrome. The available channels and whether they are present depend on the machine. Consult the launch options documentation for supported values.
Use a Chrome or Chromium executable path
Use executablePath when the browser binary lives at a known path, as it often does in a managed container. Install the package with npm install puppeteer-core, then save the following as path.mjs. Set CHROME_PATH to the actual executable before running it:
import puppeteer from 'puppeteer-core';
const executablePath = process.env.CHROME_PATH;
if (!executablePath) {
throw new Error('Set CHROME_PATH to the Chrome or Chromium executable');
}
const browser = await puppeteer.launch({
executablePath,
headless: true,
});
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: 'page.png' });
} finally {
await browser.close();
}
Use the executable path for the installed browser binary, not its application folder or a launcher script. The exact path varies by operating system and installation method. Verify that the process running Node can execute the file and read its dependencies.
Use Firefox
Puppeteer supports Firefox, but the matching browser version and installation steps depend on the Puppeteer release. Do not assume that a Chrome installation command or arbitrary Firefox build is compatible. Check the supported browser version table and current browser installation documentation, then use the browser installation method those docs specify for your Puppeteer version.
Connect to a remote browser
When another process or service owns the browser, use Puppeteer’s connection API instead of launching a local executable. For a browser that exposes a WebSocket endpoint, the shape is:
import puppeteer from 'puppeteer-core';
const browserWSEndpoint = process.env.BROWSER_WS_ENDPOINT;
if (!browserWSEndpoint) {
throw new Error('Set BROWSER_WS_ENDPOINT to the browser WebSocket 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 {
await browser.disconnect();
}
Use disconnect() when the remote process owns the browser and should keep running. Use close() for a browser instance your script launched and owns. Refer to Puppeteer’s guide on running Puppeteer in the browser for remote connection context.
5. Configure launch and capture behavior
Keep configuration tied to a concrete requirement. A minimal launch for the bundled browser is usually the most portable starting point:
const browser = await puppeteer.launch({ headless: true });
headless: use headless mode for automation without a visible browser window. For a visible window during local debugging, use the documented headful setting and ensure the machine has a display environment.channel: select a locally installed Chrome channel when using a supported channel and standard installation location.executablePath: select a specific local browser binary. This shifts installation and version compatibility to your environment.- Navigation
waitUntilandtimeout: choose a page readiness event and a bounded wait. A page’s load event does not guarantee that every application-rendered element is ready. - Screenshot options: choose a path, image type, and whether to capture the full page. Wait for the content that matters before capturing.
For complete and version-specific option names, use the LaunchOptions API reference. Avoid copying old launch flags without checking current Puppeteer guidance: flags can affect security, sandboxing, and browser behavior.
6. Troubleshoot installation and launch errors
| Symptom | Likely cause | What to do |
|---|---|---|
| “Could not find Chrome” or a missing browser version | The install script was skipped or the browser download did not complete. | Run npx puppeteer browsers install. Check the package manager’s install-script policy and the installation output. |
puppeteer-core cannot find a browser |
No browser is downloaded by this package, and launch has no valid browser selection. | Set channel for an installed supported Chrome channel or set executablePath to a real executable. Alternatively, install puppeteer for the bundled browser. |
| Browser executable exists but will not start | The path may point to the wrong file, permissions may be insufficient, or system libraries may be missing. | Confirm the binary path and execution permissions. On Linux, follow the current distribution-specific packages in Puppeteer’s system requirements. |
| Browser launches locally but fails in a container | The image may lack required libraries, fonts, writable directories, or a suitable sandbox environment. | Build from a supported environment, install the documented distribution packages, and review the container’s user and security configuration. Do not add broad security-disabling flags without understanding the tradeoff. |
| External Chrome crashes or behaves differently | The browser version may not match the Puppeteer release. | Compare it with the supported browser table; use Puppeteer’s bundled browser when compatibility matters most. |
| Install takes a long time or fails during download | Browser binaries are large and the download may be blocked, interrupted, or uncached. | Check network access and available disk space, then retry the documented browser installation. In CI, cache browser downloads where the environment supports it. |
| Navigation times out on a page that appears loaded | The chosen readiness event may wait on long-lived requests or application activity. | Use a more suitable event such as domcontentloaded, or wait for a specific selector with a bounded timeout. |
For Debian or Ubuntu, the @puppeteer/browsers CLI documents an option to install Chrome’s system dependencies; the command requires root privileges. For other Linux distributions, use the distribution-specific links in Puppeteer’s system requirements rather than assuming the Debian package list applies.
7. Plan for performance, reliability, and cost
- Installation cost: Puppeteer is open-source software, but its browser download consumes bandwidth and disk space. The approximate sizes above are documentation figures and can change with releases.
- Startup time: launching a new browser for every URL adds overhead. For a batch owned by one process, reuse a browser and create or close pages per task, while ensuring a failure cannot leave the browser process orphaned.
- Version reliability: keep Puppeteer and its paired browser aligned. If you use a separately managed browser, pin or update the pair deliberately and validate after upgrades.
- CI reliability: make the browser download and Linux dependencies part of a repeatable image or setup step. Cache downloaded binaries when appropriate, and set finite navigation and operation timeouts.
- Failure handling: close locally launched browsers in a
finallyblock. For remote connections, disconnect without shutting down a browser owned by another process. - Page variability: network-idle conditions and fixed delays are imperfect signals. Waiting for a selector tied to the content you need is often more reliable for application pages.
Or skip the browser setup
If your task is simply to capture a webpage, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API docs for request options.
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 import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
Cookie banners, newsletter popups, and chat widgets are removed before the shot, and each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed; response headers report the page verdict and billing status. The MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Every feature is on every plan.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does installing Puppeteer install Google Chrome?
The standard puppeteer install downloads Chrome for Testing and chrome-headless-shell. It does not rely on your regular Chrome installation.
Can I use Chromium instead of Chrome?
Yes, if you provide a compatible local executable path. Puppeteer guarantees compatibility with its bundled browser; check the supported browser information when using another binary.
Should I install puppeteer or puppeteer-core?
Choose puppeteer when you want Puppeteer to download its paired browser. Choose puppeteer-core when your code or infrastructure will select and manage the browser.
Can I use Puppeteer without installing a browser on my machine?
Yes. Connect to a remote browser using Puppeteer’s connection API, or use a screenshot API such as ScreenshotNeo when you need an image or PDF rather than browser automation.
How do I know which Firefox version to install?
Use the supported browser version table for your Puppeteer release and follow its current browser installation guidance. Compatibility details can change between releases.


