ScreenshotNeo

BlogHow-to

How to Fix Selenium Screenshots That Render Emojis as Boxes in Chrome

Emoji boxes in Selenium screenshots usually mean Chrome cannot find a font with the needed glyphs. Diagnose font fallback in the browser’s actual runtime, then retest.

By the ScreenshotNeo team4 October 20267 min read

Emoji boxes in a Selenium screenshot usually mean Chrome could not find an available font containing the required glyph. Check fonts in the environment that launches Chrome, confirm any custom web font loaded and covers the characters, then restart Chrome and capture again. The screenshot records the rendered pixels; Selenium does not supply missing glyphs.

Chromium’s Blink text stack tries the primary CSS font, subsequent fonts, and system fallback to fill missing glyphs. If no usable glyph is found, the text can render as a missing-glyph box. This is a font-availability diagnosis, not evidence of a screenshot encoding problem. Chromium Blink text-stack documentation

1. Confirm the characters exist in the page

Start with the exact string that appears incorrectly. Check the page’s DOM or evaluate the text in the browser session. If the intended Unicode characters are present in the DOM but appear as boxes in the screenshot, investigate font coverage and fallback first. If the DOM contains replacement characters or different code points, investigate the page’s data, encoding, or application rendering before changing browser fonts.

// Run in the page's browser console, or through Selenium's execute_script:
const el = document.querySelector(".emoji-example");
console.log(el?.textContent);
console.log([...((el?.textContent) || "")].map(ch => ch.codePointAt(0).toString(16)));

Code points help distinguish visually similar sequences. Some emoji are made from multiple code points, including variation selectors, skin-tone modifiers, regional indicators, or zero-width joiners. Check the actual sequence shown by the page rather than assuming one emoji corresponds to one character.

2. Check fonts where Chrome actually runs

Inspect the operating system and distribution of the machine or container launching Chrome. A local desktop, CI worker, container, or remote Selenium node can have a different font inventory. This follows from Chrome’s use of system font fallback: the relevant fonts must be available to the browser runtime producing the screenshot.

  • Identify the Chrome host: local machine, CI runner, container, or remote WebDriver node.
  • Check whether that runtime has an emoji-capable font that covers the specific characters.
  • Use the package name and installation instructions appropriate to that operating system and distribution. There is no universal package command established for every platform.
  • After changing the font environment, restart the Chrome process and capture the same page again.

A font being present on the machine that submits the Selenium script is not enough if Chrome runs elsewhere. Make the change in the browser’s runtime environment.

3. Check custom web fonts and CSS fallback

If the page uses a custom web font, verify that its request succeeds and that the font includes the emoji glyphs in question. A font can load correctly and still lack coverage. Chromium uses the CSS font list and falls back to system fonts for glyphs the requested fonts cannot supply. A restrictive font declaration or unavailable system fallback can therefore expose missing-glyph boxes.

/* Example: keep a system fallback after the site's preferred font. */
.emoji-example {
  font-family: "Site Font", sans-serif;
}

Inspect the element’s computed font-family and the browser’s network activity for the web-font request. If you control the page, test with a font stack that allows a suitable system fallback. The exact font name and CSS vary by platform and page; do not assume a particular font is installed everywhere.

4. Retest headless and headful on the same host

Modern Chrome Headless shares browser code with headful Chrome. A headless-only symptom does not, by itself, prove that Headless uses a separate text renderer. Compare headful and headless sessions on the same machine and with the same page, fonts, browser binary, and viewport. Then compare the font setup of machines or containers if the issue follows one host. Chrome Headless documentation

Chrome’s modern Headless mode was updated to create platform windows without displaying them. Shared browser code does not make the operating systems, installed fonts, container images, or runtime configuration identical.

5. Verify Selenium’s Chrome setup separately

Confirm which Chrome binary Selenium launched and check that Chrome and ChromeDriver have matching major versions. ChromeDriver accepts Chrome options for arguments and binary selection; these checks help rule out setup mismatches. They do not provide an emoji glyph that is absent from the runtime’s fonts.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless")  # Optional: compare with a headful session.
# If needed, select the Chrome binary used by this runtime:
# options.binary_location = "/path/to/chrome"

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    driver.save_screenshot("page.png")
finally:
    driver.quit()

