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

If a Puppeteer PDF created in Docker shows blank squares, missing letters, or glyphs that look different from your browser screenshot, start by checking fonts inside the container. A CSS font-family declaration does not install that font. The usual container-specific causes are missing coverage for the affected script, Linux font fallback to another family, or a font that has not loaded when print output is generated. Reproduce the exact characters, identify their script, inspect the runtime image, then verify print CSS and font readiness.

1. Reproduce the exact failure first

Do not begin by adding random delays or disabling Chrome’s sandbox. Create a minimal page containing the characters that fail in production, including punctuation, combining marks, emoji, or symbols. Keep the same Docker image, Chromium build, locale, Puppeteer version, and URL-loading code used by the application.

const html = `


Japanese: 日本語 中文: 中文 ไทย: ไทย ខ្មែរ: ខ្មែរ

Arabic: العربية Hebrew: עברית Symbols: € ✓ — —

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Brother DCP-L2640DW Wireless Compact Monochrome Multi-Function Printer, Copy, Scan, Duplex, Mobile Printing
  • BEST FOR SMALL BUSINESSES – Engineered for extraordinary productivity, the Brother DCP-L2640DW Monochrome (Black & White) 3-in-1 combines laser printer, scanner, copier in one compact footprint and delivers high-quality black & white prints
  • FAST PRINTER WITH EFFICIENT SCANNING – Produces documents quickly with print speeds up to 36 ppm(2) and scan speeds up to 23.6/7.9 ipm(3) (black/color). A 50-page auto document feeder(4) allows for convenient, time saving multi-page scanning and copying
  • FLEXIBLE CONNECTION OPTIONS – Easily navigate the changing demands of your business with secure multi-device connectivity via built-in dual-band wireless (2.4GHz / 5GHz) and Ethernet. Or connect locally to a single computer via USB interface
  • BROTHER MOBILE CONNECT APP – Print, scan, and manage your wireless printer anytime, from almost anywhere from your mobile device. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(5)
  • CHOOSE BROTHER GENUINE TONER – When it’s time to replace your toner, be sure to choose Brother Genuine TN830 or TN830XL replacement toner. And with Refresh EZ Print Subscription Service, you’ll never worry about running out of toner again and you’ll enjoy savings of up to 50%(6) on Brother Genuine Toner. Get started with Refresh today with a Free Trial(1)
`;

Render this HTML both as a browser screenshot and as a PDF from the same container. If the screenshot is already wrong, investigate fonts and CSS before PDF settings. If the screenshot is correct but the PDF differs, inspect print media rules, font loading, and the PDF viewer.

2. Confirm which font and script are actually required

Identify the requested family

Inspect the computed font-family for the failing element, including print styles. A declaration such as font-family: "Noto Sans CJK JP" only requests a family; it does not copy font files into Linux. Fonts installed on your host operating system are not automatically present in Docker.

Identify the script and glyph coverage

Determine whether the missing text is Japanese, Chinese, Korean, Thai, Khmer, Arabic, Hebrew, a mathematical symbol, an emoji, or another script. A font can cover Latin characters while lacking the affected glyphs. Test the exact code points rather than assuming that “Unicode” is one coverage category.

Inspect the image that launches Chrome

Run font inspection commands in the runtime container, not merely in a build stage:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
fc-list | head
fc-match "Noto Sans"
fc-match ":lang=ja"
fc-match ":lang=ar"
locale

If fc-list is unavailable, install the distribution’s fontconfig utilities temporarily or inspect the package database. The important question is whether a usable font file exists in the final image and whether fontconfig can match it.

Rank #2
Brother HL-L2405W Wireless Compact Monochrome Laser Printer with Mobile Printing, Black & White Output | Includes Refresh Subscription Trial(1), Works with Alexa
  • BEST FOR HOMES & HOME OFFICES – Engineered for consistent, premium print quality, the Brother HL-L2405W Monochrome (Black & White) Laser Printer delivers sharp, crisp prints at an affordable price. Prints one-sided documents at speeds up to 30ppm(2)
  • COMPACT, CONNECTED PRINTER – Flexible connection options make this an ideal printer for home use and at-home offices. Securely connect to multiple devices with built-in dual-band wireless (2.4GHz/5GHz) or locally to a single computer via USB interface
  • BROTHER MOBILE CONNECT APP – Manage your printer remotely and print from your mobile device anytime, from almost anywhere. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(3)
  • VERSATILE PAPER HANDLING – Enjoy seamless, reliable everyday printing with the 250-sheet paper tray(4) and a manual feed slot that enables printing on envelopes and specialty pape
  • BROTHER IS AT YOUR SIDE – Backed by Brother with a 1-year limited warranty and free online, call, or live chat support for the life of your printer

3. Install script-appropriate fonts in Docker

Add fonts to the image that actually runs Puppeteer. Puppeteer’s maintained Dockerfile starts from a Node Bookworm image, sets LANG=en_US.UTF-8, and installs examples such as Japanese, Chinese, Thai, Khmer, Arabic/Hebrew coverage packages and FreeFont. Package names and contents vary by distribution, so select packages for your base image instead of copying a list blindly. See the maintained Puppeteer Dockerfile and its Linux and Docker troubleshooting guide.

