Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
font embedding

Web Fonts in Generated PDFs: Loading, Fallbacks, Puppeteer Timing, and Licensing

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Web fonts become part of a generated PDF only when the rendering browser can load and use the requested font face at capture time, and when the resulting PDF is allowed to contain and distribute that font. In Puppeteer, page.pdf() renders with print CSS and, by default, waits for document.fonts.ready. A missing font resource, mismatched family or weight, unsupported print path, or an unsuitable license can still produce a PDF that looks different from the web page or cannot legally be shared.

What “embedding a web font” means

CSS declares a font face with @font-face, including its family name, source files, weight, style, and optional descriptors. MDN describes @font-face as a way to load a custom font from a remote server or a font installed locally on the rendering computer. WOFF2 is generally a practical web-delivery default because it is compact and broadly supported by modern browsers.

During PDF generation, the browser lays out text, resolves each character to an available face, and produces PDF font data when its PDF pipeline supports doing so. If the requested face is unavailable, the browser can select another face from the CSS font-family fallback list. The PDF may therefore contain a fallback rather than the font you intended. A successful HTTP response for a font file does not by itself prove that the PDF used that face or that distribution is licensed.

Keep three decisions separate:

  • Loading: can the renderer reach and decode the font resource?
  • Rendering: does the browser use the requested family, weight, and style for print output?
  • Rights: does the font license permit embedding and the planned sharing, editing, or commercial use?

How Puppeteer handles fonts when generating a PDF

Puppeteer’s PDF guide states: “By default, page.pdf() waits for fonts to be loaded.” Its API exposes a waitForFonts option that waits for document.fonts.ready. The method generates a PDF using print CSS by default, so print-only rules can change typography, visibility, colors, and layout. See the Puppeteer PDF generation guide and the Page.pdf() API reference.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not assume this behavior applies identically to every browser, wrapper, operating system, or PDF engine. If your code changes waitForFonts, starts capture in a custom lifecycle, or uses a different renderer, explicitly wait for the font-loading state before creating the PDF.

Minimal Puppeteer example

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/invoice', { waitUntil: 'networkidle0' });

// Optional explicit check when your capture flow needs one.
await page.evaluate(async () => {
  await document.fonts.ready;
});

await page.pdf({
  path: 'invoice.pdf',
  format: 'A4',
  printBackground: true,
  waitForFonts: true
});
await browser.close();

The explicit document.fonts.ready check is useful when other application code controls capture timing. It is not a substitute for making the font URL reachable or for checking the generated file.

Define the font face so the renderer can use it

Declare every face you actually use. A browser can synthesize a bold or italic style when a matching file is absent, but synthetic styling is not the same as loading the intended face.

