CloudPDF
DocsPricing
Start building

Fallback fonts

When a PDF references a font it doesn’t embed, or a FreeText annotation needs a glyph its chosen font lacks, the server falls back to its own fonts to draw the missing characters. Out of the box that’s the standard Latin set — to cover CJK, Cyrillic, Arabic, or any other script, configure fallback fonts on the server.

This is a server-side decision on purpose. Cloud clients can’t register fonts (the client engine.fonts API is local-engine only); the deployment owns the font policy and applies it uniformly to every render and every saved annotation appearance. The local engine has its own Custom fonts API for the in-browser case.

Configure with CLOUDPDF_FALLBACK_FONTS#

Set a JSON array of font descriptors. Each needs a stable key and a path to a TTF/OTF file readable by the server process:

CLOUDPDF_FALLBACK_FONTS='[
  { "key": "noto-sc", "path": "/srv/fonts/NotoSansSC-Regular.otf", "familyName": "Noto Sans SC" },
  { "key": "noto-arabic", "path": "/srv/fonts/NotoNaskhArabic-Regular.ttf" }
]'
FieldRequiredDescription
keyyesStable id for the font.
pathyesAbsolute path to a TTF/OTF file the server can read.
familyNamenoBase font name; inferred from the file if omitted.
weightnoStyle weight (100–900) for matching; inferred if omitted.
italicnoItalic flag for matching; inferred if omitted.
fallbacknoEnroll for automatic missing-glyph fill. Defaults to true.

Order matters: fonts are tried as fallbacks in the order listed, so put your preferred faces first.

Fonts are loaded by path and range-read on demand — the bytes are never held resident in memory. You can configure several large CJK families and each costs a file handle, not RAM per font. Make sure the paths are present in your container image or mounted volume and readable by the server user.

A font that can’t be read or parsed fails worker startup — a bad font config is a boot error, not a silent degrade. Check the path and the file on a startup failure.

How it applies#

Each PDFium worker thread registers the fallback fonts on startup, before it serves any request (the runtime is thread-confined, so every worker holds its own copy). From then on, any glyph a document’s fonts can’t draw — during page rendering or when generating an annotation’s appearance on save — is filled from the first fallback font that covers it.

Embedding via buildApp#

If you embed the server with buildApp instead of running the CLI, pass the same descriptors programmatically:

import { buildApp, loadFallbackFontsFromEnv } from '@cloudpdf/server';
 
const { app } = await buildApp({
  workerEntry,
  fallbackFonts: [
    { key: 'noto-sc', path: '/srv/fonts/NotoSansSC-Regular.otf', familyName: 'Noto Sans SC' },
  ],
  // …or reuse the env convention: fallbackFonts: loadFallbackFontsFromEnv(),
});