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

Set PUPPETEER_SKIP_DOWNLOAD=true in the same environment and installation step that runs Puppeteer’s install script. If Chrome was already downloaded, changing the variable later cannot remove it. If you use puppeteer-core, the variable is ignored and no browser is downloaded automatically; you must supply a separately installed browser and an explicit connection method.

The reliable fix is to identify the package, verify the variable reaches the install process, check whether install scripts are allowed, and then either let Puppeteer install its browser or provide a compatible Chrome/Chromium executable yourself.

What PUPPETEER_SKIP_DOWNLOAD actually controls

PUPPETEER_SKIP_DOWNLOAD is an installation-time switch. With the value true, Puppeteer skips its browser-download step during installation. It does not disable browser launching, remove a browser that was downloaded previously, or install Chrome for you.

Set it before the package manager starts the install:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
PUPPETEER_SKIP_DOWNLOAD=true npm install puppeteer

On Windows PowerShell:

$env:PUPPETEER_SKIP_DOWNLOAD = "true"
npm install puppeteer

On Windows Command Prompt:

set PUPPETEER_SKIP_DOWNLOAD=true && npm install puppeteer

Environment variables take precedence over the corresponding skipDownload configuration where Puppeteer supports that setting. The variable must exist in the shell, container build layer, CI job, or package-manager hook that actually executes installation.

First check whether you installed puppeteer or puppeteer-core

puppeteer

The full puppeteer package manages a compatible browser download unless you skip it. Its installation script reads the download configuration. If you skip the download, your application still needs a browser at runtime.

puppeteer-core

puppeteer-core is intended for projects that manage the browser themselves. Puppeteer’s configuration guide states: “Puppeteer’s configuration files and environment variables are ignored by puppeteer-core.” It also does not download Chrome automatically. Therefore, PUPPETEER_SKIP_DOWNLOAD has no useful effect for this package: install Chrome or Chromium separately and pass its path or connect to an already running browser.

Inspect package.json, your lockfile, and imports:

npm ls puppeteer puppeteer-core
const puppeteer = require('puppeteer');
// or
const puppeteerCore = require('puppeteer-core');

If you intended Puppeteer to manage the browser, replace puppeteer-core with puppeteer and reinstall. If administrator-managed browsers are intentional, keep puppeteer-core and configure the executable explicitly.

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

Use a deterministic installation sequence

  1. Remove the existing installation if you are changing policy. Delete node_modules and reinstall from the lockfile so an old postinstall result does not confuse the diagnosis.
  2. Export the variable before installation. Confirm it in the same process that invokes npm, pnpm, Yarn, Bun, or another package manager:
    node -e "console.log(process.env.PUPPETEER_SKIP_DOWNLOAD)"
    PUPPETEER_SKIP_DOWNLOAD=true npm ci
  3. Choose one browser owner. Either allow Puppeteer to download its compatible browser, or install Chrome/Chromium in the image or host and launch with its path.
  4. Keep build and runtime settings identical. If you customize the cache with PUPPETEER_CACHE_DIR, use the same path when installing and when launching. Changing the cache or download policy requires a reinstall so the install script sees the new values.

A variable set only when your application starts is too late; the install script has already run.

When package-manager policies block the browser step

Modern npm settings and package managers such as pnpm, Yarn Berry, Bun, and Deno can block dependency install scripts. In that situation, the JavaScript package may be present while Puppeteer’s browser is missing. This is different from a successful skip: the browser was not downloaded because the script never ran.

Check your CI or package-manager policy for disabled lifecycle scripts and allow Puppeteer’s install script where your security policy permits. If the package is already installed and you want Puppeteer to fetch its managed browser manually, run:

npx puppeteer browsers install

If you deliberately want no download, leave scripts disabled but install a compatible system browser and provide its executable path.

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

Launch with a browser you manage

For puppeteer with a system browser, or for puppeteer-core, pass executablePath:

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

(async () => {
  const browser = await puppeteer.launch({
    executablePath: process.env.CHROME_BIN || '/usr/bin/chromium',
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'networkidle2'});
  console.log(await page.title());
  await browser.close();
})();

Use the actual path in your operating system or container. The --no-sandbox flags are commonly required in restricted containers, but they reduce sandboxing; use them only when your deployment requires them and understand the security implications. A path that exists during image build but not at runtime produces a “cannot find Chrome” failure even though installation succeeded.

