breuer/laravel-pdf-chrome-driver
A Laravel PDF driver that turns Blade/HTML into PDFs using headless Chrome, so modern CSS, fonts, and layouts render faithfully. Register it as your PDF driver and generate invoices, reports, and other documents with minimal setup.
What it is. breuer/laravel-pdf-chrome-driver is a driver plugin for spatie/laravel-pdf that talks to Chrome over the DevTools Protocol (CDP) directly rather than going through Browsershot → Node → Puppeteer. That is the entire value proposition: it removes the Node.js runtime and the Puppeteer dependency from the PDF rendering path while keeping the familiar Pdf::view(...)->save(...) builder API.
Architecture fit. High, in principle. spatie/laravel-pdf is explicitly driver-oriented, so this slots in as a config-level swap (config/laravel-pdf.php → driver class) without touching application call sites. It respects Laravel conventions (service provider, publishable config, container bindings), which means the blast radius of adoption is one config file plus image changes. That is the ideal shape for a contained technical bet.
Integration feasibility. Straightforward mechanically — composer require, publish config, set driver, ensure a Chrome/Chromium binary is reachable. The real work is not installation, it is behavioral equivalence with the Browsershot baseline. Browsershot encodes years of accumulated pragmatism: wait-until-network-idle, waitForFunction, delay, custom user agent, cookies, auth headers, tag-based PDF options, header/footer templates, and a dozen paper/margin knobs. A direct CDP implementation has to re-earn each of those. Every PdfBuilder method our templates use must be verified against this driver, not assumed.
What v2.0.2 changes. This is a patch release with one fix, but it is a diagnostically useful one. Inline @font-face declarations using data: URIs were not applied during rendering; the driver now waits for the page load event after Page.setDocumentContent before invoking Page.printToPDF, so Chrome has fully parsed embedded resources. Three takeaways for the assessment:
Technical risk.
| Risk | Severity | Note |
|---|---|---|
| Maturity / adoption | High | Low stars, no dependents. Effectively unproven in production by anyone but the author. Active patch cadence (2.0.1 → 2.0.2) is a modest positive signal. |
| Bus factor | High | Single maintainer, no downstream community to absorb abandonment. |
| CDP drift | Medium | Page.printToPDF is one of the more stable CDP domains, but flags and lifecycle semantics change across Chrome majors. |
| Feature parity gaps | Medium–High | Font embedding (inline/base64 @font-face) resolved in v2.0.2. Header/footer HTML, background printing, tagged/accessible PDF, and scale remain unverified. |
| Silent-degradation regressions | Medium–High | v2.0.2 is a concrete instance: fonts silently fell back. The driver's failure mode is plausible-looking wrong output, not a hard error. |
| Chrome lifecycle | Medium | Spawn-per-render vs. long-lived browser; orphan processes and memory growth are the classic failure modes. |
MIT license is a meaningful mitigant: the driver surface is small and forkable, so abandonment is recoverable at modest cost.
Key questions to put to the maintainer (or answer in a spike).
spatie/laravel-pdf major versions and PHP versions are supported, and is the driver contract stable across them?PdfBuilder options are honored vs. silently ignored? Is there a parity matrix against Browsershot? A published list of known-incomplete options would materially de-risk adoption.setDocumentContent is confirmed as of v2.0.2. Still open: network-idle, selector-based waits, JS-flag waits, explicit delay, and timeout configuration.--no-sandbox guidance for root containers?Stack fit. Strong for Laravel 10–12 / PHP 8.1+ shops already on spatie/laravel-pdf. The strongest fit is containerized deployments where removing Node shrinks the image, cuts cold-start time, and eliminates a second runtime from the CVE surface — Alpine/slim images, ECS/Fargate, and any environment where a Node toolchain is otherwise carried purely for PDFs.
Migration path.
@font-face, since that path was broken until v2.0.2 and is the most likely place for residual font-handling defects.Compatibility. Pin the package and pin Chrome (base image digest). Never let chrome:latest float — a Chrome major bump is the single most likely way this breaks in production. Floor the package constraint at ^2.0.2 if any template relies on inline fonts; 2.0.0/2.0.1 will silently produce fallback-font PDFs. Add a CI job that renders the fixture corpus on every dependency update.
Sequencing. Do this behind product work, not in front of it. There is no user-visible feature payoff — it is a cost/operability play. If the team is mid-roadmap, schedule it as a platform-hygiene item, not a committed deliverable.
Maintenance. The package is small; the ownership burden is not zero. Assume we vendor or fork it within 12 months. Budget roughly 0.1–0.2 FTE for stewardship: dependency bumps, Chrome-major triage, and patching parity gaps. v2.0.2 is a fair example of the workload — a font-rendering defect in a 2.0.x line, found by the author, fixed in a patch. If we had been live on 2.0.1, our customers would have received invoices in the wrong typeface with no error anywhere. That is the shape of the ongoing cost: not outages, quiet output defects.
Support. Treat external support as nonexistent. Internal runbook required before go-live: how to reproduce a bad PDF, how to inspect Chrome stderr, how to force a driver rollback, and how to verify a font actually rendered.
Scaling. Direct CDP is the right shape for scale — one fewer process layer per render than Node+Puppeteer, lower resident memory, faster cold start. Throughput is bounded by Chrome instances, not by PHP workers. Expect ~150–300 MB per Chrome process; at meaningful volume (~10k PDFs/day) plan for a dedicated render pool or remote CDP endpoint rather than browser-per-request, and cap concurrency explicitly. Horizontal scaling is clean and stateless.
Failure modes to instrument from day one.
--no-sandbox requirements in root containers; sandbox misconfiguration on hardened runtimes.Alert on PDF failure rate and on render duration p95 and page-count distribution; a shift in page count distribution is the earliest signal that options are being ignored. Add an output-fidelity check (font-name or pixel-baseline assertion on a sampled render) — error-rate monitoring alone would not have caught v2.0.2.
Ramp-up. Low for PHP developers — the Laravel-facing API is unchanged. New concepts are confined to CDP and Chrome operations: targets, sessions, the Page domain, browser lifecycle, and container sandboxing. Expect 1–2 days for a mid-level developer to be productive and about a week of team knowledge to own the pipeline confidently, most of it spent on the diff harness and failure-mode runbook rather than the package itself.
Overall. Architecturally correct, strategically attractive (drops Node), commercially immature. v2.0.2 is mildly reassuring — active maintenance, a real parity gap closed — but it simultaneously demonstrates that defects in this package surface as silently wrong PDFs rather than errors, which raises the value of the diff harness relative to the code change itself. Recommendation unchanged: pilot, don't standardize. Run the spike against a real fixture corpus including inline-font templates; adopt only if parity is demonstrable and someone is named as owner. The MIT license and small surface make the downside bounded — this is a cheap experiment with a real operational payoff, not a platform commitment.
How can I help you explore Laravel packages today?