Generating PDFs from web pages is one of those tasks that looks simple until you're knee-deep in Puppeteer configuration.
You install the package. You launch a browser. You call page.goto(), wait for networkidle2, call page.pdf(), handle the timeout, close the browser, write the file. And that's the happy path — before you've dealt with the Docker sandbox flags, the 300MB Chromium binary in CI, or the memory leak that shows up on page three.
There's a cleaner way.
The SnapAPI approach
SnapAPI's /v1/pdf endpoint converts any URL to a PDF on our infrastructure. One HTTP call. No browser to manage.
// npm install snapapi-sdk
const snap = require('snapapi-sdk');
const fs = require('fs');
const api = new snap.SnapAPI('YOUR_KEY'); // or set SNAPAPI_KEY env var
async function generatePDF(url, outputPath) {
const pdf = await api.pdf({
url,
format: 'A4',
print_background: true, // include CSS background colors/images
margin_top: 20,
margin_bottom: 20,
margin_left: 20,
margin_right: 20,
});
fs.writeFileSync(outputPath, pdf);
console.log(`Saved: ${outputPath} (${(pdf.length / 1024).toFixed(1)} KB)`);
}
generatePDF('https://github.com', 'github.pdf');
That's it. The PDF renders from a real Chromium browser on our side — full CSS support, JavaScript execution, web fonts, the works.
Real use cases
Invoice generation — render your invoice HTML template to a URL, call the PDF endpoint, attach the result to a transactional email. No PDF library, no layout math, no font embedding — just HTML you already know how to write.
Report exports — convert any dashboard or analytics page to PDF on demand. Charts rendered by JavaScript frameworks (Chart.js, D3, Recharts) are captured correctly because Chromium waits for the page to fully settle before generating the PDF.
Web archiving — preserve live pages as PDFs for compliance, audit trails, or research. Timestamped captures that reflect exactly what a visitor would have seen.
Documentation — auto-generate PDF versions of your docs on every deploy. Link them from your site for users who prefer offline reading.
Full working script with error handling
const snap = require('snapapi-sdk');
const fs = require('fs');
const path = require('path');
const api = new snap.SnapAPI(process.env.SNAPAPI_KEY);
async function urlToPDF(url, options = {}) {
const defaults = {
format: 'A4', // A4, Letter, A3, A5, Legal, Tabloid
landscape: false,
print_background: true,
margin_top: 20,
margin_bottom: 20,
margin_left: 20,
margin_right: 20,
scale: 1.0, // 0.1–2.0 — use 0.8 to shrink dense content
};
const pdf = await api.pdf({ url, ...defaults, ...options });
const filename = new URL(url).hostname + '-' + Date.now() + '.pdf';
const filepath = path.join(process.cwd(), filename);
fs.writeFileSync(filepath, pdf);
return { path: filepath, size: pdf.length };
}
// Usage
async function main() {
// Basic A4
let result = await urlToPDF('https://github.com');
console.log(`A4 PDF: ${result.path} (${(result.size / 1024).toFixed(1)} KB)`);
// Landscape Letter — good for wide tables or dashboards
result = await urlToPDF('https://example.com', { format: 'Letter', landscape: true });
console.log(`Landscape PDF: ${result.path}`);
// Minimal margins — maximize content area
result = await urlToPDF('https://example.com', { margin_top: 0, margin_bottom: 0, margin_left: 0, margin_right: 0 });
console.log(`No-margin PDF: ${result.path}`);
}
main().catch(console.error);
Three tips for better PDFs
1. Use print_background: true for branded output. The default in most browsers is to skip background colors and images when printing. If your page uses a dark header, a colored sidebar, or background-image for layout — you need print_background: true or the PDF will look broken.
2. Add delay for pages with lazy-loaded content. If your page loads charts or images after the initial render, add a delay parameter (delay: 2000 for 2 seconds) to give the browser time to finish rendering before the PDF is captured.
3. Use scale to fit dense content. If a page has wide tables or tight layouts that clip at the margins, scale: 0.85 shrinks everything proportionally to fit the page width. Much cleaner than fighting with print media queries.
Free API key
100 PDF generations/month, no credit card, active in 30 seconds.
Top comments (0)