- How do I install spatie/browsershot and generate a PDF from a Laravel Blade view?
- Install it with composer require spatie/browsershot, then render your Blade view to a string and pass that string to Browsershot::html($html)->save($path). Browsershot infers the output format from the file extension, so a .pdf path produces a PDF and an image extension produces a screenshot. In Laravel the usual pattern is a queued job that renders the view, calls save() to a storage path, and records the resulting file. You still need Node, Puppeteer, and a Chromium binary available on the same host or container as PHP.
- Does Browsershot need Node.js, Puppeteer, and Chrome installed alongside PHP?
- Yes. Browsershot is not a PHP-native renderer: the PHP package assembles an argument list and shells out to a bundled Node script that drives Puppeteer and headless Chrome. Version 5 requires Node 20 or newer and Puppeteer 23 or newer, plus a Chromium binary, system fonts, and the usual Linux shared libraries. Treat that runtime stack as part of your container image, not as a Composer-only dependency.
- Which Laravel and PHP versions are supported by spatie/browsershot?
- Browsershot is framework-agnostic PHP, so it works with Laravel applications without a service provider and does not tie you to a specific Laravel release. Check Packagist for the exact PHP constraint of the Browsershot version you install. The compatibility risks that matter more in practice are Node 20+, Puppeteer 23+ for v5, and the Chromium build available in your runtime.
- How do I run Browsershot in a Laravel queue job without blocking web requests?
- Create a queued job, render the Blade view to HTML inside the job, and call Browsershot::html($html)->save($path) rather than rendering during the web request. Browsershot has no built-in queueing, retry logic, caching, or metrics, so use Laravel queues, job timeouts, and your own retry and monitoring strategy. Also set process timeouts and watch for orphaned Chrome children if a render hangs. High-volume or latency-sensitive paths are usually better served by a dedicated render service.
- Why are my Browsershot PDFs blank, missing fonts, or missing JavaScript-rendered charts?
- Blank PDFs, missing fonts, and absent charts usually mean Chrome could not load assets, JavaScript did not finish, or the container lacks fonts and shared libraries. Use waitUntilNetworkIdle() for pages with async JavaScript, confirm setChromePath() and setNodeBinary() point to valid binaries, and install common fonts in the image. Version mismatches between Browsershot, Puppeteer, and Chrome can also change pagination and layout without throwing a PHP error. Capture logs from the Node subprocess so failures are visible.
- Is Browsershot safe to use with user-supplied URLs, or does it create SSRF risks?
- Browsershot::url() makes your server fetch a URL, so user-supplied URLs introduce SSRF and local file read risk. Recent releases have patched specific bypasses: 5.2.1 blocks UNC paths and protocol-relative bypasses, 4.3.1 added a file: check, and 5.2.3 re-allows localhost for Vite dev servers. Do not rely on those patches as your only defense; enforce an allow-list, resolve and validate hosts, and sanitize any user-supplied HTML. Run renders with least privilege and restrict network egress where possible.
- How do I configure Browsershot to use a custom Chrome or Node binary path in Docker or Laravel Sail?
- Use the fluent escape hatches: setNodeBinary(), setNpmBinary(), setChromePath(), newHeadless(), and setOption() for Puppeteer options. In Docker or Sail, install Node 20+ and Chromium in the same image as PHP, then point Browsershot at those paths. If your base image already includes Chromium for Dusk or Cypress, reuse it to cut image size and provisioning work. Pin versions in the image so local and production renders match.
- Can Browsershot run on Laravel Vapor, AWS Lambda, or other serverless environments?
- Browsershot is a weak fit for read-only serverless runtimes such as Laravel Vapor or plain AWS Lambda because it expects Node and Chromium on the same host as PHP and writes artifacts to disk. You can make it work with container-image Lambda functions or by offloading rendering to a dedicated service, but that is an architecture change rather than a configuration tweak. Forge, VMs, and Sail are straightforward because you control the container and can install the runtime.
- How does Browsershot compare to DOMPDF, mPDF, and Snappy for Laravel PDF generation?
- DOMPDF, mPDF, and Snappy are PHP-native or lighter-weight, but they often struggle with flexbox, grid, web fonts, and JavaScript-rendered charts. Browsershot drives real headless Chrome through Puppeteer, so it produces pixel-accurate output for modern Blade layouts, invoices, dashboards, and certificates. The tradeoff is the Node and Chromium runtime, higher memory per render, and the need to manage Chrome upgrades. Choose Browsershot when visual fidelity matters more than a pure-PHP deployment.
- How should I test Browsershot renders and manage Chrome version upgrades in CI?
- There is no built-in fake for Chrome, so isolate rendering behind your own interface and test the surrounding job or service with fixture HTML. For visual stability, render deterministic HTML fixtures and compare output snapshots, and pin Chrome, Puppeteer, and Browsershot versions in CI and production. Chrome-for-Testing ships frequently, so upgrade deliberately and review PDF pagination, font metrics, and layout after each bump. Run the real Chrome path in a container-based CI job so missing libraries or fonts fail before deployment.