Use the Chrome and ChromeDriver guidance for your Selenium setup: Selenium Manager documentation and ChromeDriver version selection. A browser upgrade or driver change is not a general fix for missing font coverage.

6. Use this diagnostic order

  1. Capture the exact affected text and confirm its intended characters are in the DOM.
  2. Identify the host or container where Chrome runs, including its operating system and distribution.
  3. Check that an installed, discoverable emoji-capable font covers those characters.
  4. If the page uses a web font, confirm it loaded and inspect its glyph coverage and the CSS font stack.
  5. After changing fonts, restart Chrome and capture the same page again.
  6. If the issue remains, compare headful and headless on the same host, then compare the font configuration across hosts.
  7. Separately verify the Chrome binary and Chrome/ChromeDriver major versions.

Common errors and fixes

Symptom or assumption Likely cause What to check or do
Emoji appear on a developer laptop but as boxes in CI The browser runtime environments have different fonts. Inspect and provide a suitable font in the CI worker or container that launches Chrome, then restart Chrome.
The string looks correct in source code, but the screenshot has boxes The page may contain the right characters while no available font supplies their glyphs. Check the DOM text and code points, then check font coverage in Chrome’s runtime.
A custom font loads, but emoji still show as boxes The font may not include the relevant glyphs, and fallback may not be available. Check font coverage, the computed CSS font list, and the system fallback fonts.
Adding a WebDriver screenshot option does not help Screenshot capture records the rendered page; it does not install fonts or add glyphs. Fix character delivery or font availability. No general Selenium screenshot flag is documented as a cure for missing glyphs.
Upgrading ChromeDriver does not help The issue may be font coverage, not driver compatibility. Check Chrome and ChromeDriver major-version compatibility separately, then return to the font diagnosis.
Headless fails but headful works The sessions may differ in host, binary, fonts, or configuration; the mode alone does not establish the cause. Run both modes on the same host with the same browser and font environment, then compare runtime details.
Only some emoji or joined sequences fail Coverage can differ by glyph or sequence, and a displayed emoji can consist of multiple code points. Record the exact sequence and check the chosen font’s coverage for it.

Performance, reliability, and cost notes

Font checks are usually an environment setup task, while screenshot reliability depends on using the same browser runtime and font inventory across captures. For repeatable CI results, make the font setup part of the browser image or worker configuration and restart browser processes after font changes. The research sources do not establish a universal install command, a particular best font for every operating system, or a success rate for this fix.

There is no reason to treat this as a Selenium screenshot encoding issue unless the DOM or text data is already wrong. Browser and driver version compatibility still matters for automation setup, but installing or exposing a font with the needed glyph coverage addresses the likely missing-glyph cause.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Its one-call API can return an image or PDF without maintaining your own browser setup. The response indicates whether a page was clean and billed; bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing. ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.

For a screenshot of a page that renders emojis correctly in its own browser environment, call the API like this. This call does not repair missing fonts in your own Selenium runtime; it gives you a managed screenshot request instead.

See the ScreenshotNeo API documentation for request options.

cURL

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

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
  • Cookie banners, popups, and chat widgets are removed before the shot.
  • Bot checks, blank pages, and failed loads are never billed.
  • An MCP server lets AI agents take screenshots.
  • 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, no card required.

FAQ

Does changing the screenshot format fix emoji boxes?

Usually no. PNG, JPEG, or WebP stores the rendered pixels; it does not add missing font glyphs. First check the DOM and font fallback.

Do I need to install a font on the machine running my Python script?

Install or expose it where Chrome runs. In a remote Selenium setup, that may be a worker, container, or remote node rather than the machine running the client script.

Does headless Chrome always render emojis differently?

No such conclusion follows from the documented implementation: modern Headless shares browser code with headful Chrome. Compare both modes on the same host and configuration to isolate environmental differences.

Which emoji font should I install?

That depends on the operating system and the characters to display. Confirm the platform and required glyph coverage before choosing a package; there is no universal package recommendation in the sources used here.