Fix PHP Browsershot Screenshots That Fail Because Chrome Is Not Found
Diagnose whether Browsershot cannot find Node, Puppeteer’s browser, or Chrome’s runtime dependencies, then fix it in the environment that runs PHP.
When PHP Browsershot reports that Chrome is not found, first determine whether Node can run, Puppeteer has a browser installed, and the PHP process can see that browser. Those are separate checks. A browser that exists may also fail to launch because of missing Linux libraries, permissions, or sandbox restrictions.
For Browsershot v4, Spatie documents Node 22.0 or newer and Puppeteer 23.0 or newer. Puppeteer normally downloads a compatible Chrome for Testing browser during installation, but package-manager settings can prevent that download. If Chrome is managed separately, configure its actual executable path. [Spatie Browsershot v4 requirements] [Puppeteer installation guide]
1. Identify which part is failing
Start with the full exception or subprocess output, not just the phrase “Chrome not found.” Browsershot launches Node, which uses Puppeteer to control a browser. Check each layer in order:
- Node/npm discovery: Can the PHP-launched process find the Node binary and the project dependencies?
- Browser installation and discovery: Did Puppeteer download Chrome, or is the configured Chrome path correct?
- Browser startup: Can Chrome run under the service account, with its required libraries and sandbox configuration?
“Could not find Chrome” or “Could not find expected browser” usually points to installation, cache, or path discovery. A spawn error such as ENOENT can mean that a configured executable path does not exist. “No usable sandbox!” or a missing shared-library message means Chrome was located but could not start; follow the startup checks below instead of reinstalling blindly.
2. Record versions and execution context
Check the Browsershot version in the application and compare it with the documentation for that major version. The requirements below are for v4; do not apply them automatically to another major version.
composer show spatie/browsershot
node --version
npm --version
npm ls puppeteer puppeteer-core
Run these checks in the deployment environment that will execute Browsershot. A result from a developer laptop or an interactive shell may not represent PHP-FPM, Apache, a queue worker, or a container. Record the service account, its home directory, environment variables, working directory, and browser cache location.
3. Choose how Chrome is installed
There are two common browser-management paths. Choose one deliberately and make sure the browser remains available to the PHP process after deployment.
| Approach | Use it when | Verify |
|---|---|---|
| Puppeteer-managed Chrome for Testing | The project uses puppeteer and installation scripts can download its browser. |
The install script ran, the browser cache is present in the deployed runtime, and the PHP service account can read and execute the browser. |
| Host- or container-managed Chrome/Chromium | The runtime owns the browser package, or the project uses puppeteer-core. |
The executable path is real in the runtime, permissions allow execution, and the browser works with the installed Puppeteer version. |
Puppeteer documents that puppeteer-core does not download a browser. It requires a separately managed browser and configuration. [Puppeteer installation guide]
4. Install Puppeteer’s browser when its download was skipped
Puppeteer’s browser download can be skipped by package-manager configuration or install-script settings. Installing the npm package alone does not prove that Chrome was downloaded. In the project and runtime environment that will execute the capture, install the browser with Puppeteer’s documented command:
npx puppeteer browsers install
Then confirm the browser cache is retained and readable by the PHP service account. If deployment builds dependencies in one stage and runs the application in another, make sure the browser download is included in the runtime image or installed there. Consult Puppeteer’s installation guide for its cache and configuration behavior. [Puppeteer installation guide]
5. Configure an externally managed Chrome path
If Chrome or Chromium is installed by the host or container, find its exact executable path inside that runtime, and pass it to Browsershot. Do not copy a path from another machine and assume it exists in production.
<?php
use Spatie\Browsershot\Browsershot;
Browsershot::url('https://example.com')
->setChromePath('/path/to/chrome')
->save('/tmp/page.png');
Replace the example path with the verified executable path. Spatie documents setChromePath for specifying the browser executable. [Spatie Browsershot v4 requirements]
6. Make Node and npm visible to PHP
If Node or npm works in your shell but Browsershot cannot find it, configure the binary locations and include path. Spatie provides setNodeBinary, setNpmBinary, and setIncludePath for this purpose.
<?php
use Spatie\Browsershot\Browsershot;
Browsershot::url('https://example.com')
->setNodeBinary('/path/to/node')
->setNpmBinary('/path/to/npm')
->setIncludePath('/path/to/bin')
->setChromePath('/path/to/chrome')
->save('/tmp/page.png');
Set only the values needed by the deployment. Use paths that exist and are executable inside the PHP runtime, not just in an administrator’s shell. Refer to Spatie’s documentation for the available process configuration methods. [Spatie Browsershot v4 requirements]
7. Diagnose Linux libraries and permissions
If the executable exists but Chrome exits immediately, inspect its dynamic library dependencies on the target host:
ldd /path/to/chrome | grep not
Output showing “not found” identifies missing shared libraries. Install the packages appropriate to the operating system and release used by the runtime image. Package names differ between distributions and versions; Spatie’s Ubuntu 24.04 example lists dependencies for that release and notes that Ubuntu 22.04 uses libasound2 instead of libasound2t64. Do not paste that package list into a different distribution without checking its package names. [Spatie Browsershot v4 requirements]
Also check that the service account can traverse the browser’s parent directories, execute the browser, and access any required cache and temporary directories. Compare its home and cache settings with those used during installation. If the command succeeds as your login user but fails through PHP, test as the actual worker or web-server account.
8. Handle sandbox errors safely
A “No usable sandbox!” error means Chrome started far enough to report a sandbox problem; it is not a missing-browser error. Check the host’s sandbox support and security policy. Puppeteer notes that AppArmor or user-namespace restrictions can affect Chrome for Testing on Ubuntu 23.10 and later. Follow its troubleshooting guidance for the host configuration. [Puppeteer troubleshooting guide]
Puppeteer strongly discourages running without a sandbox because it removes an important security boundary for browser content. Do not use --no-sandbox as a routine fix. Only consider disabling the sandbox when content is trusted and the deployment’s security implications are understood; prefer configuring a working sandbox. [Puppeteer troubleshooting guide]
9. Test in the same runtime as the application
After changing installation or configuration, run a minimal capture through the same PHP application process, service account, container image, environment, and cache used for real requests. Confirm the output file is created and is non-empty. If the app uses a queue, test from a queue worker too. This catches differences that a successful local terminal run cannot establish.
If you use a remote Chrome instance intentionally, Browsershot documents remote browser configuration. That architecture can suit a deployment designed around a browser service, but it is not the first remedy for a local executable that was simply never installed. [Spatie Browsershot v4 requirements]
10. Common errors and fixes
| Symptom | Likely cause | What to do |
|---|---|---|
| “Could not find Chrome” / “Could not find expected browser” | Puppeteer’s browser was not downloaded, its cache is missing, or the runtime cannot see it. | Run npx puppeteer browsers install in the deployment environment; retain and expose the cache to the PHP account. |
ENOENT while spawning a process |
A configured Node, npm, or Chrome path is invalid or invisible in the runtime. | Verify the exact executable path and configure the relevant Browsershot binary method. |
| Works in terminal but fails through PHP | Different service account, PATH, home/cache, permissions, environment, or container filesystem. | Inspect and test as the PHP-FPM, Apache, or queue-worker identity in the deployed runtime. |
| Chrome executable exists but exits on launch | Missing shared libraries, permissions, or another host runtime dependency. | Check ldd /path/to/chrome | grep not, install release-appropriate dependencies, and verify access permissions. |
| “No usable sandbox!” | Host sandbox configuration or policy prevents Chrome from starting securely. | Follow Puppeteer’s sandbox troubleshooting guidance; avoid disabling the sandbox as a default workaround. |
Using puppeteer-core with no configured browser |
puppeteer-core does not download Chrome. |
Install/manage Chrome separately and configure its path. |
11. Performance, reliability, and operating cost
Browser installation is part of deployment reliability: a successful dependency install is insufficient if the browser download was skipped or the runtime image omits the browser cache. Keep the browser and Puppeteer versions compatible, make the executable and cache visible to the same service identity, and include required libraries in the runtime image. These checks reduce environment-specific failures; they do not guarantee that every target website will render successfully.
Chrome downloads and Linux dependencies add deployment size and setup work. Puppeteer publishes approximate browser download sizes in its installation documentation; use its current figures when estimating image storage or build time. [Puppeteer installation guide] If browser deployment and maintenance are not a fit for the workload, a hosted screenshot API can remove the need to install and launch Chrome in your PHP environment.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request captures a URL without requiring your PHP runtime to install or locate Chrome. The API supports PNG, JPEG, WebP, and PDF; see the ScreenshotNeo API documentation for parameters and 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 Bun.write('shot.webp', res);
ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, inspect page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Does installing Browsershot install Chrome too?
Do not assume so. Puppeteer normally downloads Chrome during installation, but install-script settings can skip the download. Verify the browser exists in the runtime.
Why does a queue worker fail when a web request succeeds?
They may run as different users or in different environments, with separate PATH settings, home directories, browser caches, or filesystem permissions. Check the process that actually runs the capture.
Can I use Chromium instead of Chrome?
An independently managed Chrome or Chromium executable can be configured with setChromePath. Confirm the path, runtime dependencies, and compatibility with the Puppeteer version in use.
Should I switch to a remote browser?
Use a remote browser when your deployment is intentionally designed around a browser service. For a local “not found” failure, first confirm installation, path discovery, runtime identity, and launch dependencies.


