ScreenshotNeo

BlogHow-to

How to Install Puppeteer Core

Install Puppeteer Core, provide a compatible browser, and launch it with executablePath, channel, or a remote endpoint.

By the ScreenshotNeo team1 October 20267 min read

Direct answer: install the package with npm i puppeteer-core. Puppeteer Core does not download Chrome, so you must provide a compatible browser and pass either executablePath or channel to launch(). You can also connect to a browser that is already running remotely.

What Puppeteer Core installs

puppeteer-core is the browser automation library without an automatic browser download. The full puppeteer package downloads a supported browser during installation and uses Core underneath. Core is useful when your team manages browser binaries, uses a container image, or connects to a remote DevTools endpoint. Read the official installation guide and launch API for release-specific details.

Install Puppeteer Core step by step

1. Check Node.js and your package manager

Use the Node.js version required by the Puppeteer release you plan to install. The current system-requirements page says Node.js 22.12 or newer, but requirements can change, so check the system requirements for your pinned release.

node --version
npm --version

Run the installation from the directory that contains your application’s package.json. Keep the package manager and lockfile already used by the project.

npm install puppeteer-core

Equivalent commands are:

yarn add puppeteer-core
pnpm add puppeteer-core
bun add puppeteer-core

2. Provide a browser separately

Choose one of these browser sources:

Browser source Launch setting When to use it
Local Chrome or Chromium at a known path executablePath CI images, servers, custom installations
Chrome installed in a standard location channel Developer machines with stable Chrome or another supported channel
Browser already running elsewhere puppeteer.connect() Remote browser services, shared browser hosts, or a separate container

Puppeteer’s supported-browser table is version-specific. Check the supported browsers mapping before upgrading Puppeteer or pinning a browser image. Puppeteer guarantees compatibility with its documented browser pairing; an arbitrary system browser version is not guaranteed.

3. Install Chrome for Testing when you manage the browser yourself

Puppeteer’s browser tooling can install a Chrome for Testing build independently of the Node package:

npx @puppeteer/browsers install chrome@stable

On Debian or Ubuntu, the documented command can also install required system dependencies. It may require root privileges:

npx puppeteer browsers install chrome --install-deps

Record the resulting executable path and pass it to launch(). In automated builds, install the browser during image creation and pin both the package and browser versions when repeatability matters.

Launch with an explicit executable path

This CommonJS example is runnable after installing puppeteer-core and a compatible Chrome or Chromium binary.

const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.launch({
    executablePath: '/absolute/path/to/chrome',
    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();
  }
})();

Replace the path with the binary available on your operating system or container. Keep the path outside source code when it differs between environments; an environment variable is usually simpler.

const browser = await puppeteer.launch({
  executablePath: process.env.CHROME_BIN,
  headless: true
});

Launch a standard Chrome channel

When Chrome is installed in a standard location, use a channel instead of hard-coding a path:

const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.launch({
    channel: 'chrome',
    headless: true
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  console.log(await page.title());
  await browser.close();
})();

The exact channel names and availability depend on the installed browser and Puppeteer release. If channel discovery fails, switch to an explicit executablePath.

Use ES modules or TypeScript

With "type": "module" in package.json, import Puppeteer Core and use the same launch options:

import puppeteer from 'puppeteer-core';

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

TypeScript projects can use the same API. Ensure your runtime supports the module format you compile to, and keep browser startup and shutdown inside the process lifecycle so failed jobs do not leave Chrome processes behind.

Connect to a remote browser

If another service starts Chrome with a DevTools endpoint, connect instead of launching a local process. Obtain the endpoint from that service and use the URL it documents:

const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.connect({
    browserURL: process.env.BROWSER_URL
  });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    console.log(await page.title());
  } finally {
    await browser.disconnect();
  }
})();

Use disconnect() when the browser is owned by another service. Calling close() may terminate a shared browser, depending on how that service exposes the connection.

Common launch options

Option Purpose Practical note
executablePath Selects a local browser binary Use an absolute path or an environment variable.
channel Selects a standard Chrome channel Use only when that channel is installed and supported.
headless Runs without a visible window Use headless mode on servers and CI.
args Adds Chromium command-line flags Keep flags minimal; security and sandbox behavior are environment-dependent.
env Sets environment variables for the browser process Useful for proxy or locale configuration when supported by your runtime.
timeout Limits browser startup time Set a finite value in workers so a stuck process can be reported.

