Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install puppeteer when you want Puppeteer to download a compatible Chrome for Testing build, or install puppeteer-core when you will manage Chrome yourself. The Node API is puppeteer.launch(options). A normal installation is npm i puppeteer; if the browser download was skipped, run npx puppeteer browsers install. With puppeteer-core, always provide executablePath or channel.

Choose how Puppeteer will obtain Chrome

Puppeteer is a JavaScript library that controls Chrome or Firefox through Chrome DevTools Protocol or WebDriver BiDi. The npm package and the browser binary are separate concerns, so decide who owns the browser before writing launch code.

Strategy Install Browser ownership Launch requirement Best use
Bundled Puppeteer npm i puppeteer Puppeteer downloads Chrome for Testing Usually no path is needed Local development and predictable version matching
Managed browser npm i puppeteer-core You provide Chrome, Chromium or a remote browser executablePath or channel System Chrome, custom containers and controlled infrastructure
Manual Puppeteer browser install Puppeteer package plus npx puppeteer browsers install Puppeteer’s cache Use Puppeteer’s resolved executable CI or package managers that suppress post-install scripts

The bundled route is normally the least surprising. Puppeteer’s installer downloads a recent Chrome for Testing build and a chrome-headless-shell binary. The download is large—approximately 170 MB on macOS, 282 MB on Linux and 280 MB on Windows—so account for it in build and cache storage.

Install Puppeteer and run your first headless script

  1. Make a project and initialize npm:
    mkdir headless-demo
    cd headless-demo
    npm init -y
  2. Install the batteries-included package:
    npm i puppeteer
  3. Create capture.mjs with this complete example:
    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'});
      console.log(await page.title());
    } finally {
      await browser.close();
    }
  4. Run it:
    node capture.mjs

puppeteer.launch() returns a Promise for a Browser. The browser runs headless by default; setting headless: true makes that intent explicit. Always close the browser in a finally block so failed navigation does not leave Chrome processes behind.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install when package scripts are blocked

npm, pnpm, Yarn Berry, Bun and Deno policies can disable install scripts. In that case, the JavaScript package may be present while its browser is missing. Install the package, then explicitly download the browser:

npm i puppeteer
npx puppeteer browsers install

Run the second command in the same build stage and user account that will execute your application. In CI, persist the resulting browser cache between jobs or image layers; otherwise every clean build downloads Chrome again.

Use puppeteer-core with a system or managed Chrome

puppeteer-core contains the library only. It does not download Chrome, and its launch API requires either an executable path or a browser channel.

npm i puppeteer-core
import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: process.env.CHROME_BIN
  // Alternatively: channel: 'chrome'
});
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'networkidle2'});
  console.log(await page.title());
} finally {
  await browser.close();
}

Set CHROME_BIN to a path that exists inside the runtime, not merely on your development machine. A channel such as chrome asks Puppeteer to locate an installed branded Chrome. Puppeteer works best with the Chrome for Testing version it downloads and does not guarantee compatibility with arbitrary browser versions, so test managed upgrades before deploying them.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Understand the browser cache and fix “Could not find Chrome”

Since Puppeteer v19.0.0, downloaded browsers are cached under ~/.cache/puppeteer by default. A cache that exists on a laptop may not exist in a container, CI worker or serverless build.

  1. Check whether your package manager blocked the install script.
  2. Run npx puppeteer browsers install explicitly.
  3. Confirm the runtime user can read the cache and execute the binary.
  4. Make the cache survive the build boundary. If a platform preserves node_modules but skips post-install hooks, configure the Puppeteer cache under node_modules/.puppeteer_cache as recommended for Google runtimes.
  5. If you use a system browser, stop looking in Puppeteer’s cache and verify CHROME_BIN, executablePath or channel instead.

A common failure pattern is “works locally, fails in CI”: local installation ran the download hook, while the CI image copied only JavaScript dependencies. Make browser installation and cache persistence explicit in the image or pipeline.

Launch options that matter in production

Headless mode

Use headless: true for normal automation. A visible browser is useful while debugging locally, but requires a display server in Linux environments. Keep the production setting explicit so a dependency upgrade cannot silently change behavior.

Executable selection

Use executablePath for an exact binary path and channel when Chrome is installed in a known browser channel. Do not set both unless you have a deliberate reason; an explicit path removes discovery ambiguity.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Arguments and the sandbox

Chrome’s sandbox is a host-protection layer. Run as a non-root user with a real home directory whenever possible. The --no-sandbox argument is an environment-specific exception for content you absolutely trust, not a default fix. Disabling the sandbox reduces isolation and can turn a browser compromise into a host compromise.

Navigation readiness

page.goto() can wait for a lifecycle condition such as networkidle2, but pages that poll, stream or keep analytics connections open may never become truly idle. For deterministic jobs, wait for a specific selector or application signal after navigation and use a bounded timeout. Treat a timeout as a diagnosable result, not proof that the URL is permanently unavailable.

Profiles and parallelism

Give independent jobs separate temporary profile directories. Reusing one profile across concurrent Chrome processes can corrupt locks and cookies. Reuse a browser for several pages when startup cost dominates, but isolate tenants and close pages after each job to cap memory.

Linux and Docker: dependencies, users and writable paths

Headless Chrome is not a single portable file. Linux launches require shared libraries, permissions and writable profile and cache directories.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Diagnose missing shared libraries

On Debian-family systems, inspect the downloaded Chrome binary:

ldd /path/to/chrome | grep not

Install the missing packages. Common requirements include libnss3, libgbm1, libgtk-3-0, libasound2, libx11-6 and libx11-xcb1. The exact package names can vary by distribution release, so use your image’s package manager and verify the result with ldd.

