Using Browsershot for PDF generation · vanrossum.dev    

       vanrossum.dev 

 Article

Using Browsershot for PDF generation
====================================

 ![](https://vanrossum.dev/images/jeffrey-portrait.webp) By Jeffrey van Rossum

  vanrossum.dev  

  [      vanrossum.dev ](https://vanrossum.dev)                      

  [ ← Writing ](https://vanrossum.dev/posts)   [ ← Writing ](https://vanrossum.dev/posts) [ Using Spatie's Browsershot Package ](#using-spaties-browsershot-package) [ What does the code look like? ](#what-does-the-code-look-like) [ Conclusion ](#conclusion) 

Yesterday I was trying to tweak the invoice design for [Addrow](https://addrow.io), a SaaS application I made with [Laravel](https://laravel.com). I have basically two templates for the invoice, one for web display and a PDF-version.

I tried to use one template for both versions, but using [Dompdf](https://github.com/dompdf/dompdf) I found myself having to tweak quite a lot to get the PDF anywhere near the HTML-version so ended up with two separate versions.

As I was trying to tweak the design, I decided to look for alternatives to Dompdf and try to get to a situation where I only needed to maintain one template file. I then stumbled upon this tweet by David Hemphill.

> Generating PDFs with [@vuejs](https://twitter.com/vuejs?ref_src=twsrc%5Etfw) components: I have a public invoice "print" view, styled with [@tailwindcss](https://twitter.com/tailwindcss?ref_src=twsrc%5Etfw), and served by a [@vuejs](https://twitter.com/vuejs?ref_src=twsrc%5Etfw) SPA. I'm using spatie/browsershot to hit the page and generate a PDF download response of that public page: [pic.twitter.com/yIXXCk7Nge](https://t.co/yIXXCk7Nge)
> 
> , DAVID-19 (@davidhemphill) [February 19, 2019](https://twitter.com/davidhemphill/status/1097889786654789633?ref_src=twsrc%5Etfw)

Using Spatie's Browsershot Package
----------------------------------

And that sort of blew my mind. David is using [Spatie's Browsershot package](https://github.com/spatie/browsershot/) to utilize the headless version of Chrome and generate a PDF download that way. A massive advantage is the template reusability and the PDF looks pretty darn close to the web-version. I can also use [TailwindCSS](tailwindcss.com/) to style the invoice. Pretty cool!

The package requires you to have Node and the Puppeteer library installed. But that is pretty easy to [install](https://github.com/spatie/browsershot/#requirements). The package readme file, even includes instructions how to install this on a [Forge](https://forge.laravel.com) provisioned server which is exactly my use case.

What does the code look like?
-----------------------------

You can get the idea from David's screenshot, but I thought it would be nice to share some more code to give an indication of how I implemented this. I have added a `pdf` method on my Invoice class like this:

```php
public function pdf()
{
    $content = view('templates.invoice', ['invoice' => $this])->render();

    return Browsershot::html($content)
        ->margins(18, 18, 24, 18)
        ->format('A4')
        ->showBackground()
        ->pdf();
}

```

The generated HTML is just a Blade rendered template. Then, in my `InvoicesController` I can do the following to stream the PDF to the browser:

```php
public function pdf($id)
{
    $invoice = Invoice::findOrFail($id);

    $this->authorize('view', $invoice);

    return response()->stream(function () use ($invoice) {
        echo $invoice->pdf();
    }, 200, ['Content-Type' => 'application/pdf']);
}

```

To add this PDF as an email attachment, I use the `attachData` method on the `Mailable` class.

```php
public function build()
{
    return $this->from(config('mail.from.address'))
        ->replyTo($this->invoice->profile->email)
        ->markdown('mail.invoice')
        ->subject(__("Your invoice is ready"))
        ->attachData($this->invoice->pdf(), __('Invoice :number', ['number' => $this->invoice->invoice_number]) . '.pdf');
}

```

Conclusion
----------

In the end I am very happy with this refactor. I can now use one template and use TailwindCSS for styling. Thanks to [Spatie](https://spatie.be) for providing this package and David for mentioning this on Twitter. Also, thanks to [Dompdf](https://github.com/dompdf/dompdf) since I've used this for years and in a lot of cases it might very well still be the way to go.

  ![](https://vanrossum.dev/images/jeffrey-portrait.webp) Jeffrey van Rossum [@jeffreyrossum](https://x.com/jeffreyrossum) 

 share [𝕏](https://twitter.com/intent/tweet?url=https%3A%2F%2Fvanrossum.dev%2Fposts%2Fusing-browsershot-for-pdf-generation&text=Using+Browsershot+for+PDF+generation) [WhatsApp](https://wa.me/?text=Using+Browsershot+for+PDF+generation+https%3A%2F%2Fvanrossum.dev%2Fposts%2Fusing-browsershot-for-pdf-generation) [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fvanrossum.dev%2Fposts%2Fusing-browsershot-for-pdf-generation) 

   © 2026 Jeffrey van Rossum 

  vanrossum.dev vanrossum.dev
