📋 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:
- Infrastructure footprint: Managing headless browsers introduces server heavy memory requirements and CPU spikes.
- Zombie Processes: Browsers are prone to crashing and leaving zombie OS processes that gradually eat up server RAM.
- Missing Fonts: Standard Linux servers often lack the necessary fonts required to render accurate typography, replacing emojis with boxes and missing web fonts entirely.
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 →