Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
Browsershot

How to Fix “Puppeteer Not Found” in a Laravel PDF Application

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

“Puppeteer not found” is a symptom, not a single Laravel error. A PDF request can fail because PHP cannot start Node.js, Node cannot resolve the project’s Puppeteer package, Puppeteer cannot find Chrome, or a configured executable, profile, cache, or temporary directory is wrong. Trace the complete command and standard error, then repair the first broken link in that chain.

This guide covers Laravel PDF integrations that use Spatie Browsershot, including spatie/laravel-pdf. The exact configuration names vary by installed release, so identify your package versions before copying version-specific settings.

Understand what “Puppeteer not found” can mean

Spatie’s Laravel PDF integration uses Browsershot, and Browsershot runs Puppeteer in a headless Chrome process. That creates several independent requirements:

  • Laravel’s PHP process must be able to execute Node.js.
  • That Node process must resolve the JavaScript package in the runtime’s project or module path.
  • Puppeteer must have a compatible browser available, either downloaded automatically or managed through an explicit path.
  • The browser must be able to create a profile and temporary files with the permissions and paths available on the deployment host.

Installing one component does not prove that the other three are reachable. A global npm install, for example, may not satisfy a project-local module lookup, and a browser downloaded during a build may be absent from the production image or the runtime user’s home directory.

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

1. Identify your Laravel PDF and Browsershot versions

Start with the packages Composer actually installed, not a blog post written for another release:

composer show spatie/laravel-pdf spatie/browsershot

If one package is not installed, Composer will report it. Check whether your application calls spatie/laravel-pdf directly, uses Browsershot itself, or relies on another PDF engine. Then open the documentation for that installed release. The Spatie Laravel PDF v1 documentation, for example, lists PHP 8.2+ and Laravel 10+ requirements; those requirements must not be treated as universal for every future or older release.

Also record whether PDF generation runs during a web request, queue worker, scheduler, Octane worker, or a container entrypoint. Each can have a different user, working directory, PATH, home directory, and filesystem.

2. Capture the real failing command and stderr

The short Laravel exception often hides the useful diagnosis. Log the complete exception chain and look for the command, working directory, exit code, standard output, and standard error. A message such as node: command not found points to a different repair than Cannot find module 'puppeteer' or Could not find Chrome.

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

Run checks as the same operating-system account and in the same execution context as PHP-FPM or the queue worker. An interactive SSH shell may find Node through a shell profile that services never load.

whoami
pwd
echo "$PATH"
command -v node
node --version
npm --version

For a queue, run the command under the worker’s service account or temporarily add equivalent diagnostics to a job. In a container, execute them inside the final runtime image rather than only in a build stage.

3. Fix Node.js discovery first

When Node cannot start

If the captured stderr says that node is not recognized or cannot be executed, Puppeteer has not run yet. Install a supported Node.js runtime in the environment that serves the Laravel process, then configure the Node binary using the option supported by your installed Browsershot version and deployment setup.

Do not confuse a Node binary setting with a Puppeteer package setting. Pointing Browsershot at /usr/bin/node (or the actual path on your host) only tells PHP how to launch Node; it does not install JavaScript dependencies or Chrome.

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

Why the shell works but Laravel fails

Node installed through a version manager is commonly added to an interactive shell’s PATH but not to PHP-FPM, Supervisor, systemd, cron, or a queue worker. Use an absolute executable path where your integration permits it, or define PATH explicitly in the service configuration. Restart the relevant worker or PHP service after changing its environment; long-lived workers retain their original environment.

4. Make sure Puppeteer is installed in the runtime context

Use a project dependency

Puppeteer’s standard installation is:

npm install puppeteer

Run it in the JavaScript project directory that Browsershot expects, and deploy its lockfile and installed dependency to the same runtime image or host. A globally installed package should not be assumed to satisfy a project or package-local module resolution. A single Windows community report where a global install did not solve the error is anecdotal, but it illustrates the underlying rule: verify the exact module path used by the failing process.

Know the difference between puppeteer and puppeteer-core

puppeteer normally downloads a compatible browser during installation. puppeteer-core is a library for driving an existing DevTools-compatible browser and does not download Chrome. If your application uses puppeteer-core, you must provide and maintain the browser yourself and configure its executable path or launch settings as required by your integration.

Check the dependency from the project directory:

npm list puppeteer puppeteer-core

If npm reports an empty tree or an unexpected version, fix the dependency and redeploy rather than adding another global package.

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

5. Verify Chrome and the Puppeteer cache

With a normal puppeteer installation, Puppeteer downloads Chrome for Testing and chrome-headless-shell. Since Puppeteer v19, the documented default cache is $HOME/.cache/puppeteer. That location belongs to a user and filesystem, so it is easy to lose between build and runtime stages.

Install the browser explicitly

If install scripts were disabled by npm policy, a package manager, or a production-only install, run the official recovery command in the environment that will launch the browser:

npx puppeteer browsers install

Run it as the same account used by PHP-FPM or the worker, or configure a shared cache that the runtime can read. Confirm that the resulting browser files are present in the final deployment image. Installing under root in a build stage does not establish that an unprivileged runtime user has a browser in its own home directory.

When you changed the cache directory