Use a non-root container user

  • Create a user with a writable home directory.
  • Give that user ownership of the Puppeteer cache, temporary profile and application directory.
  • Ensure the container has enough shared memory and temporary disk for the pages you capture.
  • Install the browser and dependencies in the image layer that runs the application.

Running as root often produces sandbox errors and permission surprises. Adding --no-sandbox may hide the symptom but should be reserved for trusted content and a deliberately isolated environment.

Alpine Linux

Chrome does not support Alpine out of the box. If you choose Alpine, match its Chromium package to your Puppeteer version and test the complete image, including fonts, shared libraries and sandbox behavior. A Debian-family base image is usually simpler when you need Puppeteer’s downloaded Chrome for Testing build.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cloud Run, App Engine and Functions

Google Cloud Run

The default Node.js runtime does not include the system packages required by Headless Chrome. Build a custom Docker image that installs Chrome or Chromium, all required libraries, a non-root user and a persistent-enough Puppeteer cache for the image lifecycle. Set executablePath when the image owns the browser, and test the exact deployed image rather than only the local source tree.

Google App Engine standard and Cloud Functions

The documented runtimes include the system packages needed by Puppeteer. Install dependencies during the build and keep the Puppeteer cache in a build-persistent location when install hooks may not run again. Cold starts still pay browser startup and page-loading costs, so avoid downloading a browser on every invocation.

Serverless limits

Bound navigation and total job time, close every browser or page, and log whether failure occurred during browser launch, navigation or page evaluation. Keep concurrency within the memory available to each instance; several Chromium processes can exhaust a small function quickly.

Troubleshoot the failure you actually have

Symptom Likely cause Fix
Could not find Chrome Install script was skipped or cache is absent Run npx puppeteer browsers install, persist ~/.cache/puppeteer, or set a verified executablePath/channel.
Failed to launch: missing shared library Linux image lacks Chrome dependencies Run ldd chrome | grep not and install packages such as libnss3, libgbm1 and libgtk-3-0.
Sandbox or permission error Running as root or using unwritable home/profile paths Use a non-root user and writable directories; use --no-sandbox only for trusted content in an isolated environment.
Navigation timeout Slow site, blocked request, or a page that never becomes idle Use a bounded timeout, wait for a concrete selector, and capture console/request logs to identify the stalled resource.
Works locally but not in Docker Different OS libraries, user, cache or environment variables Reproduce with the deployed image, inspect the binary with ldd, verify ownership and print the resolved executable path.
Alpine launch failure Chrome/Chromium is not supported by the base image without extra work Use a compatible Chromium package and Puppeteer version, or switch to a Debian-family image.
Cloud Run launch failure Default runtime lacks Headless Chrome packages Deploy a custom image containing the browser, dependencies, writable paths and a non-root user.

Performance, reliability and cost planning

  • Startup: launching Chrome is expensive compared with opening a new page. Reuse one browser for a controlled batch, but isolate jobs that handle different users or credentials.
  • Downloads: cache the approximately 170–282 MB browser artifact in CI and container layers instead of downloading it for every build.
  • Memory: cap parallel pages and close them promptly. Full-page layouts, large images and multiple browser processes increase resident memory.
  • Determinism: pin your Puppeteer dependency and test the browser version shipped with it. Arbitrary system Chrome versions have no compatibility guarantee.
  • Security: keep the Chrome sandbox enabled, avoid untrusted extensions and never place secrets in URLs or page content.
  • Observability: record launch mode, executable path, browser version, navigation URL, timeout stage and final error. This separates missing binaries from site-level failures.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup: ScreenshotNeo

If your goal is a clean website screenshot rather than browser automation logic, ScreenshotNeo provides a single HTTP request. It accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and the response reports the result in X-Page-Verdict and X-Billed headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

See the ScreenshotNeo API documentation for all options. This cURL request returns a WebP image:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same endpoint from Python:

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)

And Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server for AI clients such as Claude and Cursor, with take_screenshot, get_page_info and capture_pdf tools. Its 63 options include full-page captures with lazy images loaded, CSS-selector element shots, dark mode, 12 device presets or custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, pre-capture clicks, selector/delay/network-idle waits, ad and tracker blocking, custom headers/cookies/user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API and an OpenAPI specification. Common parameter names from other screenshot APIs are accepted to ease migration.

Plan Included shots Price
Free 1,000 per month $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Yearly billing gives two months free, and every feature is available on every plan. Sign up for 1,000 free screenshots a month with no card.

FAQ

Can Puppeteer drive Firefox?

Yes. Puppeteer’s high-level API supports Chrome and Firefox through DevTools Protocol or WebDriver BiDi, although this installation guide focuses on Chrome binaries and Linux deployment requirements.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why does a successful HTTP response still produce no screenshot?

HTTP success only proves that a server answered. Browser rendering can still fail because of scripts, blocked resources, missing libraries, sandbox restrictions or a page that never reaches your chosen readiness condition.

Should I commit the downloaded Chrome binary to Git?

No. Keep the binary in a build cache or image layer, install it reproducibly with Puppeteer’s browser command, and record the dependency version used to create that cache.

Frequently Asked Questions

Can Puppeteer drive Firefox?

Yes. Puppeteer’s high-level API supports Chrome and Firefox through DevTools Protocol or WebDriver BiDi, although this guide focuses on Chrome binaries and Linux deployment.

Why does a successful HTTP response still produce no screenshot?

An HTTP response only proves that a server answered; browser rendering can still fail because of scripts, blocked resources, missing libraries, sandbox restrictions or an unmet readiness condition.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I commit the downloaded Chrome binary to Git?

No. Keep it in a reproducible build cache or image layer and record the Puppeteer dependency version used to create that cache.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.