Fix Emojis That Turn Into Boxes in HTML to PDF Output
Emoji boxes in PDFs usually mean the renderer cannot find a font glyph. Check font fallback, the PDF runtime, and print styles to fix them.
Emoji boxes in an HTML-to-PDF file usually mean the PDF renderer cannot find a usable glyph in the selected font or its fallback fonts. Make the needed font available to the process that generates the PDF, check print-specific styles, and test the exact emoji sequence through that renderer. If the sequence still cannot render reliably, use an image or a clear text alternative.
A font name in CSS is not enough: the matching font must be installed or otherwise available to the PDF renderer. A laptop’s browser rendering correctly does not establish that a container or remote PDF worker has the same fonts.
Why emojis become empty squares
A font can be selected for text yet lack a glyph for a particular character. Chromium’s Blink first uses the CSS font families and then searches system fonts for missing glyphs. If fallback also fails, it renders the primary font’s missing-character glyph, commonly called tofu. Blink font fallback documentation.
Emoji are especially prone to gaps because what looks like one symbol may be a sequence of Unicode code points. Flags, keycaps, skin-tone modifiers, and joined family or profession emoji can require sequence support beyond the individual characters. Test the exact sequence that fails, including variation selectors and zero-width joiners.
PDF output can also use a different stylesheet from the browser screen. Puppeteer’s page.pdf() uses print media by default, so @media print rules may change the font stack. Puppeteer PDF documentation.
Diagnose the renderer and reproduce the failure
- Record the HTML-to-PDF engine and version, operating system, and whether generation runs in a container, server, or remote worker.
- Make a minimal HTML file containing the exact failing emoji sequence and ordinary text around it. Preserve variation selectors, modifiers, flags, and joiners.
- Generate a PDF through the same deployed process. Do not use only a desktop browser preview as evidence.
- Check the font that the renderer can actually discover, then inspect print-specific CSS and renderer warnings.
- Open the PDF in another viewer if portability matters, and confirm whether the symbol is visually present and whether text extraction behaves as needed.
<!doctype html>
<meta charset="utf-8">
<style>
body { font-family: "Your Text Font", sans-serif; }
@media print {
body { font-family: "Your Text Font", sans-serif; }
}
</style>
<p>Emoji check: ☕️ 👩🏽💻 🇺🇳 1️⃣ 👨👩👧👦</p>
Replace Your Text Font with a font that is installed and discoverable in the PDF runtime. This fixture helps reveal which sequences fail; it does not guarantee that any particular font or renderer supports all emoji.
Fix font availability and fallback
Chromium and Puppeteer
Ensure the browser process can access a font with the needed emoji coverage and that its system fallback is available in the production environment. Check both the regular CSS font declarations and @media print. If you want to compare screen styling in a Puppeteer PDF, emulate screen media before generating it:
await page.emulateMediaType('screen');
await page.pdf({ path: 'output.pdf', format: 'A4' });
Use that only when screen media is the intended PDF design. Otherwise keep print media and correct its font rules. See the Puppeteer media emulation API and PDF API.
WeasyPrint
WeasyPrint uses fonts Pango can find; on Linux, font discovery is handled through Fontconfig. Run discovery commands inside the same container or worker that creates the PDF:
fc-list
fc-match sans-serif
fc-match "Your Emoji Font"
Install or configure a suitable font in that runtime, then repeat the PDF fixture. WeasyPrint documents that fonts are embedded and subset by default. It logs a warning and draws a missing-character glyph when neither the chosen font nor fallback covers a character. Fontconfig configuration can also affect colored emoji variants and CSS font behavior. Consult the WeasyPrint API reference.
wkhtmltopdf
An archived wkhtmltopdf issue reports an empty square instead of the coffee emoji in a generated PDF. That is an individual report, not a confirmed universal diagnosis or fix. The project repository is archived, so account for its maintenance status when choosing a renderer for a new pipeline. Issue report · Repository status.
Check the generated PDF, not just the HTML
Font fallback and emoji support depend on the renderer, operating system, font format, and exact sequence. Reproduce with the deployed versions and runtime. If the PDF must travel between viewers or systems, verify its appearance in the viewers your readers use. Font embedding can help portability, but it does not establish identical emoji rendering in every viewer.
If one complex sequence remains unsupported, choose an image asset for the symbol or replace it with wording that preserves the meaning. This avoids silently shipping a tofu glyph. Consider accessibility and text extraction requirements when choosing an image; provide an appropriate text equivalent where needed.
Troubleshooting checklist
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Boxes appear only in production | The container or worker lacks the font available on the developer machine. | Run fc-list and fc-match in the PDF runtime; install/configure the font there. |
| HTML looks correct, PDF does not | PDF generation selects print media or a different renderer path. | Inspect @media print font rules and reproduce with the actual PDF call. |
| Some emoji work, but flags or joined emoji fail | The font or renderer lacks support for that sequence. | Test the exact code-point sequence; use an image or text alternative if unsupported. |
| WeasyPrint logs a missing glyph warning | Neither the selected font nor fallback covers the character. | Use Fontconfig discovery tools in the worker and make a suitable font available. |
| Emoji color or style changes unexpectedly | System fallback or Fontconfig rules may select a different emoji font or variant. | Inspect font matching and runtime configuration; validate the resulting PDF. |
| A PDF looks different in another viewer | Viewer font handling or rendering differs. | Check embedding and portability needs; test target viewers and use an image for symbols that must remain visually fixed. |
| Only one legacy renderer fails | Renderer-specific font or sequence support may be limited. | Compare current renderer maintenance and test the exact corpus before migrating. |
Performance, reliability, and cost considerations
Adding fonts increases the assets the PDF environment must provision, but the central reliability issue is consistency: every worker and deployment needs the intended font configuration. Pin renderer and font versions where reproducibility matters, and keep the minimal emoji fixture as a release check. No cross-engine benchmark establishes one renderer as universally best for emoji.
WeasyPrint embeds and subsets fonts by default, which affects the generated PDF’s font data and portability. Check output size and viewer behavior for your own documents; the cited documentation provides no universal cost or performance figure. If the required emoji cannot be rendered consistently, an image or text alternative may be more predictable than repeatedly changing CSS font names.
Or skip the browser setup
If the deliverable you need is a screenshot of a page rather than a PDF with selectable text, ScreenshotNeo offers a website screenshot API and MCP server. Its one-call API returns an image or PDF; the call below asks for a screenshot of the page:
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 request options. Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each removal step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers indicate the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does adding an emoji font to CSS always fix PDF boxes?
No. The font must be available to the PDF renderer, and it must support the exact emoji sequence. Check the runtime and test the generated PDF.
Why does the same emoji work in a browser but not in a PDF?
The PDF path may use another renderer, runtime font set, or print stylesheet. Reproduce through the PDF generation process and inspect those differences.
Will embedding fonts guarantee the same emoji in every viewer?
No universal guarantee follows from font embedding. Test the PDF in the viewers and environments that matter for your workflow.
Should I use an image instead?
Use an image when visual consistency matters and the renderer cannot reliably show the required sequence. Include a text equivalent when the symbol conveys information.


