October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
browser automation

How to Fix Puppeteer on Ubuntu When It Works on Windows

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

When Puppeteer works on Windows but fails on Ubuntu, the JavaScript is usually not the useful place to start. Ubuntu may be missing Linux shared libraries, the browser binary may not exist or may be a different version, or Chrome may be blocked by the Linux sandbox or AppArmor. Capture the complete launch error and environment first, then follow the matching branch below. The title alone does not identify one universal cause.

Puppeteer’s current system-requirements page (identified as Puppeteer 25.12.0 when checked) lists Node.js 22.12 or later and Chrome for Testing support on Debian/Ubuntu for x64 and arm64. Linux still requires the operating-system packages needed by Chrome. See the official system requirements for the release you have installed.

1. Record the Ubuntu environment and the full error

Do this before changing flags or reinstalling packages. A complete launch trace distinguishes a missing library from a missing executable and from a security-policy failure.

node --version
npm ls puppeteer puppeteer-core
cat /etc/os-release
uname -m
npx puppeteer browsers list
DEBUG=puppeteer:* node app.js 2>&1 | tee puppeteer-launch.log

Also record whether the process runs directly on Ubuntu, inside Docker or another container, or under WSL. Note the browser source (Puppeteer’s download, Google Chrome, Chromium, or an image-provided binary), the configured executable path, and the complete error including its first and last lines. The system-requirements and troubleshooting documentation describe categories of failure, not the cause on your particular host.

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

2. Check for missing Linux shared libraries

Windows DLLs do not tell you whether the Linux Chrome binary can start. Find the exact executable that Puppeteer is launching. The browser list command, launch logging, or your configured executablePath can reveal it. Then run:

ldd /absolute/path/to/chrome | grep not

If output appears, those are unresolved shared libraries. Install the Ubuntu packages that provide them, then run the command again until it returns no missing entries. Puppeteer’s troubleshooting guide lists common Debian/Ubuntu dependencies covering NSS, GTK, GBM, X11, fonts, audio, and related components. Package names vary with Ubuntu release and image, so use the guide together with the actual ldd output rather than copying an old universal package list.

Let Puppeteer request dependencies when policy permits

The browsers CLI documents an option that attempts to install Chrome and its system dependencies on Debian or Ubuntu:

npx puppeteer browsers install chrome --install-deps

This requires root privileges and package installation access. Inspect the command and confirm it complies with your container, CI, or server change policy before running it. In a minimal image, you may need to install packages in the image build instead of at runtime.

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

3. Confirm that a browser exists and that Puppeteer is using it

Know which package you installed

Package Browser behavior What to verify on Ubuntu
puppeteer Normally downloads a compatible Chrome for Testing during installation. Check that the download completed, the cache is present, and the launch path points to that browser.
puppeteer-core Does not download a browser; your application manages one. Provide a valid browser executable and verify its compatibility and Linux dependencies.

The distinction is documented in Puppeteer’s installation guide. A package-manager configuration that blocks install scripts can leave a normal puppeteer install without its downloaded browser. Check your npm, pnpm, or Yarn policy and the install log instead of assuming the cache is populated.

Inspect and set the executable path

If you intentionally use system Chrome or Chromium, make the path explicit and verify that it is the binary you inspected:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined
  });
  const page = await browser.newPage();
  await page.goto('https://example.com', {waitUntil: 'domcontentloaded'});
  console.log(await page.title());
  await browser.close();
})();

Use an absolute path when setting PUPPETEER_EXECUTABLE_PATH, and confirm its permissions and architecture. The configuration interface documents executable-path and cache settings. Puppeteer guarantees compatibility with its bundled browser; a separately managed Chrome or Chromium requires you to validate the pairing, as described in the LaunchOptions documentation.

Prefer one browser source per deployment

Do not silently mix a Puppeteer-downloaded Chrome for Testing with a system browser selected by an environment variable. Choose one source, log its path at startup, and keep the Node, Puppeteer, and browser versions together in your deployment definition. If you upgrade only one of them, repeat the launch and dependency checks.

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

4. Separate sandbox failures from dependency failures

Errors such as No usable sandbox! indicate a security configuration problem, not merely a missing GTK package. On Ubuntu 23.10 and later, Puppeteer’s troubleshooting documentation describes an AppArmor interaction: a profile applied to stable Chrome at /opt/google/chrome/chrome can prevent Puppeteer-downloaded Chrome for Testing from using user namespaces.

Follow the upstream AppArmor workaround linked from the Puppeteer troubleshooting page for your Ubuntu release and the browser path actually in use. The profile and path matter; a workaround for stable Chrome may not match a Chrome for Testing binary.

Do not make --no-sandbox your routine fix. Puppeteer’s documentation states: “Running without a sandbox is strongly discouraged.” It discusses disabling the sandbox only for content you absolutely trust. A working user-namespace and AppArmor configuration is the safer resolution. If policy forces a disabled sandbox in an isolated environment, document that exception, restrict the content, and treat it as a deliberate security trade-off rather than a compatibility setting.