Docker and CI checklist

  • Set PUPPETEER_SKIP_DOWNLOAD=true in the Docker ENV or the same RUN instruction that executes npm ci.
  • Install Chrome or Chromium in the image when skipping Puppeteer’s download.
  • Set CHROME_BIN (or your own variable) to the runtime executable path.
  • Do not assume a browser installed in one CI job is available in another; persist the image layer or install it in each job.
  • Use one shared PUPPETEER_CACHE_DIR when relying on Puppeteer’s downloaded browser cache.
  • After changing environment variables, cache keys, or package-manager script policy, invalidate dependency caches and reinstall.

A minimal Docker pattern for a separately managed browser is:

FROM node:22-bookworm
# Install a compatible Chromium package using your distribution's package manager.
ENV PUPPETEER_SKIP_DOWNLOAD=true
ENV CHROME_BIN=/usr/bin/chromium
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "app.js"]

The exact browser package name and path vary by base image, so verify them inside the image with a command such as which chromium or which google-chrome.

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.

Configuration files for persistent settings

For project-wide settings, Puppeteer supports configuration files including .puppeteerrc.js, .puppeteerrc.cjs, .puppeteerrc.json, .puppeteerrc, puppeteer.config.js, and puppeteer.config.cjs. A CommonJS example:

/** @type {import('puppeteer').Configuration} */
module.exports = {
  skipDownload: true,
  cacheDirectory: process.env.PUPPETEER_CACHE_DIR || './.cache/puppeteer'
};

Use the environment variable in CI when you need deployment-specific behavior, and keep the checked-in configuration for stable project defaults. Remember that these files are ignored by puppeteer-core.

Diagnose the common errors

“Puppeteer still downloads Chrome”

The variable was probably set after installation, misspelled, visible only to a later process, or overridden by a different package-manager invocation. Print it immediately before npm install or npm ci, remove the existing modules and cache if necessary, then reinstall.

“Could not find Chrome” or “Could not find Chromium”

This means downloading was skipped or the install script was blocked, but no usable browser is available at runtime. Install a compatible browser, set executablePath, and verify the file exists inside the running container or host.

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

The package installs but no browser appears

Check lifecycle-script policy. A blocked postinstall can leave a successful package installation without a browser. Allow the script or run npx puppeteer browsers install for a Puppeteer-managed browser.

The browser exists but launches in one environment only

Compare build and runtime users, filesystem paths, permissions, architecture, and cache directories. A root-owned cache may be unreadable by the application user; a host path may not exist in a container.

The setting appears ignored

Confirm you are not importing puppeteer-core. Its configuration files and environment variables are intentionally ignored, and it never performs the automatic Chrome download provided by puppeteer.

Decide which setup fits your deployment

Requirement Recommended approach Trade-off
You want a compatible browser with minimal setup Use puppeteer and allow its install script Browser download increases install time and image size
Your organization supplies Chrome/Chromium Skip download and set executablePath You own browser patching and compatibility
You need a tightly controlled cache Set a shared PUPPETEER_CACHE_DIR Build and runtime must use the same path and permissions
You use a browser service or remote endpoint Use puppeteer-core and connect explicitly Connection, authentication, and browser availability are your responsibility
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is reliable website images rather than controlling Chromium yourself, ScreenshotNeo provides a single HTTP request for PNG, JPEG, WebP, or PDF output. 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. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status.

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

cURL:

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

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)

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

See the ScreenshotNeo documentation for all options. It includes full-page and CSS-selector captures, device and viewport presets, retina scale, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous webhooks, bulk capture for up to 100 URLs per call, usage reporting, and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

Every plan includes the features above: 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. Yearly billing provides two months free. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can I set PUPPETEER_SKIP_DOWNLOAD in a .env file?

Only if your installation command loads that file before the package manager starts. A runtime dotenv load does not affect an install script that has already finished.

Does skipping the download reduce Puppeteer’s npm package size?

It prevents the browser-download step; the JavaScript package remains installed. Image and cache size also depend on whether another browser is installed separately.

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

Should I use puppeteer or puppeteer-core in a Docker image?

Use puppeteer when you want Puppeteer to manage a compatible browser. Use puppeteer-core when the image or a remote service manages the browser and your code supplies the connection details.

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.