INTEGRATION Spatie Laravel PDF v2 · 8 min read

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
PHP8.2+
Laravel11.x through 13.x
Spatie Laravel PDF2.10+
BladePDFAccount 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

Terminal
bash
 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:

.env
env
 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.

Generate an invoice
php
 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:

.env
env
 1LARAVEL_PDF_DRIVER=bladepdf

After changing cached production configuration, rebuild Laravel's config cache:

Terminal
bash
 1php artisan config:cache

Your normal Spatie code no longer needs driver('bladepdf'):

Controller
php
 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.
Printed backgrounds are enabled automatically

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:

resources/views/pdf/footer.blade.php
blade
 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:

Wait for a chart
php
 1Pdf::view('pdf.report')
 2    ->driver('bladepdf')
 3    ->waitUntilReady('window.reportReady === true')
 4    ->save('report.pdf');
Do not pass a custom readiness timeout

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:

Queue worker render
php
 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:

Feature test
php
 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() or onLambda(), 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.