← Back to blog

Your PDF's "standard fonts" aren't embedded — and when that matters

Helvetica in a PDF is usually a promise, not a font. Why viewer substitution is fine for invoices, fatal for PDF/A and PDF/UA, and how metric-compatible embedding fixes it without moving a single glyph.

Open almost any programmatically-generated PDF that uses Helvetica, Times, or Courier and look at its font resources. There's a good chance the font isn't there. The file just says "Helvetica" and every conformant viewer promises to supply something metrically identical — Arial, Liberation Sans, Helvetica Neue, whatever the platform has.

This isn't a bug. It's a 30-year-old feature: the PDF spec defines 14 standard fonts every viewer must support, so documents can reference them by name and stay small. Forme's built-in fonts work exactly this way, and for the everyday invoice or report it's the right trade — smaller files, instant rendering, identical layout, because substitution is done against published metrics.

When the promise isn't enough

Two document classes reject the promise outright:

PDF/A (archival) exists so a file opened in 2056 renders exactly as it did in 2026. A reference to a font the viewer must supply is a dependency on the future — precisely what archival forbids. PDF/A requires every font embedded, no exceptions.

PDF/UA (accessibility) requires embedded fonts too, for reliable text extraction and rendering under assistive technology.

So the moment you write pdfa="2b" or pdfUa, "Helvetica by reference" stops being an option. And here's the trap most PDF libraries set: they'll happily embed some other font you registered — changing metrics, reflowing text, moving page breaks — so your archival document doesn't lay out like the one you proofread.

Metric-compatible embedding

@formepdf/fonts-standard resolves this with metric-compatible TrueType replacements (the Liberation family) for the standard fonts:

import { standardFonts } from '@formepdf/fonts-standard';

<Document pdfa="2a" pdfUa lang="en-US" fonts={standardFonts()}>

</Document>

Metric-compatible means every glyph advance matches the published standard-font metrics — so line breaks, page breaks, justified spacing, and table geometry are identical between your normal output and your archival output. The document you previewed is the document you archive. Forme's CI enforces this: the compliance corpus renders geometry-identical with and without embedding, and every file is validated by veraPDF against PDF/A-2b, PDF/A-2a, and PDF/UA-1 on every commit.

The refusal is the feature

One more design decision worth stating plainly: if you request PDF/A and a font in the document can't be embedded, Forme fails the render with a named error telling you which font and how to fix it.

The alternative — what you get from tooling that treats compliance as metadata — is a file whose XMP claims PDF/A conformance while its font resources violate it. That file passes your smoke test, gets accepted by your document pipeline, and fails the day an auditor runs veraPDF on it. We know how that story goes because we lived a version of it: Forme's own pre-0.16 PDF/A output carried an invalid ICC profile that nothing caught, because nothing validated. Never again — refuse loudly at render time, or pass veraPDF.

verapdf -f 2b your-file.pdf tells you in seconds which kind of file you're holding.

Docs