Automating HTML Invoice Generation with Node.js

Generate pixel-perfect PDF and PNG invoices from dynamic HTML templates in your backend.

📋 Table of Contents

The Challenge with Document Generation

If you're building an e-commerce platform or a SaaS application, you will inevitably need to generate receipts and invoices. Historically, developers relied on complex PDF generation libraries (like PDFKit) which required drawing rectangles and text strings manually at specific X,Y coordinates.

This approach is extremely tedious. A much better workflow is HTML-to-Image / HTML-to-PDF rendering. You build a beautifully styled HTML invoice using technologies you already know (HTML/CSS), inject dynamic data into it, and then capture it as a document.

Step 1: Creating the HTML Template

First, we create a basic HTML template. You can use standard template engines like Handlebars, EJS, or just native ES6 template literals to inject your user's billing data.

function generateInvoiceHtml(invoiceData) {
  return `
    <!DOCTYPE html>
    <html>
    <body style="font-family: Arial; padding: 40px; color: #333;">
      <div style="max-width: 800px; margin: auto; border: 1px solid #eee; padding: 20px;">
        <h1 style="color: #4F46E5;">INVOICE #${invoiceData.id}</h1>
        <p><strong>Date:</strong> ${invoiceData.date}</p>
        <p><strong>Customer:</strong> ${invoiceData.customerName}</p>
        
        <table style="width: 100%; border-collapse: collapse; margin-top: 20px;">
          <tr style="background: #f9f9f9;">
            <th style="padding: 10px; text-align: left;">Description</th>
            <th style="padding: 10px; text-align: right;">Amount</th>
          </tr>
          <tr>
            <td style="padding: 10px; border-bottom: 1px solid #eee;">${invoiceData.item}</td>
            <td style="padding: 10px; border-bottom: 1px solid #eee; text-align: right;">$${invoiceData.amount}</td>
          </tr>
        </table>
        
        <h3 style="text-align: right; margin-top: 20px;">Total: $${invoiceData.amount}</h3>
      </div>
    </body>
    </html>
  `;
}

Step 2: Rendering with SnapAPI

Now we have a raw HTML string. We can pass this directly to the SnapAPI via a POST request. The API uses absolute paths and headless Chrome under the hood to ensure full CSS3 support, custom fonts, and crisp rendering.

const fetch = require('node-fetch');
const fs = require('fs');

async function createInvoiceImage(invoiceData) {
  const htmlContent = generateInvoiceHtml(invoiceData);
  
  // Call SnapAPI with the raw HTML payload
  const response = await fetch('https://snapapi.alterra-solutions.com/v1/screenshot', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      html: htmlContent,
      api_key: process.env.SNAPAPI_KEY,
      width: 800,
      format: 'png' // Can easily be swapped to pdf, jpeg, webp
    })
  });

  if (!response.ok) {
    throw new Error(`API request failed: ${response.statusText}`);
  }

  // Save the result to disk or upload directly to S3
  const buffer = await response.buffer();
  fs.writeFileSync(`./invoice_${invoiceData.id}.png`, buffer);
  console.log('Invoice generated successfully!');
}

// Usage
createInvoiceImage({
  id: '78291',
  date: 'Feb 23, 2026',
  customerName: 'Acme Corp',
  item: 'Enterprise API License (Annual)',
  amount: '1,200.00'
});

Why not use Puppeteer directly?

If you implement exactly what happens inside SnapAPI manually, you'll need to install puppeteer in your Node environment. Here are the issues you'll immediately face:

Delegating the rendering to an API handles these complexities natively, saving hours of dev-ops headaches and ensuring pixel-perfect output every time.

Start Generating Documents

Use SnapAPI to generate your invoices, social media cards, and reports. 100 free captures per month.

Get Started Free →