Building a SaaS? Add PDF Export in 5 Minutes
Add PDF export to your SaaS application in under 5 minutes. Step-by-step integration guide with code examples for React, Next.js, and backend APIs.
Building a SaaS? Add PDF Export in 5 Minutes
At some point, your SaaS app needs to generate PDFs. Invoices for your billing system. Reports for your analytics dashboard. Contracts for your HR tool. Certificates for your learning platform. A PDF generation API is a cloud service that accepts HTML, templates, or structured data and returns a rendered PDF document via a REST endpoint, eliminating the need to manage headless browsers or rendering infrastructure on your own servers.
Most developers dread this feature request. They picture weeks of wrestling with Puppeteer, managing Chromium memory leaks, debugging page break issues, and scaling browser pools. But it does not have to be that way. With a PDF generation API, you can add PDF export to any SaaS application in under five minutes and about fifteen lines of code.
This guide walks you through the complete process, from getting your API key to building a polished download button in React, with server-side examples in Node.js and Python.
Why Every SaaS Needs PDF Export
PDF export keeps users from leaving your app to screenshot and paste into docs. Users expect to download, print, and share their data. Here are the most common scenarios across SaaS verticals:
Billing and Payments: Invoices, receipts, credit notes, and account statements. Every SaaS that charges money needs these. Your customers need them for their accountants, their expense reports, and their tax filings.
Analytics and Reporting: Monthly performance reports, quarterly business reviews, and ad-hoc data exports. Stakeholders who do not log into your dashboard still need to see the numbers. PDFs get attached to emails and shared in board meetings.
Compliance and Legal: Contracts, terms of service agreements, audit logs, and compliance certificates. Regulated industries like fintech and healthcare require immutable document records.
Education and Training: Course completion certificates, transcripts, and training records. If you run an LMS or any platform with credentialing, PDF certificates are table stakes.
E-commerce: Order confirmations, packing slips, shipping labels, and WooCommerce invoices. Customers expect a printable receipt for every transaction.
The pattern is the same across all of these: take structured data from your database, merge it into a template, and produce a downloadable PDF. The only question is how you build it.
Quick Start: Get Your API Key and Make Your First Request
The fastest path from zero to PDF is three steps: sign up, grab your key, and make a request.
Step 1: Create a Free Account
Head to lightningpdf.dev/auth/register and sign up. The free tier gives you 50 PDFs per month with full API access, no credit card required. That is enough to build, test, and launch your integration.
Step 2: Copy Your API Key
After signing up, you will find your API key on the dashboard. It looks something like lpdf_live_abc123.... Copy it.
Step 3: Generate Your First PDF
Open a terminal and run this:
curl -X POST https://api.lightningpdf.dev/api/v1/pdf/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Hello from my SaaS</h1><p>This PDF was generated in under 100ms.</p>", "options": {"format": "A4"}}'
That is it. You just generated a PDF. The response contains a base64-encoded PDF in the data.pdf field. The entire round-trip takes under 200 milliseconds for simple documents using the native engine.
For a deeper look at the API, check the full documentation.
Building a Download Button in React
The most common integration pattern for SaaS apps is a "Download PDF" button that generates and downloads the document on click. Here is a complete React component:
import { useState } from 'react';
function DownloadPDFButton({ invoiceData }) {
const [loading, setLoading] = useState(false);
const handleDownload = async () => {
setLoading(true);
try {
const response = await fetch('/api/generate-pdf', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ invoiceData }),
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `invoice-${invoiceData.invoiceNumber}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
} catch (error) {
console.error('PDF generation failed:', error);
} finally {
setLoading(false);
}
};
return (
<button onClick={handleDownload} disabled={loading}>
{loading ? 'Generating...' : 'Download PDF'}
</button>
);
}
Notice the button calls /api/generate-pdf on your own server, not the LightningPDF API directly. You never want to expose your API key to the browser. The next section shows how to build that backend route.
Server-Side Generation: Node.js
Here is an Express route handler that receives invoice data from your frontend, builds the HTML, calls LightningPDF, and returns the PDF binary:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/api/generate-pdf', async (req, res) => {
const { invoiceData } = req.body;
const html = buildInvoiceHTML(invoiceData);
const response = await fetch('https://api.lightningpdf.dev/api/v1/pdf/generate', {
method: 'POST',
headers: {
'X-API-Key': process.env.LIGHTNINGPDF_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html,
options: {
format: 'A4',
margin_top: '15mm',
margin_bottom: '15mm',
margin_left: '15mm',
margin_right: '15mm',
},
}),
});
const result = await response.json();
const pdfBuffer = Buffer.from(result.data.pdf, 'base64');
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition',
`attachment; filename="invoice-${invoiceData.invoiceNumber}.pdf"`);
res.send(pdfBuffer);
});
function buildInvoiceHTML(data) {
return `
<html>
<head>
<style>
body { font-family: 'Helvetica Neue', Arial, sans-serif; color: #1a1a1a; }
.header { display: flex; justify-content: space-between; margin-bottom: 40px; }
.company { font-size: 24px; font-weight: bold; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th { background: #f8f9fa; text-align: left; padding: 12px; border-bottom: 2px solid #dee2e6; }
td { padding: 12px; border-bottom: 1px solid #dee2e6; }
.total { font-size: 20px; font-weight: bold; text-align: right; margin-top: 20px; }
</style>
</head>
<body>
<div class="header">
<div class="company">${data.companyName}</div>
<div>Invoice #${data.invoiceNumber}<br>${data.date}</div>
</div>
<p><strong>Bill to:</strong> ${data.customerName}<br>${data.customerEmail}</p>
<table>
<thead>
<tr><th>Description</th><th>Qty</th><th>Price</th><th>Total</th></tr>
</thead>
<tbody>
${data.items.map(item => `
<tr>
<td>${item.description}</td>
<td>${item.quantity}</td>
<td>$${item.unitPrice.toFixed(2)}</td>
<td>$${(item.quantity * item.unitPrice).toFixed(2)}</td>
</tr>
`).join('')}
</tbody>
</table>
<div class="total">Total: $${data.total.toFixed(2)}</div>
</body>
</html>
`;
}
app.listen(3000);
For a complete walkthrough of Node.js PDF generation including templates, markdown input, and engine selection, see the Node.js PDF generation guide.
Server-Side Generation: Python
If your SaaS backend runs on Python (Django, Flask, or FastAPI), the integration works the same way:
import os
import base64
import requests
from flask import Flask, request, send_file
from io import BytesIO
app = Flask(__name__)
@app.route('/api/generate-pdf', methods=['POST'])
def generate_pdf():
invoice_data = request.json['invoiceData']
html = build_invoice_html(invoice_data)
response = requests.post(
'https://api.lightningpdf.dev/api/v1/pdf/generate',
headers={
'X-API-Key': os.environ['LIGHTNINGPDF_API_KEY'],
'Content-Type': 'application/json',
},
json={
'html': html,
'options': {
'format': 'A4',
'margin_top': '15mm',
'margin_bottom': '15mm',
},
},
)
result = response.json()
pdf_bytes = base64.b64decode(result['data']['pdf'])
return send_file(
BytesIO(pdf_bytes),
mimetype='application/pdf',
as_attachment=True,
download_name=f"invoice-{invoice_data['invoiceNumber']}.pdf",
)
def build_invoice_html(data):
items_html = ''.join(
f"<tr><td>{item['description']}</td>"
f"<td>{item['quantity']}</td>"
f"<td>${item['unitPrice']:.2f}</td>"
f"<td>${item['quantity'] * item['unitPrice']:.2f}</td></tr>"
for item in data['items']
)
return f"""
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; color: #1a1a1a; }}
table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
th {{ background: #f8f9fa; text-align: left; padding: 12px; }}
td {{ padding: 12px; border-bottom: 1px solid #dee2e6; }}
.total {{ font-size: 20px; font-weight: bold; text-align: right; margin-top: 20px; }}
</style>
</head>
<body>
<h1>{data['companyName']}</h1>
<p>Invoice #{data['invoiceNumber']}</p>
<table>
<thead><tr><th>Description</th><th>Qty</th><th>Price</th><th>Total</th></tr></thead>
<tbody>{items_html}</tbody>
</table>
<div class="total">Total: ${data['total']:.2f}</div>
</body>
</html>
"""
For more Python-specific patterns including async generation, Django integration, and batch processing, see the Python PDF generation guide.
Using Templates for Invoices and Reports
Building HTML strings in your code works, but it gets messy fast. Templates let you separate your document design from your application logic. LightningPDF supports two approaches.
Pre-Built Marketplace Templates
The template marketplace has over 50 ready-to-use templates for invoices, receipts, reports, and certificates. Pick one and pass your data:
const response = await fetch('https://api.lightningpdf.dev/api/v1/pdf/generate', {
method: 'POST',
headers: {
'X-API-Key': process.env.LIGHTNINGPDF_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
template_id: 'invoice-professional',
variables: {
company_name: 'Acme SaaS Inc.',
invoice_number: 'INV-2026-0042',
customer_name: 'Jane Smith',
customer_email: 'jane@example.com',
items: [
{ description: 'Pro Plan - Monthly', quantity: 1, unit_price: 29.00 },
{ description: 'Additional Users (5)', quantity: 5, unit_price: 5.00 },
],
subtotal: 54.00,
tax: 4.86,
total: 58.86,
},
}),
});
Custom Templates with the Visual Designer
For branded documents that match your SaaS aesthetic, use the visual template designer. Design your template with drag-and-drop, define variable placeholders, and call it from your code the same way. This approach is covered in detail in the PDF invoice API guide.
Handling Reports and Multi-Page Documents
Invoices are usually single-page documents. Reports are more complex. They may have charts, tables spanning multiple pages, and dynamic content that changes length each month.
Here is how to handle automated PDF reports with proper page breaks:
const reportHTML = `
<html>
<head>
<style>
@page { size: A4; margin: 20mm; }
.section { page-break-inside: avoid; margin-bottom: 24px; }
.page-break { page-break-before: always; }
table { width: 100%; border-collapse: collapse; page-break-inside: auto; }
tr { page-break-inside: avoid; }
thead { display: table-header-group; }
h2 { page-break-after: avoid; }
</style>
</head>
<body>
<h1>Monthly Performance Report</h1>
<p>Generated: ${new Date().toLocaleDateString()}</p>
<div class="section">
<h2>Revenue Summary</h2>
<table>
<thead><tr><th>Metric</th><th>This Month</th><th>Last Month</th><th>Change</th></tr></thead>
<tbody>
<tr><td>MRR</td><td>$48,200</td><td>$44,100</td><td>+9.3%</td></tr>
<tr><td>New Customers</td><td>142</td><td>118</td><td>+20.3%</td></tr>
<tr><td>Churn Rate</td><td>2.1%</td><td>2.8%</td><td>-0.7%</td></tr>
</tbody>
</table>
</div>
<div class="page-break"></div>
<div class="section">
<h2>Detailed Breakdown</h2>
<!-- Dynamic content here -->
</div>
</body>
</html>
`;
const response = await fetch('https://api.lightningpdf.dev/api/v1/pdf/generate', {
method: 'POST',
headers: {
'X-API-Key': process.env.LIGHTNINGPDF_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: reportHTML,
options: {
format: 'A4',
engine: 'chromium',
},
}),
});
For troubleshooting page break issues, the fix PDF page breaks guide covers every CSS property and technique in detail.
Scaling Considerations
As your SaaS grows, your PDF volume grows with it. Here is what to think about at each stage.
Early Stage (Under 50 PDFs/Month)
Use the free tier. Fifty PDFs per month covers development, testing, and early customers. Synchronous generation is fine since each request completes in under a second.
Growth Stage (Hundreds to Thousands per Month)
Move to the Starter plan at $9/month for 2,000 PDFs. At this stage, consider:
- Caching: If the same PDF gets downloaded multiple times, store the generated PDF in S3 and serve the cached version.
- Background generation: For reports and statements, generate PDFs asynchronously via a job queue and email the download link.
- Templates: Switch from inline HTML to marketplace or custom templates for easier maintenance.
Scale Stage (Thousands to Tens of Thousands)
The Pro plan at $29/month covers 10,000 PDFs. At this volume:
- Batch API: Generate hundreds or thousands of PDFs in a single API call. Ideal for monthly invoicing runs and report automation.
- Webhooks: Use async generation with webhook callbacks instead of waiting for each PDF synchronously.
- Regional considerations: If you serve regulated industries, review the self-hosted deployment option for data sovereignty.
See the pricing page for all plan details and volume discounts.
API Comparison: Why LightningPDF for SaaS
If you are evaluating options, here is how the most common approaches compare for SaaS integration:
| Criteria | LightningPDF | Puppeteer (DIY) | DocRaptor | PDFShift |
|---|---|---|---|---|
| Time to integrate | 5 minutes | 2-5 days | 30 minutes | 30 minutes |
| Lines of code | 10-15 | 500+ | 10-15 | 10-15 |
| Speed (invoice) | <100ms | 1-3 seconds | 2-5 seconds | 1-3 seconds |
| Infrastructure | None | Docker, scaling, monitoring | None | None |
| Template marketplace | 15+ starter templates | None | None | None |
| Visual designer | Yes | No | No | No |
| Batch API | Yes | Build it yourself | No | No |
| Cost at 10K/mo | $29 | $300+ infra | $79+ | $79 |
| Free tier | 50/mo | N/A | 5/mo | 50/mo |
For detailed head-to-head comparisons, see LightningPDF vs Puppeteer, LightningPDF vs DocRaptor, and LightningPDF vs PDFShift.
Next Steps
You now have everything you need to add PDF export to your SaaS:
- Sign up for a free account (50 PDFs/month, no credit card)
- Browse the template marketplace for ready-to-use designs
- Read the API documentation for all available options and parameters
- Copy the React button component and Node.js or Python route handler from this guide
Expect five minutes with a marketplace template, or about thirty if you build your own HTML template.
Frequently Asked Questions
How do I add PDF export to my SaaS application?
Add PDF export by signing up for a LightningPDF API key, creating a backend route that accepts document data and calls the API with HTML or a template ID, and adding a download button in your frontend that triggers the backend route and saves the returned PDF binary as a file download.
Do I need to run a headless browser to generate PDFs?
No. LightningPDF handles all rendering on its servers, so you never install Chrome, manage browser pools, or deal with memory leaks. Your server sends a simple HTTP POST with HTML or template variables and receives a finished PDF back. This eliminates the largest infrastructure burden of self-hosted PDF generation.
How much does PDF generation cost for a SaaS application?
LightningPDF offers a free tier of 50 PDFs per month for development and testing. The Starter plan at $9 per month covers 2,000 PDFs, and the Pro plan at $29 per month covers 10,000 PDFs. At the Pro tier, each document costs roughly $0.003, which is significantly cheaper than self-hosting headless browsers.
Related Reading
- Best PDF Generation APIs in 2026 — Full comparison of top PDF APIs
- Generate PDFs in Node.js — Complete Node.js integration guide
- Generate PDFs in Python — Python-specific patterns and examples
- Generate PDFs in Go — Go tutorial with invoice example
- HTML to PDF: The Complete Guide — Every approach compared
- How to Fix PDF Page Breaks — Solve page break issues in generated PDFs
- LightningPDF vs Puppeteer — Build vs buy cost analysis
- PDF Invoice API Guide — Deep dive into invoice generation
LightningPDF Team
Building fast, reliable PDF generation tools for developers.