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

If Laravel reports “Puppeteer not found” while creating a PDF, do not assume the npm package is missing. The message can mean that PHP cannot start Node.js, Node cannot resolve the package, Puppeteer cannot find Chrome, or the browser cannot create its profile or temporary files. Capture the complete command, exit code, standard output, and standard error, then identify which layer failed.

This guide follows the execution chain used by Spatie Laravel PDF and Browsershot: Laravel/PHP → Node.js → Puppeteer → Chrome → temporary profile and output file. Check the versions installed in your application before copying version-specific settings.

Understand what “Puppeteer not found” can mean

Spatie’s Laravel PDF package uses Browsershot under the hood, and Browsershot uses Puppeteer with headless Chrome to render HTML as a PDF or image. A failure reported at the Laravel layer may therefore hide a lower-level error.

Layer What must be available Typical symptom
Laravel/PHP The package, configuration, and the same environment used by the request or queue worker A generic exception with a command and non-zero exit code
Node.js An executable visible to PHP-FPM, the queue worker, scheduler, container, or service account node is not recognized, command not found, or process cannot start
JavaScript dependency puppeteer (or deliberately managed puppeteer-core) in the runtime’s module-resolution path Cannot find module, missing package, or a global install that has no effect
Browser Chrome for Testing, chrome-headless-shell, or a manually managed executable Browser executable missing, launch failure, or an invalid executablePath
Filesystem A writable temporary/profile directory and access to the browser cache mkdtemp, permission denied, blank output, or profile creation errors

The short message is not enough to choose a fix. Keep the underlying stderr with the incident or log entry.

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

1. Identify your Laravel PDF and Browsershot versions

First inspect the installed Composer packages rather than relying on a blog post written for another release:

composer show spatie/laravel-pdf spatie/browsershot

If one package is not installed, Composer will report that explicitly. Also inspect your application’s package manifest and lock file:

grep -n 'spatie/laravel-pdf|spatie/browsershot' composer.json composer.lock

Spatie’s Laravel PDF v1 documentation lists PHP 8.2+ and Laravel 10+ as requirements for that version. Do not apply those requirements to every future or older release; use the documentation matching the version Composer installed.

Confirm which integration actually generates the PDF. A project may call SpatieLaravelPdfPdf, instantiate Browsershot directly, or use another renderer entirely. The repair must target the command that is failing.

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

2. Capture the complete failing command

Run the same code path that fails and record:

  • the full command line Laravel or Browsershot attempted to execute;
  • the working directory;
  • the operating-system user;
  • the exit code;
  • all standard output and standard error;
  • the Node and package versions visible to that process.

Do not test only in your interactive terminal. A shell may have a PATH entry that PHP-FPM, a systemd service, a scheduler, a queue worker, or a container does not inherit. A reported Windows case in which node was not recognized is anecdotal, but it illustrates why the execution context matters.

3. Verify Node.js from Laravel’s execution context

Run these checks as the account that launches the PDF job. On a server, that may be the web-server user or a queue account rather than your login:

node --version
command -v node   # Linux and macOS
where node        # Windows

For a queue, execute a temporary diagnostic job; for PHP-FPM, expose the result through a protected administrative route or a one-off command that uses the same service account. Do not leave a public diagnostic endpoint enabled.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

If Node cannot start, install a supported Node.js release through your deployment process and make its absolute path available to the service. Browsershot versions provide configuration for selecting a Node binary; use the setting documented for your installed version. Setting a Node path only points to Node—it does not install Puppeteer or Chrome.

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

After changing service configuration, restart the relevant PHP-FPM pool, queue workers, scheduler, or container. Long-running workers retain their original environment.

4. Install Puppeteer in the correct project context

Puppeteer’s standard installation is a project dependency:

npm install puppeteer

Run it in the directory and build stage from which the Browsershot command resolves its JavaScript modules. A global installation is not a substitute for a local dependency: Node resolves modules relative to the running project and its configured paths. Reinstalling globally may leave the failing runtime unchanged.

Check what the runtime can resolve:

node -p "require.resolve('puppeteer')"
node -p "require('puppeteer/package.json').version"
npm ls puppeteer

If the first command fails, the package is absent from that runtime context. Install dependencies during the image build or deployment step, and ensure production installs have not omitted the package. If your project intentionally uses puppeteer-core, remember that it is a DevTools Protocol client and does not download Chrome for you; you must provide and configure a browser separately.

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

5. Install and verify Chrome on the deployment target

The regular puppeteer package normally downloads a compatible Chrome for Testing and chrome-headless-shell. Since Puppeteer v19, the documented default cache is under the current user’s $HOME/.cache/puppeteer directory. That creates two common deployment traps:

  • the npm install ran under one user, but the web or queue process runs under another;
  • the browser was downloaded in a build stage but was not copied into the final container image.

Package managers or CI policies can disable install scripts, which prevents the automatic browser download. Restore the download step or run Puppeteer’s documented recovery command in the runtime environment:

npx puppeteer browsers install

Run it as the account that will launch Chrome, then verify that the resulting cache exists in the deployed filesystem. Do not assume a successful build-stage command means the production stage has the same files.

If you changed Puppeteer’s cache directory or download settings, update the configuration and run the browser installation again. Keep the cache inside the image or on a persistent volume according to your deployment model; ephemeral containers must download or receive it on every new 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 and browser configuration

Browsershot or Puppeteer may be configured with an explicit executable path. That path must identify the actual browser file visible to the Node process—not a directory, a path from your laptop, or a location that exists only in a previous container layer.

  • Remove a stale override if you want Puppeteer’s downloaded browser to be selected automatically.
  • If you manage Chrome yourself, set the documented executable path for your installed Browsershot/Puppeteer version.
  • Check the path from inside the running container or service account, and verify execute permission.
  • Do not mix a Windows path with Linux deployment configuration, or vice versa.

