ScreenshotNeo

BlogHow-to

Puppeteer screenshot in Node.js on Windows: fix Chrome launch errors

Fix Puppeteer Chrome launch errors on Windows by checking browser installation, executable paths, extension policies, and sandbox permissions.

By the ScreenshotNeo team4 October 20269 min read

If Puppeteer fails before it can capture a screenshot on Windows, first identify whether Chrome is missing, the configured executable path is wrong, a managed Chrome policy requires extensions, or Windows denied the downloaded browser access. Each cause has a different fix. Install Puppeteer’s browser if it is missing, correct the executable selection if you manage Chrome yourself, use enableExtensions: true for the documented extension-policy conflict, and repair file permissions for the documented sandbox access-denied error. Avoid adding launch flags before you know which failure you have.

This guide follows the official [Puppeteer installation guide](https://pptr.dev/guides/installation), [Windows troubleshooting guide](https://pptr.dev/troubleshooting), [system requirements](https://pptr.dev/guides/system-requirements), [screenshot guide](https://pptr.dev/guides/screenshots), and [launch options reference](https://pptr.dev/api/puppeteer.launchoptions). Documentation details can change between releases; check the version your project uses.

1. Check whether Puppeteer installed its browser

The regular puppeteer package downloads a compatible Chrome for Testing browser during installation. Since Puppeteer 21.6.0, it also downloads a separate chrome-headless-shell binary. If your package manager blocks dependency install scripts, the package may be present while the browser download is absent. A common symptom is Could not find Chrome (ver. ...).

From the project directory, run the documented browser installation command:

npx puppeteer browsers install

Then retry the script. If your package manager suppresses install scripts by policy, allow Puppeteer’s install script according to that package manager’s configuration, or run the browser installation command explicitly as part of setup. Do not assume a launch flag can fix a browser binary that was never downloaded.

Puppeteer’s default browser cache location changed to ~/.cache/puppeteer beginning with v19.0.0. Check the configured cache and the browser installation output if you need to confirm where the binary was placed. The documented Windows Chrome for Testing download is approximately 280 MB, so a slow or interrupted install can also leave the browser unavailable.

2. Confirm Node.js and Windows prerequisites

The Puppeteer 25.12.0 system requirements list Node.js 22.12 or later and Chrome for Testing on Windows x64. That version’s Windows unpacking requirement is tar.exe or PowerShell, unless the optional yauzl dependency is installed. These are version-specific documentation requirements; check the requirements for the Puppeteer release in your lockfile.

  • Confirm the Node version used by the shell or service that runs the script: node --version.
  • Confirm that the install command completed and that the browser cache contains the expected Puppeteer browser.
  • If install output shows an extraction error, verify that tar.exe or PowerShell is available, or use the documented optional yauzl route.
  • Check whether a CI runner, Windows service, or scheduled task runs under a different account. Its home directory and Puppeteer cache can differ from your interactive login.

3. Choose how Puppeteer finds Chrome

Use puppeteer when you want Puppeteer to download and manage its compatible browser. Use puppeteer-core when you manage the browser yourself or connect to a remote browser. puppeteer-core does not download Chrome at installation, so you must supply a supported browser channel or an explicit executable path.

Setup Use it when Launch setting
puppeteer bundled browser You want Puppeteer to install a compatible browser. puppeteer.launch()
Installed Chrome channel You intentionally use a regular Chrome installation. puppeteer.launch({ channel: 'chrome' })
Managed browser binary Your deployment pins or provisions a particular executable. puppeteer.launch({ executablePath: 'C:\\path\\to\\chrome.exe' })

Puppeteer guarantees operation with its bundled browser. A separately managed Chrome version gives you control over installation, but can introduce compatibility problems when it differs from the version Puppeteer expects. On Windows, verify the actual path under the same account that runs Node.js. In JavaScript string literals, escape backslashes as \\ or use forward slashes in the path.

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

async function main() {
  const browser = await puppeteer.launch({
    executablePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
    headless: true,
  });

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

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Replace the example path with the Chrome executable actually installed on the target machine. If you use the regular puppeteer package, omit executablePath unless you intentionally want to override its bundled browser.

4. Fix Windows extension-policy launch failures

Puppeteer passes --disable-extensions by default. Some Windows Chrome policies require extensions, and that policy conflict can prevent Chrome from launching. For this specific documented case, enable extensions in Puppeteer’s launch options:

const browser = await puppeteer.launch({
  enableExtensions: true,
});

Use this setting when the managed Chrome policy is the cause. It is not a general fix for missing executables, invalid paths, permission errors, or timeouts.

5. Fix the documented Windows sandbox access-denied error

A Windows sandbox failure may include a message like Sandbox cannot access executable. Check filesystem permissions are valid ... Access is denied. (0x5). Puppeteer v22.14.0 and later attempts to configure permissions for downloaded Chrome by running Chrome’s setup.exe during browser installation.

  1. Check your Puppeteer version and reinstall the managed browser with npx puppeteer browsers install.
  2. If you use an older release, or access is still denied, follow the documented permission workaround from an appropriate Windows command prompt:
icacls "%USERPROFILE%/.cache/puppeteer/chrome" /grant *S-1-15-2-1:(OI)(CI)(RX)

This grants read and execute access to the downloaded Chrome files for the specified SID. In high-security environments, the Puppeteer troubleshooting guide notes that a more restrictive SID may be preferable. Confirm the cache path for the account running Puppeteer before applying the command; a custom cache location needs the corresponding path.

Do not treat disabling Chrome’s sandbox as the default Windows permission fix. The documented Windows remedy addresses access to downloaded Chrome files. Follow your organization’s browser security policy if it requires a different controlled configuration.

6. Diagnose headless behavior and startup timeouts

Current Puppeteer documentation uses regular headless Chrome by default. You can also run visible Chrome with headless: false while diagnosing, or use headless: 'shell' to select the separate headless shell. The shell may be faster for automation, but does not completely match regular Chrome behavior. If a page or feature behaves differently in the shell, compare against regular headless Chrome or visible Chrome.

Set dumpio: true to pipe browser stdout and stderr to Node’s output. The documented default startup timeout is 30 seconds; timeout controls the launch wait. Increase it only when the browser is installed and starting slowly, rather than using a longer timeout to hide a missing binary or access-denied error.

const browser = await puppeteer.launch({
  dumpio: true,
  headless: false, // temporary diagnostic mode
  timeout: 60_000, // only if startup is slow after other checks
});

Visible mode can make policy dialogs or startup behavior easier to observe, but it requires a usable desktop session. A Windows service or headless CI worker may not have one. Return to the mode appropriate for deployment after diagnosis.

7. Complete screenshot example after Chrome launches

Once launch succeeds, use page.goto() to load the target and page.screenshot() to save the image. The finally block ensures the browser is closed if navigation or capture throws.

const puppeteer = require('puppeteer');

async function main() {
  const browser = await puppeteer.launch({
    headless: true,
  });

  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1440, height: 1000, deviceScaleFactor: 1 });
    await page.goto('https://example.com', {
      waitUntil: 'networkidle2',
      timeout: 45_000,
    });
    await page.screenshot({ path: 'screenshot.png', fullPage: true });
  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error('Screenshot failed:', error);
  process.exitCode = 1;
});

