Node.js — Create a PDF from HTML with Puppeteer and Handlebars

Puppeteer is Node.js library giving you access to a headless Chrome browser. This makes it a breeze to generate PDF files with Node.js.

Puppeteer works with so-called “pages” and allows you to inject your own HTML onto a page. From there, generate a PDF file from this page and save it to a file.

Node.js Series Overview

  1. Callback and Promise Support in your Node.js Modules
  2. Increase the Memory Limit for Your Process
  3. Why You Should Add “node” in Your Travis Config
  4. How to Run an Asynchronous Function in
  5. Create a PDF from HTML with Puppeteer and Handlebars
  6. Get Number of Seconds Since Epoch in JavaScript (Coming soon)
  7. Create Your Custom Error (Coming soon)
  8. Extend Multiple Classes (Multi Inheritance) (Coming soon)
  9. Filter Data in Streams (Coming soon)
  10. Get a File’s Created Date (Coming soon)
  11. Get a File’s Last Modified/Updated Date (Coming soon)
  12. How to Reset and Empty an Array (Coming soon)
  13. Human-Readable JSON.stringify() With Spaces and Line Breaks (Coming soon)
  14. String Replace All Appearances (Coming soon)
  15. Write a JSON Object to a File (Coming soon)

Generate an Invoice PDF from HTML

This tutorial illustrates the PDF creation from HTML using the example of an invoice. We extracted code from the Future Studio platform to make it approachable 😃

Let’s start off with this Postmark invoice template. Save the HTML template to your project’s location on your computer. You’ll need it in a minute.

A Dedicated Invoice Class

This tutorial uses an ES2015 class called Invoice that handles the PDF creation from HTML. Let’s say the Invoice class consists of two methods: html and pdf.

The html method reads the mentioned invoice HTML template from local disk. From here, it compiles the file content with Handlebars which returns a function. The resulting compile function from Handlebars can then take data which ultimately renders data into the placeholders resulting in the final HTML.

The pdf function of your Invoice class uses Puppeteer to create a new browser page, sets the HTML content for this page using the Invoice’s html method and generates the PDF content from the Puppeteer page.

const Fs = require('fs')  
const Path = require('path')  
const Util = require('util')  
const Puppeteer = require('puppeteer')  
const Handlebars = require('handlebars')  
const ReadFile = Util.promisify(Fs.readFile)

class Invoice {  
  async html() {
    try {
      const data = {
        your: 'data'

      const templatePath = Path.resolve('path', 'to', 'invoice.html')
      const content = await ReadFile(templatePath, 'utf8')

      // compile and render the template with handlebars
      const template = Handlebars.compile(content)

      return template(data)
    } catch (error) {
      throw new Error('Cannot create invoice HTML template.')

  async pdf() {
    const html = await this.html()

    const browser = await Puppeteer.launch()
    const page = await browser.newPage()
    await page.setContent(html)

    return page.pdf()

This is all you need for the PDF creation from HTML. Puppeteer does the difficult handling and gives you the methods to work on top of Chrome.

By default, Puppeteer generates a PDF using the print CSS media. If you want to print with screen CSS, call await page.emulateMedia('screen') before page.pdf().

The PDF Invoice from HTML

This is a sample receipt printed with Puppeteer:

PDF Invoice from HTML

Handlebars and Puppeteer are a powerful combination for PDF files from HTML. Handlebars gives you the flexibility to render data into placeholders and Puppeteer uses the HTML to generate a PDF.


Puppeteer as a Node.js library to control a headless Chrome browser provides a convenient interface to generate PDF files from HTML. You can render complex HTML with template engines like Handlebars. All libraries combined are a powerful toolset to integrate on-the-fly PDF creation in your Node.js apps.

Mentioned Resources

Explore the Library

Find interesting tutorials and solutions for your problems.