> ## 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.

# Asset Loading

> Control how fonts, images, and stylesheets load during PDF rendering.

## The problem

PDF rendering depends on external assets: fonts, images, stylesheets. Any of these can fail, be slow, or load in the wrong order — causing blank areas, wrong fonts, or broken layouts.

PDFBase gives you explicit control over asset loading behavior.

## wait\_until

Controls when PDFBase considers the page "ready" to capture:

| Value              | Waits for                                  | Best for                             |
| ------------------ | ------------------------------------------ | ------------------------------------ |
| `domcontentloaded` | HTML parsed, no external resources         | Simple HTML without external assets  |
| `load`             | All resources loaded (images, fonts, etc.) | Standard pages with known assets     |
| `networkidle`      | No network requests for 500ms              | JavaScript-heavy pages, SPAs, charts |

Default: `networkidle` (safest, slightly slower).

```json theme={null}
{ "html": "...", "wait_until": "networkidle" }
```

## wait\_for\_selector

Wait for a specific CSS selector to appear before capturing. Useful when JavaScript dynamically creates content:

```json theme={null}
{
  "url": "https://your-app.com/report",
  "wait_for_selector": "#chart-rendered",
  "wait_until": "load"
}
```

In your app, set a flag when content is ready:

```javascript theme={null}
// In your report page
renderChart(data).then(() => {
  document.getElementById('chart-rendered').style.display = 'block'
})
```

## wait\_for\_timeout

Add a fixed delay after `wait_until` fires. Use as a last resort when there's no reliable signal:

```json theme={null}
{
  "html": "...",
  "wait_until": "networkidle",
  "wait_for_timeout": 2000
}
```

<Warning>
  Fixed delays are fragile. Prefer `wait_for_selector` when possible — it's both faster (no unnecessary waiting) and more reliable (doesn't break if load time varies).
</Warning>

## resource\_timeout

Max time to wait for each individual resource. Resources that exceed this are skipped:

```json theme={null}
{
  "html": "...",
  "resource_timeout": 15000
}
```

Default: 10,000ms (10 seconds).

## skip\_failed\_resources

Controls behavior when a resource fails to load:

* `true` (default): Continue rendering. The PDF will have missing images or fallback fonts, but it will generate.
* `false`: Fail the entire request. Returns an error listing the failed resources.

```json theme={null}
{
  "html": "...",
  "skip_failed_resources": false
}
```

Use `false` for templates where every asset is critical (e.g., a branded certificate where the logo must be present).

## Font loading

### Google Fonts

Just link them in your HTML. They load automatically:

```html theme={null}
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
```

### Bundled fonts

PDFBase includes 6 high-quality font families that don't require any network loading:

* **Inter** — Clean sans-serif (body text)
* **JetBrains Mono** — Monospace (code)
* **Merriweather** — Serif (documents)
* **Noto Sans** — Wide Unicode coverage (internationalization)
* **Noto Sans CJK** — Chinese, Japanese, Korean
* **Noto Sans Arabic** — Arabic script

Use these for fastest rendering and no font-loading risk.

### Fallback behavior

When a custom font fails to load (network error, timeout, 404), PDFBase automatically falls back to the closest bundled font based on the CSS `font-family` stack:

| Your CSS                                | Fallback chain                            |
| --------------------------------------- | ----------------------------------------- |
| `font-family: 'BrandFont', sans-serif`  | BrandFont → Inter → Noto Sans             |
| `font-family: 'CustomSerif', serif`     | CustomSerif → Merriweather → Noto Sans    |
| `font-family: 'CodeFont', monospace`    | CodeFont → JetBrains Mono → Noto Sans     |
| `font-family: 'ArabicFont', sans-serif` | ArabicFont → Noto Sans Arabic → Noto Sans |
| `font-family: 'CJKFont', sans-serif`    | CJKFont → Noto Sans CJK → Noto Sans       |

The fallback is CSS-standard: PDFBase follows your `font-family` stack, substituting the first available bundled font that matches the generic family. If no generic family is specified, Inter is the final fallback.

**To see which font was actually used**, enable `debug: true`. The console output will log any font substitution:

```json theme={null}
{
  "debug": {
    "console": [
      { "level": "warn", "message": "Font 'BrandFont' not found, falling back to 'Inter'" }
    ]
  }
}
```

<Tip>
  Always include a generic family (`sans-serif`, `serif`, `monospace`) at the end of your `font-family` stack. This ensures predictable fallback behavior and matches how browsers handle missing fonts.
</Tip>

### Custom fonts

Host your font files on a CDN and use `@font-face`:

```css theme={null}
@font-face {
  font-family: 'BrandFont';
  src: url('https://your-cdn.com/fonts/brand.woff2') format('woff2');
}
```

<Tip>
  Use `.woff2` format for smallest file size and fastest loading. Avoid `.ttf` — it's 2-3x larger.
</Tip>

## Image loading

### Inline images (base64)

For critical images that must always appear, embed them as base64:

```html theme={null}
<img src="data:image/png;base64,iVBORw0KGgo..." />
```

Trade-off: larger HTML payload, but zero network risk.

### Remote images

For non-critical images, use URLs. Pair with `resource_timeout` and `skip_failed_resources`:

```json theme={null}
{
  "html": "<img src='https://cdn.example.com/photo.jpg'>",
  "resource_timeout": 5000,
  "skip_failed_resources": true
}
```