The navigation timeout above controls page loading; it is separate from Chrome’s launch timeout. For pages with persistent network connections, networkidle2 may not be the right readiness condition. Use a page-specific selector wait when you know which element marks the content as ready. For a specific element, find its handle and call elementHandle.screenshot(); the Puppeteer screenshot guide documents that alternative.

8. Troubleshooting by symptom

Symptom Likely cause Fix
Could not find Chrome (ver. ...) Install script was blocked, install was incomplete, or the running account uses a different cache. Run npx puppeteer browsers install; check package install-script policy and the cache for the runtime account.
Chrome path does not exist or executable cannot be spawned Wrong executablePath, or puppeteer-core is used without a browser path/channel. Correct the executable path or set a supported channel; alternatively use puppeteer and its bundled browser.
Policy-related launch error on managed Windows Chrome Organization policy enforces extensions while Puppeteer disables them by default. Try enableExtensions: true when that policy conflict applies.
Sandbox cannot access executable / Access is denied (0x5) Downloaded Chrome files lack permissions needed by the Windows sandbox. On v22.14.0+, reinstall/check automatic setup; for older versions or persistent failure, apply the documented icacls grant to the correct cache path.
Launch times out Browser startup is slow, blocked, or unable to initialize. Enable dumpio, inspect the browser output, and check path, permissions, policy, and runtime before raising timeout.
Screenshot differs in shell mode chrome-headless-shell does not fully match regular Chrome behavior. Compare with headless: true or headless: false, depending on the feature under investigation.
Browser works locally but not in CI/service The process runs as a different Windows user or without an interactive desktop. Check that account’s Node version, browser cache, executable permissions, and whether visible mode is supported.
Navigation hangs after successful launch The page never reaches the chosen network-idle condition, often due to ongoing requests. Use an appropriate navigation condition or wait for a page-specific selector; handle navigation timeout separately from launch timeout.

9. Performance, reliability, and cost considerations

  • Installation size and cold setup: Chrome for Testing’s Windows download is approximately 280 MB in the cited Puppeteer documentation. Provision it during image or environment setup instead of repeatedly downloading it at runtime.
  • Startup diagnostics: Browser startup has a documented 30-second default timeout. Collect dumpio output before changing the timeout so slow startup can be distinguished from a broken launch.
  • Headless choice: The separate shell can be more performant for automation tasks that do not need the full Chrome feature set, but compare output when browser behavior matters.
  • Reproducibility: The bundled browser is the compatibility path Puppeteer guarantees. If you pin a separately managed Chrome, keep its version and path consistent across developer machines and deployment environments.
  • Resource cleanup: Close the browser in a finally block. A process left running after a failed navigation consumes machine resources and can make later runs less reliable.
  • Cost: Puppeteer and Chrome are software components; the practical operating costs are browser downloads, machine resources, and maintenance of the Windows runtime. The cited research provides no benchmark or fixed infrastructure cost.

10. Or skip the browser setup

If you need a screenshot without installing and maintaining Chrome on the Windows machine, [ScreenshotNeo](https://screenshotneo.com) provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. See the [ScreenshotNeo API documentation](https://screenshotneo.com/docs/) for request options.

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 require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
  • Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

FAQ

Does puppeteer-core install Chrome?

No. It is intended for a browser you manage yourself or a remote browser connection. Provide a supported browser channel or executable path.

Should I always set --no-sandbox on Windows?

No. The documented Windows access-denied fix is to check Puppeteer’s browser setup and downloaded-file permissions. Diagnose the specific error before changing sandbox behavior.

Can I take a screenshot of only one element?

Yes. Use the element handle’s screenshot() method after locating the element on the page.

Why does Chrome work in a terminal but fail in a Windows service?

The service may run as another account with a different cache, permissions, or environment. Check the browser and Node setup under the service’s actual identity.