Spatie Laravel PDF
Keep the familiar Spatie\LaravelPdf\Facades\Pdf API and use BladePDF as its managed Chromium backend. Existing Blade views are rendered by Spatie, then passed through BladePDF's asset pipeline without running Chrome or Node.js in your application.
Requirements
| Requirement | Supported version |
|---|---|
| PHP | 8.2+ |
| Laravel | 11.x through 13.x |
| Spatie Laravel PDF | 2.10+ |
| BladePDF | Account and API key |
The native bladepdf/laravel package also supports Laravel 10, but this integration starts at Laravel 11. Spatie Laravel PDF 2.10 is the minimum because it introduced the readiness and caching contracts used by the driver.
Installation
1composer require bladepdf/spatie-laravel-pdf-driver
The integration installs the BladePDF Laravel client and Spatie Laravel PDF, then registers the bladepdf driver through Laravel package auto-discovery.
Add the API key from your BladePDF dashboard:
1BLADEPDF_API_KEY=blpdf_xxxxxxxxxxxxxxxxxxxxxxxx
Use BladePDF for one PDF
Select the driver on an individual Spatie builder. No application-wide configuration changes are required.
1use Spatie\LaravelPdf\Facades\Pdf;
2
3Pdf::view('pdf.invoice', ['invoice' => $invoice])
4 ->driver('bladepdf')
5 ->format('a4')
6 ->margins(12, 12, 16, 12)
7 ->save(storage_path('app/invoice.pdf'));
Make BladePDF the default driver
Set the Spatie driver environment variable when every existing Pdf:: call should use BladePDF:
1LARAVEL_PDF_DRIVER=bladepdf
After changing cached production configuration, rebuild Laravel's config cache:
1php artisan config:cache
Your normal Spatie code no longer needs driver('bladepdf'):
1return Pdf::view('pdf.invoice', ['invoice' => $invoice])
2 ->name("invoice-{$invoice->number}.pdf");
Supported options
| Spatie feature | BladePDF behavior |
|---|---|
view() and html() | Rendered HTML is sent through BladePDF's asset pipeline. |
headerView() / headerHtml() | Forwarded as Chromium header HTML. |
footerView() / footerHtml() | Forwarded as Chromium footer HTML. |
format() | Forwarded to BladePDF. |
paperSize() | Width, height, and unit are forwarded. Custom dimensions take precedence over format(). |
margins() | All four margins and their unit are forwarded. |
landscape() / portrait() | Forwarded to Chromium. |
scale() | Forwarded to BladePDF. |
pageRanges() | Forwarded to BladePDF. |
tagged() | Requests a tagged PDF from Chromium. |
waitUntilReady() | The JavaScript readiness expression is forwarded. |
meta() | Applied by Spatie after BladePDF returns the PDF. |
encrypt() | Applied by Spatie after BladePDF returns the PDF. |
cache() | Uses Spatie's cache layer. |
disk() | Uses Spatie's filesystem flow after rendering. |
saveQueued() | Runs a synchronous BladePDF request inside Spatie's queued job. |
The integration calls BladePDF's showBackground() for every render, matching the behavior of Spatie's Chromium-based drivers.
Headers, footers, and assets
Spatie renders the body, header, and footer Blade views before invoking the driver. BladePDF then discovers local images, stylesheets, CSS imports, and fonts in the resulting HTML and uploads them as request-scoped assets.
Spatie's @pageNumber and @totalPages directives compile to Chromium header/footer placeholders and continue to work:
1<footer>
2 Page @pageNumber of @totalPages
3</footer>
See Asset Pipeline for local URL detection and Headers & Footers for Chromium layout constraints.
JavaScript readiness
The expression form of Spatie's readiness API is supported:
1Pdf::view('pdf.report')
2 ->driver('bladepdf')
3 ->waitUntilReady('window.reportReady === true')
4 ->save('report.pdf');
BladePDF does not accept Spatie's optional per-expression timeout. Calling waitUntilReady($expression, $milliseconds) throws UnsupportedReadinessTimeoutException instead of silently ignoring the timeout. Use the BladePDF plan render limit and HTTP timeout configuration.
Queued renders
Spatie's queue API remains available:
1Pdf::view('pdf.report', $data)
2 ->driver('bladepdf')
3 ->disk('s3')
4 ->saveQueued('reports/monthly.pdf');
This queues Spatie's job, and the worker performs a synchronous BladePDF API request. It is different from BladePDF's native asynchronous render API, which stores the PDF in BladePDF and delivers completion through signed webhooks.
Testing
Pdf::fake() continues to work and prevents the driver from being invoked:
1use Spatie\LaravelPdf\Facades\Pdf;
2use Spatie\LaravelPdf\PdfBuilder;
3
4Pdf::fake();
5
6$this->get('/invoices/INV-1.pdf')->assertOk();
7
8Pdf::assertRespondedWithPdf(
9 fn (PdfBuilder $pdf): bool => $pdf->viewName === 'pdf.invoice',
10);
For an integration test that exercises the driver and option mapping, fake BladePDF's outbound Laravel HTTP request with Http::fake().
When to use the native BladePDF facade
The Spatie driver deliberately exposes Spatie's portable PDF abstraction. Use BladePDF:: directly for features that are specific to the managed service:
- dashboard-managed cloud Blade templates,
- request-scoped asset overrides,
- BladePDF references and template names,
- stored PDFs and signed retrieval URLs,
- per-request webhooks and native async rendering,
withBrowsershot()oronLambda(), which apply only to Spatie's Browsershot driver.
Both APIs can coexist in the same application: use the Spatie driver for portable existing call sites and the native facade where BladePDF-specific capabilities are valuable.