Guide Mar 28, 2026

How to Generate PDFs from HTML in 2026: Server-Side API vs Local Headless Chrome

Invoices, reports, receipts — without installing Chromium, managing browser processes, or paying for infrastructure. One REST API call converts any URL or HTML string to PDF in under a second.

Every developer eventually needs to generate PDFs. Invoices, reports, receipts, contracts — the list goes on. The traditional approach is to spin up Puppeteer or Playwright, manage Chromium installation, and run the browser locally. But there's a simpler way: an HTTP API.

PageBolt's /pdf endpoint converts URLs or raw HTML to PDF with a single REST call. No browser installation, no infrastructure, no DevOps headaches.

The Problem With Local PDF Generation

Most teams generate PDFs like this:

// Traditional approach — Puppeteer + local Chromium
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/invoice/123');
await page.pdf({ path: 'invoice.pdf' });
await browser.close();

This works, but comes with hidden costs:

An API-first approach eliminates all of this.

URL-to-PDF: The Simplest Case

Convert any public URL to PDF in one HTTP call:

curl -X POST https://pagebolt.dev/api/v1/pdf \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/invoice/123",
    "format": "A4",
    "margin": "1cm"
  }' \
  -o invoice.pdf

That's it. The PDF is saved locally. No browser, no dependencies, no infrastructure.

Cost: 1 API request = 1 PDF. PageBolt's free tier includes 100 requests/month. At $29/month you get 5,000 requests (enough for small SaaS); at $199/month, 50,000 requests (enterprise scale).

HTML-to-PDF: Generate From Dynamic Content

Real-world scenario: your app builds a custom invoice as HTML (line items, taxes, totals). You need to convert that HTML string to PDF.

JavaScript example:

const response = await fetch('https://pagebolt.dev/api/v1/pdf', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.PAGEBOLT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    html: `
      <html>
        <head>
          <style>
            body { font-family: Arial; margin: 40px; }
            .header { font-size: 24px; font-weight: bold; margin-bottom: 20px; }
            .line-item { display: flex; justify-content: space-between; margin: 10px 0; }
            .total { font-weight: bold; border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px; }
          </style>
        </head>
        <body>
          <div class="header">Invoice #INV-2026-001</div>
          <div class="line-item"><span>Product A</span><span>$50.00</span></div>
          <div class="line-item"><span>Product B</span><span>$30.00</span></div>
          <div class="total">Total: $80.00</div>
        </body>
      </html>
    `,
    format: 'A4',
    margin: '1.5cm',
  }),
});

const pdfData = await response.arrayBuffer();
fs.writeFileSync('invoice.pdf', Buffer.from(pdfData));

Python example:

import requests, os

response = requests.post(
    'https://pagebolt.dev/api/v1/pdf',
    headers={
        'x-api-key': os.environ['PAGEBOLT_API_KEY'],
        'Content-Type': 'application/json',
    },
    json={
        'html': '''
            <html>
              <head><style>
                body { font-family: Arial; margin: 40px; }
                .header { font-size: 24px; font-weight: bold; margin-bottom: 20px; }
                .line-item { display: flex; justify-content: space-between; margin: 10px 0; }
                .total { font-weight: bold; border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px; }
              </style></head>
              <body>
                <div class="header">Invoice #INV-2026-001</div>
                <div class="line-item"><span>Product A</span><span>$50.00</span></div>
                <div class="line-item"><span>Product B</span><span>$30.00</span></div>
                <div class="total">Total: $80.00</div>
              </body>
            </html>
        ''',
        'format': 'A4',
        'margin': '1.5cm',
    }
)

with open('invoice.pdf', 'wb') as f:
    f.write(response.content)

Both examples generate a professional invoice PDF in under 1 second, with no local browser or dependencies.

Adding Headers, Footers, and Page Numbers

Common requirement: page numbers and a footer on every page.

curl -X POST https://pagebolt.dev/api/v1/pdf \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/report",
    "format": "A4",
    "displayHeaderFooter": true,
    "headerTemplate": "<div style=\"font-size:12px;text-align:center;width:100%\">Confidential Report</div>",
    "footerTemplate": "<div style=\"font-size:10px;text-align:center;width:100%;color:#666\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>",
    "margin": "1cm"
  }' \
  -o report.pdf

The pageNumber and totalPages placeholders are automatically replaced with the correct values.

Page Format Options

FormatDimensionsUse Case
A4 (default)210×297mmStandard documents, invoices, reports
Letter8.5×11inUS documents, contracts, forms
Legal8.5×14inLegal documents, extended letters
Tabloid11×17inLarge reports, posters
A3297×420mmBlueprints, large-format documents
A5148×210mmSmall booklets, receipts

Also supported: landscape mode ("landscape": true), custom margins ("margins": {"top": "1cm", "bottom": "2cm"}), and scale ("scale": 0.8 to shrink or enlarge content, range 0.1–2.0).

Batch PDF Generation in CI/CD

Your SaaS generates monthly invoices for 1,000 customers. You need to create PDFs, store them, and email them out.

#!/bin/bash
# Generate invoices for all customers
for customer_id in $(get_customer_ids); do
  curl -X POST https://pagebolt.dev/api/v1/pdf \
    -H "x-api-key: $PAGEBOLT_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"url\": \"https://my-saas.com/invoice/$customer_id\",
      \"format\": \"A4\",
      \"margin\": \"1cm\",
      \"displayHeaderFooter\": true,
      \"footerTemplate\": \"<div style='font-size:10px;text-align:center;width:100%'>Invoice Generated $(date +%Y-%m-%d)</div>\"
    }" \
    -o "invoices/invoice-$customer_id.pdf"
done

Cost analysis: 1,000 invoices × 1 request each = 1,000 API calls/month ≈ $10–20 at PageBolt's plans. Compare to running Puppeteer: 1,000 browser instances × 300MB = 300GB of infrastructure plus CPU/memory for concurrency = $500+/month.

Puppeteer vs PageBolt for PDF Generation

ScenarioPageBoltPuppeteer
Simple URL-to-PDF
HTML string-to-PDF
Batch PDF generation
Complex page interactions before PDF
Running locally during development
Serverless/FaaS (Lambda, Vercel)
No dependency management
Cost-effective at scale

PageBolt wins when you need: API-first PDF generation, serverless compatibility, no infrastructure, and cost efficiency.

Puppeteer wins when you need: Complex interactions (login, form fill, dynamic rendering), local debugging, and full browser control.

Getting Started

  1. Sign upFree tier: 100 requests/month, no credit card required
  2. Get your API key — Available immediately from the dashboard
  3. Make your first PDF — Copy the curl examples above and try them
  4. Integrate into your app — Use the JavaScript or Python examples to generate PDFs on-demand
  5. Monitor usage — Check your API usage in the dashboard; upgrade if needed

PDF generation doesn't require you to manage Chromium. Try PageBolt free — 100 requests/month, no credit card.

Generate PDFs from HTML without managing a browser — free

100 requests/month, no credit card. URL or HTML to PDF in one API call, no Chromium required.

Get API key free →