Prompt
My HTML to PDF output is missing fonts, how do I troubleshoot it?
Latest observation
When HTML renders to PDF with missing or wrong fonts, the issue is usually one of these: font availability, font loading timing, CSS support, or PDF engine limitations. Here’s a practical way to troubleshoot it.
1) Confirm the font is actually available to the PDF renderer
Browsers and PDF tools don’t always share the same font environment.
- If you rely on system-installed fonts, make sure the machine/container running the converter has them installed.
- In Docker/Linux environments, fonts are often missing by default.
- Verify the exact font family name is installed and spelled correctly.
Check:
- Is the font installed on the host?
- Is it installed inside the container/VM?
- Does the PDF tool run under a different user or sandbox with limited access?
2) Use @font-face with explicit font files
Don’t depend only on system fonts if you need consistent PDF output.
@font-face {
font-family: "MyFont";
src: url("/fonts/MyFont-Regular.woff2") format("woff2"),
url("/fonts/MyFont-Regular.woff") format("woff");
font-weight: 400;
font-style: normal;
}
body {
font-family: "MyFont", sans-serif;
}
Things to verify:
- The font URL is reachable from the renderer.
- Use absolute URLs if relative paths break in the PDF context.
- If rendering locally, make sure the PDF tool can access the file path.
- Some tools support only certain font formats. If
woff2fails, trywofforttf.
3) Make sure fonts load before generating the PDF
If the PDF is generated before web fonts finish loading, the renderer may fall back to default fonts.
In browser-based rendering:
await document.fonts.ready;
Or if you know the exact font:
await document.fonts.load('16px "MyFont"');
await document.fonts.ready;
If using Puppeteer/Playwright:
- Wait for network idle or explicitly wait for fonts.
- Sometimes an extra delay is needed, especially with remote font files.
4) Check whether your PDF engine supports the font format
Different HTML-to-PDF tools have different support:
- Chrome/Puppeteer/Playwright: generally good support for web fonts
- wkhtmltopdf: more limited and can be picky
- WeasyPrint: supports fonts via Pango/Cairo, usually works well with proper font config
- PrinceXML / Antenna House: excellent support, but still requires correct paths/config
If a font works in the browser but not in PDF, the engine may not support:
woff2- certain OpenType features
- variable fonts
- remote fonts behind redirects/authentication
5) Inspect the generated PDF
Check whether the font is embedded or substituted.
Tools:
- Adobe Acrobat / Preview font properties
pdffontson Linux:pdffonts output.pdf
This tells you:
- whether fonts are embedded
- whether they are subsetted
- whether substitution occurred
If you see substitution, the font wasn’t embedded properly.
6) Verify CSS fallback behavior
If the font fails, the browser may silently use fallback fonts.
Example:
font-family: "MyFont", Arial, sans-serif;
If MyFont is missing, the PDF may use Arial or another fallback. This can make the issue look like “missing fonts” when it’s actually substitution.
7) Watch for CSS that breaks font use
Some CSS can interfere:
font-weightvalues that don’t match the loaded facefont-style: italicwithout a matching italic font fileunicode-rangeexcluding characters you needfont-display: swapcausing fallback if rendering is too early
Make sure you have:
- regular
- bold
- italic
- bold italic
if your document uses all four.
8) Test with a minimal reproduction
Strip the page down to the smallest case:
<!doctype html>
<html>
<head>
<style>
@font-face {
font-family: "MyFont";
src: url("https://example.com/fonts/MyFont-Regular.ttf") format("truetype");
}
body { font-family: "MyFont", sans-serif; font-size: 24px; }
</style>
</head>
<body>
The quick brown fox jumps over the lazy dog.
</body>
</html>
If this works, add complexity back gradually:
- images
- CSS framework
- JavaScript
- dynamic content
- headers/footers
9) If using containers, install fonts and rebuild cache
For Linux containers, fonts may need to be installed and cached.
Examples:
- install
fontconfig - install the needed font packages
- rebuild font cache:
fc-cache -f -v
Then verify:
fc-list | grep -i "MyFont"
10) Check CORS / authentication if fonts are remote
If fonts are hosted on another domain, the renderer may not fetch them due to:
- CORS restrictions
- auth requirements
- blocked cookies
- expired signed URLs
Best practice:
- serve fonts from the same origin
- or embed them as local files/base64 if appropriate
11) Consider embedding fonts directly
If portability matters, embedding fonts can eliminate many issues.
Options:
- use local file paths
- use base64-encoded font data in CSS
- use a PDF engine with robust font embedding support
12) Common symptom-to-cause clues
- Works in browser, fails in PDF → PDF engine/font loading issue
- Only some characters missing → font lacks glyphs, wrong subset, or encoding issue
- Bold/italic missing → those font faces weren’t provided
- Works locally, fails in CI/server → fonts missing in environment
- Remote font works sometimes → timing/network/auth issue
Quick checklist
- Font installed on rendering machine/container
-
@font-faceuses correct URL/path - PDF generator supports the font format
- Fonts are loaded before PDF generation
- Proper font weights/styles exist
- Fonts are embedded/subset correctly
- No CORS/auth/network issues
- Test with minimal HTML
If you tell me which HTML-to-PDF tool you’re using (Puppeteer, wkhtmltopdf, WeasyPrint, Prince, etc.) and how fonts are loaded, I can give more specific troubleshooting steps.