Prompt

How do I convert HTML into a PDF reliably?

Technology / Developer Tools1 observationLast seen Oct 12, 2026

Latest observation

Oct 12, 2026OpenAI APIWeb search: off

Converting HTML to PDF reliably depends a lot on what “HTML” means in your case:

  • simple, static HTML/CSS
  • modern web pages with JS rendering
  • invoices/documents with precise print layout
  • server-side generation at scale

Here are the most reliable approaches.

1) Use a browser engine for best fidelity

For most cases, the most reliable option is to render HTML in a real browser engine and print to PDF.

Good options

  • Headless Chrome / Chromium
    • Tools: Puppeteer (Node.js), Playwright
    • Best for modern CSS, web fonts, flexbox/grid, SVG, and JS-rendered content
  • WebKit-based rendering
    • Sometimes useful if your target environment is Safari-like

Why this is reliable

Browsers are the real HTML/CSS renderers, so the PDF output matches what users see.

Example with Puppeteer

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: true,
  args: ['--no-sandbox']
});
const page = await browser.newPage();
await page.goto('file:///path/to/document.html', { waitUntil: 'networkidle0' });
await page.pdf({
  path: 'output.pdf',
  format: 'A4',
  printBackground: true,
  margin: {
    top: '20mm',
    bottom: '20mm',
    left: '15mm',
    right: '15mm'
  }
});
await browser.close();

2) Use print CSS

If you want the PDF to look good, add a dedicated print stylesheet.

Key things to include

  • @media print
  • page size and margins with @page
  • hide navigation/buttons
  • avoid splitting important blocks across pages

Example:

@media print {
  body {
    margin: 0;
    font-size: 12pt;
  }

  .no-print {
    display: none !important;
  }

  @page {
    size: A4;
    margin: 20mm;
  }

  h1, h2, h3 {
    page-break-after: avoid;
  }

  .section {
    break-inside: avoid;
  }
}

3) Wait for all assets before generating PDF

A common source of unreliability is timing.

Make sure:

  • fonts are loaded
  • images are loaded
  • JS-rendered content is complete
  • any API calls are finished

For Puppeteer/Playwright, use something like:

  • waitUntil: 'networkidle0'
  • explicit waits for selectors
  • font loading checks

Example:

await page.goto(url, { waitUntil: 'networkidle0' });
await page.evaluate(() => document.fonts.ready);

4) Prefer absolute or fully resolvable asset URLs

Relative paths often fail in PDF generation.

Use:

  • absolute URLs
  • embedded data URIs for small images/icons
  • local file access only if the tool is configured for it

5) Avoid layout features that don’t print well

Even with a browser engine, some things can be tricky:

  • huge tables
  • fixed-position headers/footers
  • complex flex/grid layouts spanning pages
  • absolutely positioned elements
  • content that depends on viewport size
  • page breaks inside transformed elements

For long documents, table pagination and page headers/footers need special handling.

6) For high-volume or enterprise use, consider dedicated rendering tools

If you need a server-side API or batch conversion, good options include:

  • PrinceXML — very high quality for print/PDF
  • Antenna House
  • DocRaptor — hosted API using Prince
  • WeasyPrint — good for simpler HTML/CSS, especially Python workflows

These can be more predictable for paginated documents than a browser, especially with advanced page styling.

7) Common pitfalls

  • Missing fonts
  • CORS issues on images/fonts
  • CSS loaded too late
  • Page size defaults not set
  • Browser sandbox issues in containers
  • Different results between local and production environments

Practical recommendation

  • Need modern HTML/CSS/JS fidelity? Use Playwright or Puppeteer
  • Need print-perfect documents and can pay for it? Use PrinceXML/DocRaptor
  • Need Python and simpler documents? Try WeasyPrint

If you want, I can give you:

  1. a Node.js example using Puppeteer or Playwright,
  2. a Python example, or
  3. a recommended setup for invoices/reports.

Observation history

How did Obsurfable measure this prompt?

Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.

Which AI systems does Obsurfable collect answers from?

OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, Meta AI, Qwen.

How can brands improve their AEO?

Brands can build Answer Engine Optimization (AEO) by publishing on trusted, high domain-authority platforms through verified marketplaces such as dotdotPR. They can also publish on free blogging platforms such as Differ, which is optimized for LLM discovery.

Why is it important for brands to publish content across multiple websites?

Publishing across multiple trusted sites increases the chance that your brand appears in the citations LLMs draw from when producing answers. Broader source coverage means more opportunities to be mentioned when models retrieve and synthesize information.

Want this interpreted for your brand?

Explorer is the free public corpus. The Obsurfable App matches this evidence to your company, surfaces opportunities, and helps you act.