5. Account for containers, WSL, and service users

An interactive Ubuntu desktop and a production container are different runtimes. In a container, the image may omit fonts, shared libraries, or user-namespace permissions even when the host has them. In WSL, verify which Linux distribution and architecture actually run Node and Chrome. Under systemd, a service user may have a different home directory, cache, permissions, and AppArmor profile than your shell account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Run the diagnostic commands as the same user that launches Puppeteer.
  • Check that the browser file is executable and that its parent directories are traversable.
  • Make the Puppeteer cache location explicit when the service user cannot see a developer’s home directory.
  • Build required OS packages into the image or VM, then run ldd inside that exact runtime.
  • Record architecture separately from the host; an arm64 container on an x64 machine still needs an arm64-compatible browser.

6. Use a minimal launch to isolate application code

Once the binary and libraries are known, reduce the test to a launch, one page, and a close. This removes your application’s proxy, extensions, navigation hooks, and business logic from the diagnosis.

const puppeteer = require('puppeteer');

(async function () {
  let browser;
  try {
    browser = await puppeteer.launch({headless: true});
    const page = await browser.newPage();
    await page.goto('https://example.com', {waitUntil: 'load', timeout: 30000});
    console.log({title: await page.title(), url: page.url()});
  } catch (error) {
    console.error(error.stack || error);
    process.exitCode = 1;
  } finally {
    if (browser) await browser.close();
  }
}());

If this succeeds but your application fails, reintroduce its launch options one at a time. If it fails before a page is created, stay on the dependency, executable, compatibility, or sandbox branches above.

7. Common symptoms and the corresponding fix

Symptom Likely branch Next action
error while loading shared libraries Linux package dependency Run ldd on the launched Chrome and install the package providing each missing library.
ENOENT, “Browser was not found,” or a path that does not exist Browser download or path Check whether you use puppeteer or puppeteer-core, inspect the browser cache, and correct executablePath or PUPPETEER_EXECUTABLE_PATH.
Chrome starts but immediately exits with a version or protocol error Browser/Puppeteer mismatch Use the bundled Chrome for Testing or validate the separately managed browser against your installed Puppeteer release.
No usable sandbox! or user-namespace errors Sandbox/AppArmor Check Ubuntu version, browser path, user namespaces, and the documented AppArmor workaround; avoid routinely adding --no-sandbox.
Works in a shell but not as a service Runtime user, cache, or policy Run diagnostics as the service user and compare its environment, permissions, cache path, and security profile with the interactive shell.
Works on x64 but fails in an arm64 image Architecture or image contents Confirm uname -m, the browser architecture, and arm64-compatible packages in the actual image.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

8. Version, reliability, and operating-cost considerations

The system-requirements page currently calls for Node.js 22.12 or later and documents Debian/Ubuntu Chrome for Testing on x64 and arm64. Those are documentation facts at that page’s revision, not proof that your project meets them. The installation and troubleshooting pages are labeled “Next”; use documentation matching your installed Puppeteer release when an option or platform behavior differs.

For repeatable deployments, pin Node and Puppeteer in the project, choose whether the browser is bundled or image-managed, and record the resulting executable path in startup logs. Reuse a browser process for multiple pages when your workload allows it rather than launching a new process for every URL; this reduces repeated startup work, while separate browser processes can provide stronger isolation. Set explicit navigation and operation timeouts, collect stderr, and close pages and browsers in error paths so a failed navigation does not leave orphaned processes.

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

There is no single Ubuntu fix or success rate established by the available documentation. Your Ubuntu release, CPU architecture, runtime, browser source, and full error determine the correct branch.

Or skip the browser setup

If your goal is a clean website image rather than maintaining Chrome on an Ubuntu host, ScreenshotNeo is a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; 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 identifies the result with X-Page-Verdict and X-Billed headers.

One GET request is enough. The full API documentation is at screenshotneo.com/docs/.

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

ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. It supports full-page and element captures, device and viewport settings, retina scale, PDF paper and page options, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Existing parameter names used by other screenshot APIs are accepted to ease migration.

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.
Plan Allowance and price
Free 1,000 shots per month, no card
Starter $5 for 3,000 shots
Growth $15 for 15,000 shots
Pro $39 for 60,000 shots
Scale $99 for 250,000 shots
Business $249 for 1,000,000 shots

Every feature is on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Frequently Asked Questions

What does an empty result from ldd ... | grep not prove?

It means that particular executable has no unresolved libraries reported by ldd. It does not prove that Puppeteer selected that executable, that the browser versions match, or that Ubuntu security policy will permit startup.

Do I need a graphical desktop session for headless Chrome?

No desktop window is required for headless operation, but headless Chrome still needs its Linux libraries, fonts, executable permissions, and permitted sandbox or namespace configuration.

Which Puppeteer documentation should I follow when pages disagree?

Start with the documentation version matching your installed package. The installation and troubleshooting links used here are labeled Next, while the API pages are versioned interfaces; flags and platform behavior can change between releases.

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.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.