# Debian/Ubuntu example; verify names for your release
RUN apt-get update 
 && apt-get install -y --no-install-recommends 
      fontconfig 
      fonts-ipafont-gothic 
      fonts-wqy-zenhei 
      fonts-thai-tlwg 
      fonts-khmeros 
      fonts-kacst 
      fonts-freefont-ttf 
 && rm -rf /var/lib/apt/lists/*

Those packages are examples covering several scripts, not a guarantee of complete Unicode support. Installing every available font increases image size and maintenance cost. Prefer the smallest set that covers your content and fallback requirements, then rebuild and run fc-match again.

System fonts versus web fonts

For a self-contained service, system fonts make rendering independent of external requests. If your page uses @font-face, make sure the font URL is reachable from the container, credentials are supplied when required, and the response is a real font rather than an HTML error page. You can also package the font files in the image and reference them with a local URL.

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.

4. Understand fallback and changed glyph shapes

Linux font matching can substitute another family when the requested face is absent or lacks a glyph. Chromium’s Linux PDF implementation delegates this kind of substitution to fontconfig; the result may render successfully but look unlike your design. The Chromium PDFium font helper source documents this implementation context.

Use an explicit fallback stack appropriate to your content:

Rank #3
Canon imageCLASS LBP6030w - Monochrome Single-Function Wireless Compact Wireless Laser Printer, 1 Year Limited Warranty, 19 PPM, White - Print Only
  • FAST PRINT SPEEDS: Print up to 19 pages per minute.
  • COMPACT DESIGN: Space-saving, compact design fits anywhere in your home, school or small office.
  • WIRELESS CONNECTIVITY: Print from almost anywhere in your workspace using your compatible mobile device.
  • PAPER CAPACITY: Up to 150 sheets.
  • SUSTAINABILITY: Uses less than 2 watts in Energy Saver mode.
body {
  font-family: "Noto Sans", "Noto Sans CJK JP", "Noto Sans Thai", sans-serif;
}

Do not assume that naming a family forces Chromium to use it. Verify the family is installed and contains the required glyphs. If appearance matters, embed and select the exact licensed font, and test representative characters from every script you publish.

5. Check Puppeteer’s PDF timing and print CSS

PDF uses print media

page.pdf() generates output using print CSS media. A print stylesheet can select a different family, hide text, alter writing direction, or change colors. Compare screen and print rules with:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.emulateMediaType('print');
console.log(await page.$eval('body', el => getComputedStyle(el).fontFamily));

Then inspect any @media print block and print-specific components.

Wait for fonts deliberately

In Puppeteer 25.12.0, page.pdf() waits for fonts by default. The PDFOptions waitForFonts option waits for document.fonts.ready and defaults to true; the documentation notes that bringing a background page to the foreground may be needed for this wait to resolve. See the PDFOptions interface and Page.pdf() documentation.

await page.goto(url, { waitUntil: 'networkidle0' });
await page.bringToFront();
await page.evaluate(() => document.fonts.ready);
await page.pdf({
  path: '/tmp/output.pdf',
  printBackground: true,
  waitForFonts: true
});

For older Puppeteer versions, confirm whether waitForFonts exists and what its default is. An arbitrary setTimeout is not a substitute for fixing a failed font request or a missing glyph.

Rank #4
Brother HL-L2460DW Wireless Compact Monochrome Laser Printer with Duplex, Mobile Printing, Black & White Output | Includes Refresh Subscription Trial(1), Works with Alexa
  • BEST FOR HOME OFFICES & SMALL TEAMS – Engineered for consistent, premium print quality, the Brother HL-L2460DW Monochrome (Black & White) Laser Printer produces documents that are clear, crisp, and easy to review and share, all at an affordable price
  • COMPACT, CONNECTED, EXCEPTIONALLY EFFICIENT– Connect with built-in dual-band wireless (2.4GHz/5GHz), Ethernet, or to a single computer via USB interface. Prints at speeds up to 36ppm(2), plus automatic duplex printing saves time and reduces paper waste
  • BROTHER MOBILE CONNECT APP – Manage your wireless printer remotely and print from your mobile device anytime, from almost anywhere. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(3)
  • VERSATILE PAPER HANDLING – Tackle high-volume black & white printing with the 250-sheet capacity paper tray.(4) The manual feed slot enables printing on envelopes and specialty paper
  • BROTHER IS AT YOUR SIDE – Backed by Brother with a 1-year limited warranty and free online, call, or live chat support for the life of your printer

Diagnose font requests

page.on('requestfailed', request => {
  console.error('Request failed:', request.url(), request.failure());
});
page.on('response', response => {
  if (response.url().match(/.(woff2?|ttf|otf)(?|$)/i)) {
    console.log('Font', response.status(), response.url());
  }
});

Check certificate errors, DNS, authentication, CORS policy, redirects, and content type. A network-idle wait can complete even when a font request failed.

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

6. Keep locale, browser dependencies, and fonts separate

The official Docker setup configures LANG=en_US.UTF-8 and installs browser dependencies. Locale controls text encoding and language behavior; it does not provide font files. A missing shared library can prevent Chrome from launching, while missing glyph coverage leaves Chrome running but produces a square or fallback character. Treat these as separate checks.

Use a maintained, version-compatible image and pin Puppeteer and Chromium versions together where possible. Consult Puppeteer’s troubleshooting documentation for required Linux libraries. Avoid using --no-sandbox as a font fix: Puppeteer discusses it as a separate security issue and strongly discourages running without a sandbox.

7. A complete minimal PDF test

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    args: []
  });
  try {
    const page = await browser.newPage();
    await page.setContent(`
      <meta charset="utf-8">
      <style>
        @font-face {
          font-family: TestFont;
          src: url("https://example.com/fonts/test.woff2") format("woff2");
        }
        @media print {
          body { font-family: TestFont, "Noto Sans", sans-serif; }
        }
        body { font-size: 22px; }
      </style>
      <p>日本語 中文 ไทย ខ្មែរ العربية עברית € ✓</p>`,
      { waitUntil: 'networkidle0' }
    );
    await page.bringToFront();
    await page.evaluate(() => document.fonts.ready);
    console.log(await page.evaluate(() => ({
      status: document.fonts.status,
      loaded: document.fonts.check('22px TestFont'),
      family: getComputedStyle(document.querySelector('p')).fontFamily
    })));
    await page.pdf({
      path: '/tmp/unicode-test.pdf',
      format: 'A4',
      printBackground: true,
      waitForFonts: true
    });
  } finally {
    await browser.close();
  }
})();

Replace the example font URL with a resource you control. A true result from document.fonts.check indicates that a face is available to the browser, not that it contains every glyph; the PDF still needs a font with coverage for each character.

8. Troubleshooting by symptom

Symptom Likely cause Fix
Blank square or tofu glyph No installed font covers the code point Identify the script, install a suitable package in the final image, rebuild, and verify with fc-match.
Text appears, but shape or metrics change Fontconfig substituted another family Install the requested family or an intentional fallback and verify computed print styles.
Browser screenshot is correct; PDF is wrong Print CSS selects another family or media-specific rule Emulate print media and inspect computed styles and @media print.
Web-font text intermittently falls back Font request failed or was not ready Log failed requests, check response status and credentials, await document.fonts.ready, and use the version-appropriate waitForFonts.
Chrome will not start Missing Linux shared library or sandbox configuration Install documented browser dependencies; do not treat --no-sandbox as a glyph solution.
Different viewers show different results Viewer font rendering or historical platform differences Inspect the PDF in more than one viewer and compare the embedded/output fonts. Puppeteer issue #3668 is an anecdotal report, not proof of a universal viewer defect.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

9. Validate the rebuilt artifact

  1. Rebuild without reusing an old image layer that omitted the font package.
  2. Run the minimal page and production template from the same container.
  3. Check the generated PDF in at least two viewers if the discrepancy is viewer-specific.
  4. Archive the exact Dockerfile, package versions, Puppeteer version, Chromium revision, and test string so future image updates can be compared.

Or skip the browser setup

If you only need a reliable website capture or PDF endpoint rather than maintaining Chrome and fonts yourself, ScreenshotNeo provides a GET API and an MCP server. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. AI agents can use its MCP tools take_screenshot, get_page_info, and capture_pdf.

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.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for PDF options, custom CSS and JavaScript, device and viewport settings, font-related page controls, asynchronous jobs, and webhooks. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Best Value
HP LaserJet M110w Wireless Black & White Printer, Print, Fast speeds, Easy Setup, Mobile Printing, Best-for-Small Teams
  • FROM AMERICA'S MOST TRUSTED PRINTER BRAND – Perfect for small teams printing professional-quality black & white documents and reports. Perfect for 1-3 people
  • WORLD'S SMALLEST LASER IN ITS CLASS – Precision laser printing that fits anywhere
  • FAST PRINT SPEEDS – Up to 21 black-and-white pages per minute single-sided
  • WIRELESS WITH SELF-RESET – Helps you stay connected
  • PRINT FROM ANY DEVICE – Wireless printing from any mobile device, PC or tablet. Works with Microsoft, Mac, AirPrint, Android, Chromebook and more

FAQ

Does setting LANG=en_US.UTF-8 install Unicode fonts?

No. It configures locale behavior. Font files and glyph coverage must be installed separately.

Should I add a long delay before calling page.pdf()?

Not as a first fix. In Puppeteer 25.12.0, PDF generation waits for fonts by default. Diagnose failed requests, missing glyph coverage, and print CSS first.

Why does a character render in one font but not another?

Unicode assigns code points, but each font covers a different set of scripts and symbols. Select a family with the required coverage or an intentional fallback.

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

Are package names identical on Alpine and Debian?

No. Font package names and available files are distribution-specific. Consult the package index for the base image you deploy.

The Bottom Line

Make the container’s fonts, print CSS, and font-loading state explicit. Test the exact failing characters after every image or Puppeteer upgrade.

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.