A browser can be present while still failing to launch because its sandbox, shared-memory area, or required system libraries are restricted by the hosting environment. Use the exact Chrome stderr before adding launch flags; indiscriminately disabling security features can create a different production risk.

7. Fix temporary-directory and profile failures

Chrome creates a temporary user-data directory. If the error mentions mkdtemp, an undefined temp path, or permission denied, inspect the environment used by the failing process:

echo "$TMPDIR"
echo "$TEMP"
echo "$TMP"
ls -ld /tmp

On Windows, inspect the service account’s TEMP/TMP variables and permissions. On Linux containers, ensure the configured temporary directory exists and is writable by the web or queue user. A community report of a Windows profile-creation failure is a single-machine example, not a universal fix; the reliable approach is to correct the actual path and permission shown in your stderr.

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

Also check disk space and inode availability. A full volume can look like a browser or Puppeteer failure because Chrome cannot create its profile or write the PDF.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

8. Use a minimal Laravel reproduction

Once Node, Puppeteer, Chrome, and temporary storage are verified, reduce the application call to a small document. For a Laravel PDF integration that exposes the following API, the shape is:

use SpatieLaravelPdfFacadesPdf;

Route::get('/diagnostic-pdf', function () {
    return Pdf::view('pdf.diagnostic', ['message' => 'Puppeteer check'])
        ->name('diagnostic.pdf');
});

Create a view containing only plain HTML and CSS. If that succeeds, add your real Blade components, web fonts, JavaScript, remote images, and custom headers one at a time. This separates a runtime installation problem from a page-specific timeout, asset, authentication, or JavaScript error. Match the method and options to your installed Laravel PDF version; method names vary between releases.

Common errors and targeted fixes

node: command not found or “node is not recognized”

Cause: Node is absent or not on the service account’s PATH. Fix: install Node in the deployment image, configure the Browsershot Node-binary setting supported by your version, restart workers, and test as the launching account.

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

Cannot find module 'puppeteer'

Cause: Puppeteer is not installed in the project/runtime module path, or production dependency installation skipped it. Fix: run npm install puppeteer in the correct project, confirm with require.resolve, and include the dependency in the final image.

Browser executable missing

Cause: install scripts were disabled, the cache belongs to another user, or a build stage did not copy the browser. Fix: run npx puppeteer browsers install in the runtime environment and verify the cache and permissions.

Using puppeteer-core without Chrome

Cause: puppeteer-core does not download a browser. Fix: install and manage Chrome yourself, then configure its real executable path.

mkdtemp, profile, or permission errors

Cause: the process cannot resolve or write its temporary directory. Fix: correct TEMP/TMP/TMPDIR, create the directory, grant the service account access, and check disk space.

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

Works in the shell but fails in production

Cause: different PATH, HOME, user, cache, working directory, filesystem, or container stage. Fix: compare those values from the failing process, not from an interactive login.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Deployment checklist for reliable PDF jobs

  • Pin and record the Laravel PDF, Browsershot, Puppeteer, Node.js, and Chrome versions used by the release.
  • Install npm dependencies during the image build or deployment step that produces the final runtime.
  • Download the browser in that same runtime, or copy its cache deliberately.
  • Keep the browser cache and temporary profile writable by the process account.
  • Use an absolute executable path only when you manage Chrome explicitly.
  • Restart PHP-FPM and queue workers after environment or package changes.
  • Log command, exit code, stdout, stderr, user, working directory, and version information for failed jobs.
  • Test a minimal local document before troubleshooting application-specific assets.

Or skip the browser setup

If your requirement is simply to obtain a clean screenshot or PDF from a URL, ScreenshotNeo provides a website screenshot API and MCP server instead of making your Laravel host maintain a Puppeteer installation. Its cleanup step accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup action can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers.

One GET request returns PNG, JPEG, WebP, or PDF. The API accepts the URL and access key directly:

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 documentation for options such as full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets, retina scale, PDF paper and page settings, custom CSS or 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, usage data, and the OpenAPI specification.

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

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(`${res.status} ${await res.text()}`);

ScreenshotNeo also exposes MCP tools named take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Every feature is included on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

When to change PDF engines

Switch only after comparing the CSS and JavaScript fidelity your documents require with the runtime dependencies your hosting provider permits. A different engine may avoid Node or Chrome, but it can render modern layouts, fonts, scripts, or page breaks differently. Browsershot documentation mentions older Chrome headless CLI and PhantomJS approaches; PhantomJS is described there as abandoned, so replacing Puppeteer with it is not a current general remedy.

Frequently Asked Questions

Does reinstalling Puppeteer globally fix Laravel PDF errors?

Usually not. Node resolves packages from the project and runtime module path, so verify the package with require.resolve('puppeteer') under the same account and environment that runs the PDF job.

Why does Puppeteer work locally but not in a container?

The container may have a different user, HOME directory, PATH, browser cache, filesystem, or final image stage. Compare those values inside the failing container and install or copy the browser there.

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.

Should I use puppeteer or puppeteer-core?

Use puppeteer when you want its normal browser-download behavior. Use puppeteer-core only when you intentionally manage a compatible browser and configure its executable path.

What information should I include when asking for support?

Include the installed Laravel PDF/Browsershot/Puppeteer versions, operating system, Node version, launching user, full command, exit code, stdout, stderr, working directory, and whether the failure occurs in a web request, queue, or container.

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.