Puppeteer supports changing its cache directory through configuration. After changing download options or the cache location, run the browser installation command again and verify the configured directory in the deployed environment. Keep the cache outside ephemeral storage if containers are recreated without rebuilding dependencies, or bake the browser into the image.

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.

6. Check executablePath, profile, and temporary directories

Validate an explicit executable path

If your configuration sets executablePath, verify that it names the browser executable itself and exists on the host where Node runs. A path from a laptop, another container stage, or a different operating system will fail in production. If you intend to use Puppeteer’s downloaded browser, remove a stale override and let the installed version resolve its default.

Do not supply a directory when the integration expects a file. Check permissions as the runtime user, not only as root.

Investigate profile and temp failures separately

Errors mentioning mkdtemp, an undefined temporary path, profile creation, or “permission denied” are not module-resolution errors. Confirm that the process has a valid temporary-directory environment and write permission. On Linux, inspect the service’s TMPDIR and the system temporary directory. On Windows, verify that the account has access to the resolved temporary location. A reported Windows failure creating a Puppeteer profile beneath an undefined temp path is a machine-specific example, not a universal fix; use the path shown in your own stderr.

7. A practical diagnosis sequence

  1. Save the full Laravel exception, including stderr and the command that failed.
  2. Identify installed spatie/laravel-pdf, Browsershot, Laravel, PHP, Node, and Puppeteer versions.
  3. As the web or worker user, confirm command -v node and node --version.
  4. From the expected JavaScript project directory, run npm list puppeteer puppeteer-core.
  5. Determine whether the project uses puppeteer (automatic browser download) or puppeteer-core (operator-managed browser).
  6. Run npx puppeteer browsers install in the final runtime environment when the browser is missing.
  7. Check the browser cache, configured executablePath, temporary directory, and permissions as the runtime account.
  8. Restart PHP-FPM, queue workers, Supervisor processes, or containers so they receive the corrected environment.

Common errors and targeted fixes

Observed message or symptom Likely boundary Action
node is not recognized or command not found PHP cannot launch Node Install Node in the runtime image and configure the supported Node binary/PATH for the service user.
Cannot find module 'puppeteer' JavaScript dependency is absent from the resolved project Install puppeteer locally, deploy the dependency and lockfile, and test from the same working directory.
Chrome executable missing Browser was not downloaded or cache is unavailable Run npx puppeteer browsers install in the final runtime and verify cache ownership and contents.
Works locally, fails in production Different PATH, user, home, image stage, or filesystem Repeat every check inside production’s actual PHP/worker context; avoid laptop-only paths.
mkdtemp, profile, or permission denied Temporary directory or profile creation Set a valid writable temp location and correct ownership; use the path named in stderr.
Browser starts but pages fail to render Launch flags, sandbox, network, or page-level issue First resolve the missing-component error, then inspect the complete browser stderr and page logs. Do not mask the original failure with unrelated flags.

Performance, reliability, and deployment notes

  • Browser downloads are large and platform-specific. Puppeteer documents approximate download sizes of about 170 MB on macOS, 282 MB on Linux, and 280 MB on Windows; treat these as package-download context, not a Laravel performance guarantee.
  • Cache the browser in your image or a persistent cache appropriate to your deployment, but ensure the runtime account can read and execute it.
  • Build and runtime stages must agree on architecture, operating system, cache path, and user home directory.
  • Queue workers and application servers should be restarted after Node, PATH, cache, or executable-path changes.
  • Do not apply a configuration snippet from a different Browsershot release without checking that release’s API and requirements.
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 simply to turn a URL into an image or PDF rather than maintain Chrome inside Laravel, ScreenshotNeo provides a website screenshot API and MCP server. Its clean-shot pipeline accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

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

One GET request is enough:

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

See the ScreenshotNeo API documentation for all options. The same endpoint supports PNG, JPEG, WebP, and PDF output, full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper settings and page ranges, custom CSS and JavaScript, clicks, selector waits, delays, network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const body = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', body));

ScreenshotNeo also offers take_screenshot, get_page_info, and capture_pdf through an MCP server for Claude, Cursor, and other MCP clients. Pricing includes 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account to get started.

When changing PDF engines makes sense

Switching engines is a project decision, not a fix for an undiscovered PATH or cache problem. Compare the CSS and JavaScript fidelity your documents require, whether the hosting environment permits the required runtime dependencies, and whether the specific Laravel integration and version remain supported. Older headless-CLI and PhantomJS approaches appear in historical Browsershot discussions; PhantomJS is abandoned, and an alternative may not preserve your project’s styling or browser behavior.

Frequently Asked Questions

Does installing Puppeteer globally fix Laravel’s error?

Not reliably. Browsershot may resolve modules from a project-specific context, so install and verify Puppeteer where the failing Node process expects it.

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.

Why does Puppeteer work for my user but not for PHP-FPM?

PHP-FPM can have a different PATH, user, home directory, cache, and working directory. Repeat the Node, package, browser, and permission checks as the PHP-FPM account.

Should I use puppeteer or puppeteer-core?

Use puppeteer when you want Puppeteer’s normal browser download behavior. Use puppeteer-core only when you intentionally manage a compatible browser and configure its executable and lifecycle yourself.

Is there one universal Laravel fix?

No. The correct repair depends on whether Node, the JavaScript package, Chrome, or the filesystem boundary is failing. The complete command and stderr identify the branch.

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.

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

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
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

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.