HTML To PDF Converter
2 March 2026

HTML to PDF in Laravel/PHP: The Simplest Integration

DomPDF can't handle modern CSS. Snappy wraps archived wkhtmltopdf. Here's how to generate PDFs in Laravel with a single HTTP request to a $5/year API — no packages, no binaries.

Laravel developers typically reach for one of two PDF packages: DomPDF (via barryvdh/laravel-dompdf) or Snappy (via barryvdh/laravel-snappy). Both have significant problems in 2026.

  • DomPDF: Pure PHP renderer. No flexbox, no grid, limited CSS support. Tables break with complex layouts. Fine for simple documents, painful for anything modern.
  • Snappy: A wrapper around wkhtmltopdf, which was archived in January 2023. No security updates, no modern CSS, no modern JavaScript.

There's a simpler option: skip the packages entirely and make an HTTP request to a PDF API.

The API approach

Send your rendered Blade template as HTML to the API. Get a PDF URL back. No composer packages, no binary dependencies, no system library requirements.

// app/Http/Controllers/InvoiceController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class InvoiceController extends Controller
{
    public function downloadPdf(string $invoiceId)
    {
        $invoice = Invoice::findOrFail($invoiceId);

        // Render the Blade template to HTML
        $html = view('invoices.pdf', compact('invoice'))->render();

        // Convert to PDF via API
        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . config('services.pdf.api_key'),
            'Content-Type' => 'text/html',
        ])->withBody($html, 'text/html')
          ->post('https://htmltopdfconverter.com.au/api/programmatic/pdf/generate');

        $pdfUrl = $response->json('pdfs.0.url');

        return redirect($pdfUrl);
    }
}

Configuration

Add your API key to .env:

PDF_API_KEY=your_api_key_here

And register it in config/services.php:

'pdf' => [
    'api_key' => env('PDF_API_KEY'),
],

Blade template example

<!-- resources/views/invoices/pdf.blade.php -->
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial, sans-serif; margin: 40px; color: #333; }
    .header { display: flex; justify-content: space-between; margin-bottom: 30px; }
    .company-name { font-size: 24px; font-weight: bold; }
    table { width: 100%; border-collapse: collapse; margin: 20px 0; }
    th { background: #f8f8f8; padding: 10px; text-align: left; border-bottom: 2px solid #ddd; }
    td { padding: 10px; border-bottom: 1px solid #eee; }
    .text-right { text-align: right; }
    .total { font-weight: bold; font-size: 18px; border-top: 2px solid #333; }
  </style>
</head>
<body>
  <div class="header">
    <div class="company-name">{{ config('app.name') }}</div>
    <div>Invoice #{{ $invoice->number }}<br>{{ $invoice->date->format('d M Y') }}</div>
  </div>

  <p><strong>Bill to:</strong> {{ $invoice->customer->name }}</p>

  <table>
    <thead>
      <tr><th>Description</th><th class="text-right">Qty</th><th class="text-right">Price</th><th class="text-right">Total</th></tr>
    </thead>
    <tbody>
      @foreach($invoice->items as $item)
      <tr>
        <td>{{ $item->description }}</td>
        <td class="text-right">{{ $item->quantity }}</td>
        <td class="text-right">$@{{ number_format($item->price, 2) }}</td>
        <td class="text-right">$@{{ number_format($item->total, 2) }}</td>
      </tr>
      @endforeach
      <tr class="total">
        <td colspan="3">Total</td>
        <td class="text-right">$@{{ number_format($invoice->total, 2) }}</td>
      </tr>
    </tbody>
  </table>
</body>
</html>

Because the API uses Chromium, your Blade template can use modern CSS — flexbox, grid, custom fonts, backgrounds. Everything that works in Chrome works in the PDF.

Multipart file upload (alternative)

If you prefer sending files rather than raw HTML:

$response = Http::withHeaders([
    'Authorization' => 'Bearer ' . config('services.pdf.api_key'),
])->attach('files', $html, 'invoice.html', ['Content-Type' => 'text/html'])
  ->post('https://htmltopdfconverter.com.au/api/programmatic/pdf/generate');

Why this beats DomPDF and Snappy

API approachDomPDFSnappy
CSS supportFull (Chromium)Limited (no flexbox/grid)Outdated (QtWebKit)
DependenciesNoneComposer packagewkhtmltopdf binary
MaintenanceManagedActiveArchived upstream
Rendering qualityBrowser-identicalApproximateOutdated engine
Cost$5 AUD/yearFreeFree (with caveats)

Get started

  1. Create an account (30 seconds)
  2. Subscribe from your dashboard ($5 AUD/year)
  3. Generate an API key and add it to your .env
  4. Copy the controller code above
  5. Create your Blade template and route

Full API docs — request formats, error codes, rate limits, and examples in PHP, Node.js, and Python.

FAQ

Do I need to install any composer packages?

No. Laravel's built-in Http facade handles the API call. No additional packages required.

Can I use this with Livewire or Inertia?

Yes. The PDF generation happens server-side in a controller or action. It doesn't matter how the request is triggered on the frontend — Livewire, Inertia, or a plain anchor tag all work.

What about DomPDF — is it really that limited?

DomPDF works well for simple, table-based layouts. But it has no flexbox or grid support, limited float handling, and struggles with complex CSS. If your templates are basic, DomPDF is fine. If they use modern CSS, it won't render them correctly.

Should I migrate from Snappy?

Yes. Snappy depends on wkhtmltopdf, which was archived in 2023 with no security updates. Continuing to use it means running unpatched software with known vulnerabilities.