> ## Documentation Index
> Fetch the complete documentation index at: https://pdfbase.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# HTML to PDF

> Everything you need to know about generating PDFs from HTML content.

## How it works

PDFBase loads your HTML into a headless Chromium browser, renders it exactly as Chrome would, and captures the result as a PDF. This means full support for:

* CSS Grid, Flexbox, `@media print`
* Web fonts (Google Fonts, custom `@font-face`)
* SVG, Canvas, inline images
* JavaScript execution (charts, dynamic content)
* CSS `page-break-before`, `page-break-after`, `page-break-inside`

## Basic usage

```bash theme={null}
curl -X POST https://api.pdfbase.dev/v1/pdfs \
  -H "Authorization: Bearer pk_live_xxx" \
  -d '{"html": "<h1>Hello World</h1>", "output": "url"}'
```

## Full HTML document

For production use, send a complete HTML document with `<!DOCTYPE html>`, `<head>`, and styles:

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: 'Inter', sans-serif; padding: 40px; color: #1a1a1a; }
    h1 { font-size: 24px; margin-bottom: 20px; }
    table { width: 100%; border-collapse: collapse; margin-top: 20px; }
    th { text-align: left; padding: 8px; border-bottom: 2px solid #333; font-weight: 600; }
    td { padding: 8px; border-bottom: 1px solid #eee; }
    .total { font-weight: 700; font-size: 18px; text-align: right; margin-top: 20px; }

    @media print {
      body { padding: 0; }
      table { page-break-inside: avoid; }
    }
  </style>
</head>
<body>
  <h1>Invoice #001</h1>
  <table>
    <thead><tr><th>Item</th><th>Qty</th><th>Price</th></tr></thead>
    <tbody>
      <tr><td>Widget</td><td>10</td><td>$50.00</td></tr>
      <tr><td>Gadget</td><td>5</td><td>$75.00</td></tr>
    </tbody>
  </table>
  <p class="total">Total: $875.00</p>
</body>
</html>
```

## Page breaks

Control where pages break using CSS:

```css theme={null}
/* Force a page break before this element */
.new-section { page-break-before: always; }

/* Prevent a table from being split across pages */
table { page-break-inside: avoid; }

/* Keep headings with their content */
h2 { page-break-after: avoid; }
```

## Headers and footers

Headers and footers are rendered separately from the main content and appear on every page:

```json theme={null}
{
  "html": "<h1>Report</h1>...",
  "header": {
    "html": "<div style='font-size:10px;width:100%;text-align:right;padding:5px 20px;'><span class='date'></span></div>",
    "height": "20mm"
  },
  "footer": {
    "html": "<div style='font-size:10px;width:100%;text-align:center;padding:5px;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",
    "height": "15mm"
  }
}
```

### Special CSS classes in headers/footers

| Class        | Replaced with       |
| ------------ | ------------------- |
| `date`       | Current date        |
| `title`      | Document title      |
| `url`        | Page URL            |
| `pageNumber` | Current page number |
| `totalPages` | Total page count    |

<Warning>
  Headers and footers cannot reference styles or scripts from the main HTML body. They render in a separate context. Include all styles inline.
</Warning>

## Web fonts

Google Fonts load automatically. For custom fonts, use `@font-face` with a publicly accessible URL:

```html theme={null}
<style>
  @font-face {
    font-family: 'BrandFont';
    src: url('https://your-cdn.com/fonts/brand.woff2') format('woff2');
    font-weight: 400;
  }
  body { font-family: 'BrandFont', sans-serif; }
</style>
```

<Tip>
  Use `wait_until: "networkidle"` (the default) to ensure all fonts finish loading before capture. If a font takes too long, `resource_timeout` will skip it and fall back to the next font in the stack.
</Tip>

## From a URL

Instead of sending HTML, point PDFBase at a live URL:

```json theme={null}
{
  "url": "https://your-app.com/reports/monthly?token=abc",
  "wait_for_selector": "#report-ready",
  "format": "letter"
}
```

The URL is loaded in Chromium and rendered identically to how it appears in Chrome. Pass a `wait_for_selector` to wait for dynamic content to finish loading.

## Print-optimized CSS

Add a `@media print` block to adjust styling for PDF output:

```css theme={null}
@media print {
  .no-print { display: none; }    /* hide navigation, buttons */
  body { font-size: 12pt; }        /* use print-friendly sizes */
  a { color: #000; text-decoration: none; } /* de-emphasize links */
  * { -webkit-print-color-adjust: exact; }  /* preserve background colors */
}
```

## Common pitfalls

| Problem                   | Cause                                    | Fix                                                       |
| ------------------------- | ---------------------------------------- | --------------------------------------------------------- |
| Blank PDF                 | JavaScript renders content after capture | Use `wait_for_selector` or `wait_for_timeout`             |
| Missing fonts             | Font CDN is slow or blocked              | Use `resource_timeout: 15000` and test with `debug: true` |
| Content cut off           | No page break hints                      | Add `page-break-inside: avoid` to key elements            |
| Background colors missing | Chromium strips backgrounds by default   | Add `-webkit-print-color-adjust: exact`                   |
| Oversized file            | High-res images not compressed           | Use `compress: "medium"` or pre-optimize images           |