Minimal screenshot script

const puppeteer = require('puppeteer-core');

(async () => {
  const browser = await puppeteer.launch({
    executablePath: process.env.CHROME_BIN,
    headless: true
  });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
    await page.goto('https://example.com', { waitUntil: 'networkidle2', timeout: 30000 });
    await page.screenshot({ path: 'example.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

Or skip the browser setup

If your goal is a clean website screenshot rather than maintaining Chrome, ScreenshotNeo provides a GET endpoint that returns PNG, JPEG, WebP, or PDF. The API accepts the URL and an access key; see the ScreenshotNeo API docs.

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}`);

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account to get started.

Troubleshooting

“An executablePath or channel must be provided”

Cause: Core was launched without a browser selection. Fix: add executablePath or channel, or use puppeteer.connect() for a remote browser.

“Failed to launch the browser process”

Cause: the path is wrong, the binary lacks execute permission, or a required shared library is missing. Fix: verify the path with your shell, check permissions, install the platform dependencies, and run the browser manually in the same environment.

Chrome starts locally but fails in CI

Cause: the CI image does not contain the browser or its libraries, or the runtime user has different permissions. Fix: install Chrome for Testing and dependencies while building the image, set CHROME_BIN, and use the same user that runs the job.

Browser and Puppeteer versions behave inconsistently

Cause: an unsupported browser/package pairing. Fix: consult the supported-browser mapping, pin compatible versions, and upgrade them together.

Pages hang during navigation

Cause: the page keeps connections open or waits on third-party resources. Fix: set navigation and operation timeouts, choose an appropriate waitUntil condition, and close the browser in a finally block.

Sandbox errors on Linux

Cause: the process user or container configuration cannot use Chromium’s sandbox. Fix: run with a correctly configured sandbox and non-root user where possible; change launch flags only when your deployment security model explicitly permits it.

Remote connection is refused

Cause: the endpoint is unreachable, the port is blocked, or the remote browser exited. Fix: verify network access and endpoint lifetime, then reconnect with bounded retry logic.

Performance, reliability, and cost

  • Startup: launching a fresh browser is expensive compared with creating a new page. In a worker, reuse a healthy browser and create isolated pages, then recycle the browser on a schedule or after repeated failures.
  • Concurrency: limit simultaneous pages according to available CPU and memory. Excessive parallelism causes slow rendering and crashes.
  • Repeatability: pin puppeteer-core and the browser build in CI. Record the browser version with artifacts so visual differences can be explained.
  • Timeouts: use finite browser, navigation, and task timeouts. Always close or disconnect in cleanup code.
  • Network: wait only for the condition your page needs. networkidle2 can take longer on sites with analytics or streaming requests.
  • Cost: Puppeteer Core itself is an npm dependency; your infrastructure cost comes from browser downloads, CPU, memory, storage, and any remote browser service. ScreenshotNeo charges only for clean shots and offers 1,000 free shots monthly.

Installation checklist

  • Confirm the Node.js requirement for your pinned Puppeteer release.
  • Install puppeteer-core with the project’s existing package manager.
  • Install or provision a compatible Chrome, Chromium, or remote browser.
  • Configure exactly one browser source: executablePath, channel, or a remote connection.
  • Verify the browser/package pairing against Puppeteer’s support table.
  • Add finite timeouts and guaranteed cleanup.
  • Test the same user, libraries, and binary path used in production.

FAQ

Does Puppeteer Core include Chrome?

No. It installs the Node.js automation library only. You provide a local browser or connect to one remotely.

Should I install puppeteer instead?

Choose puppeteer when its managed browser download fits your project. Choose Core when browser provisioning must remain under your control.

Can I use Firefox?

Use the browser support table for the Puppeteer release you install and follow its documented browser selection requirements.

Is a system Chrome always compatible?

No. Check the supported-browser mapping and pin versions when compatibility matters.

Can Puppeteer Core capture a page without launching Chrome?

Yes. Connect to a compatible browser that is already running with puppeteer.connect().