@font-face {
  font-family: 'Acme Sans';
  src: url('https://cdn.example.com/fonts/acme-sans-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: 'Acme Sans';
  src: url('https://cdn.example.com/fonts/acme-sans-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: block;
}

body { font-family: 'Acme Sans', Arial, sans-serif; }
strong { font-weight: 700; }

Use the same family spelling and numeric weight in your elements and in the face descriptors. If your page uses a relative font URL, confirm that the document URL resolves it correctly in the headless browser. For HTML generated in memory, an absolute URL or a data URL can avoid an unexpected base path.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why is my custom font not showing in my generated PDF?

Work through the causes in this order:

1. The font request failed

Private network addresses, authentication requirements, certificate errors, content-security rules, DNS failures, and cross-origin restrictions can prevent the browser from obtaining the file. Inspect requests and browser console messages, and ensure the Puppeteer process has the same network access as a normal user. A font URL that works in your desktop browser may be inaccessible from a container or CI runner.

2. The family, weight, or style does not match

Check that the CSS uses the exact family name declared in @font-face, and that a requested font-weight or font-style has a corresponding face. A page requesting 600 while only 400 is declared can select another face or synthesize one.

3. Capture occurred before the face was ready

Wait for document.fonts.ready and retain Puppeteer’s waitForFonts: true. Also wait for the page’s data and layout to settle; font readiness does not mean images, client-rendered content, or late CSS have finished changing the page.

4. Print CSS selects a different rule

page.pdf() uses print media by default. A @media print rule may replace the family, hide text, alter size, or apply a different stylesheet. Use await page.emulateMediaType('screen') only when screen styling is intentionally required; otherwise design and test the print stylesheet.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. The renderer does not support that face for printing

Adobe documents that unsupported web-font printing can use the declared fallback stack. A browser may display the web font on screen yet choose a fallback in its print/PDF path. Do not promise identical results across engines based only on Puppeteer documentation.

6. The PDF viewer substitutes a font

Open the file in the viewers your recipients use, not only in the browser that generated it. Check the actual language, accents, symbols, and weights in the document. A viewer can report a substitute when embedded data is missing, incomplete, or unusable.

How do I wait for fonts before Puppeteer generates a PDF?

The documented default is to wait, but an explicit wait makes custom workflows clear:

await page.goto(url, { waitUntil: 'networkidle0' });
await page.evaluate(async () => {
  await document.fonts.ready;
  // Optional: fail fast if a required face is not usable.
  if (!document.fonts.check('400 16px "Acme Sans"')) {
    throw new Error('Acme Sans regular face is not available');
  }
});
await page.pdf({ path: 'output.pdf', waitForFonts: true, printBackground: true });

document.fonts.check() is a useful diagnostic, but it should be interpreted alongside network logs and the output PDF. It can confirm that the browser considers a face available; it does not establish licensing or guarantee every glyph in your content exists.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How to verify the generated PDF before distribution

  1. Check the source: confirm the expected @font-face URL, family, weight, and style in the HTML delivered to Puppeteer.
  2. Check readiness: record whether document.fonts.ready completed and whether required faces pass document.fonts.check().
  3. Check print output: inspect print-media rules and compare a representative page with the intended design.
  4. Check real text: test every language, accented character, symbol, numeral, and bold/italic combination used in the document.
  5. Check multiple viewers: open the PDF in the target desktop and browser viewers and look for substitutions, missing glyphs, reflow, and changed line breaks.
  6. Check embedding information: use your PDF inspection tool to see whether the expected font data is embedded and whether subsets are present. Treat that as technical evidence, not legal clearance.

Can I distribute a PDF with a web font?

Only after checking the font’s actual license for the intended distribution. Technical embedding, metadata permissions, and contractual rights are different questions.

Adobe Fonts’ guidance, last updated July 11, 2023, says: “Printing a page that uses web fonts is allowed, provided the printout is for personal use only,” and directs users to licensing terms for PDFs and EPS files made available to users. That is Adobe’s policy guidance, not a universal rule for every foundry, subscription, country, or renderer.

Adobe’s developer guide cautions: “The policies presented in this document do not guarantee that font usage will be in legal compliance with font vendor license agreements.” The PDF 1.7 reference likewise explains that embedded font programs are subject to copyright-owner conditions and, absent contrary information, may be restricted to viewing and printing. Read the license supplied by the foundry or service for your exact font and planned audience. If recipients must edit the PDF, distribute source files, or extract text for a product, those uses may require permissions beyond ordinary viewing.

Relevant references are Adobe’s printing web fonts guidance, Adobe’s Font Embedding Guidelines, and the PDF 32000-1:2008 reference text.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance, reliability, and cost considerations

  • Use WOFF2 where supported: its smaller transfer size can reduce startup time, while retaining a fallback for environments that cannot decode it.
  • Limit faces and subsets: load only the weights, styles, and character ranges the document needs. Verify that required scripts and symbols are included.
  • Cache stable font files: immutable, versioned URLs reduce repeated downloads in long-running workers.
  • Control network waits: networkidle0 can be slow on pages with persistent connections. Combine a sensible navigation policy with an explicit font readiness check rather than waiting indefinitely.
  • Use deterministic assets: self-hosting or authenticated asset delivery can improve reproducibility, but it does not change the license terms.
  • Fail visibly: if a required face is unavailable, log and stop rather than silently distributing a document with changed line breaks.

Common errors and fixes

“The PDF uses Arial even though the page looks correct”

Inspect print CSS, verify the font request in the capture environment, and check the requested weight/style. Then wait for document.fonts.ready before calling page.pdf().

“Fonts load locally but not in CI”

Compare DNS, certificates, proxy settings, credentials, container fonts, and file permissions. Capture browser console and request failures in CI; do not rely on your workstation’s network or installed fonts.

“Only bold text falls back”

Declare a 700 face (or the exact weight used), confirm its URL and format, and ensure the CSS does not request a weight outside the declared range.

“The PDF has boxes for characters”

The chosen face may lack those glyphs, or the fallback chain may not provide them. Test the actual text and add a licensed face covering the required script and symbols.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“The file renders, but sharing it is questioned”

Rendering success and embedding metadata do not prove distribution rights. Retrieve the font license and ask the vendor about PDF embedding, audience, editing, and commercial distribution when the terms are unclear.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo can return a screenshot or PDF from one GET request, useful when you need a rendered page without maintaining a Puppeteer worker. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with the response identifying the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/invoice -o invoice.pdf

See the ScreenshotNeo API documentation for output and options. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Sign up free to try it.

FAQ

Does a WOFF2 file guarantee that the PDF embeds the font?

No. WOFF2 describes a web-delivery format. The renderer must load and use it, its PDF pipeline must preserve font data, and the license must permit the planned embedding and distribution.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is networkidle0 enough to guarantee correct typography?

No. It is a navigation wait condition, not a proof that the required face is usable. Check document.fonts.ready, required faces, print CSS, and the output file.

Should I use screen or print media for PDF generation?

Use print media when the document is designed for printing, which is Puppeteer’s default. Emulate screen media only when reproducing screen styling is an intentional requirement.

Can a PDF contain a subset instead of the complete font?

PDF producers commonly embed only glyphs needed by the document, but the exact subset and permissions depend on the renderer and font. Inspect the file and consult the license rather than assuming a subset is unrestricted.

Frequently Asked Questions

Does a WOFF2 file guarantee that the PDF embeds the font?

No. WOFF2 describes a web-delivery format; loading, PDF support, and license terms still determine the result.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is networkidle0 enough to guarantee correct typography?

No. Also wait for document.fonts.ready and verify faces, print CSS, and the output PDF.

Should I use screen or print media for PDF generation?

Use print media for print-oriented documents; Puppeteer uses it by default. Choose screen media only deliberately.

Can a PDF contain a subset instead of the complete font?

It can, depending on the producer, but inspect the file and license before relying on that behavior.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.