Most Puppeteer “font cache” problems on Ubuntu are not caused by Puppeteer’s browser cache. Missing glyphs and unexpected fallback fonts usually mean that Fontconfig cannot see the required font files, while errors such as “Could not find Chrome” involve Puppeteer’s browser installation. Diagnose the failing stage first, then repair the relevant layer.
Identify which problem you actually have
There are two unrelated caches that are often confused:
- Fontconfig cache: Ubuntu scans installed font directories and stores metadata used to resolve typefaces. This affects glyph selection and fallback during page rendering.
- Puppeteer browser cache: Since Puppeteer v19.0.0, downloaded browser binaries are stored by default in
~/.cache/puppeteer. This affects whether Puppeteer can find its browser, not whether an installed font contains a particular glyph.
| Symptom | Most likely area | First action |
|---|---|---|
| Boxes, tofu characters, missing symbols, or unexpected fallback | Font files, Fontconfig discovery, CSS font-family, or script coverage | Check that the required fonts are installed and readable, then run fc-cache -f -v |
| “Could not find Chrome” or browser executable missing | Puppeteer installation or browser cache | Install the browser with npx puppeteer browsers install |
No usable sandbox! |
Ubuntu security policy or launch configuration | Investigate AppArmor, user namespaces, and launch dependencies |
| Browser exits before rendering | Shared libraries, sandboxing, permissions, or writable paths | Check the runtime environment before changing font caches |
Do not delete ~/.cache/puppeteer as a routine response to missing glyphs. It is a browser-download cache, not Fontconfig’s metadata store.
Check the font files before rebuilding anything
A cache rebuild cannot supply a font that is not installed. Determine the exact typeface and scripts your page needs. Latin text may work while Chinese, Japanese, Korean, Arabic, emoji, or specialist symbols fall back because the selected family lacks those glyphs.
Recommended Free Tools
#1 Best Overall
Verify the package or font directory
Install a suitable font package for the Ubuntu release and language coverage required by your application. Puppeteer’s Linux guidance specifically notes that additional font files may be needed for CJK rendering; there is no universal package that covers every script.
For manually installed fonts, check common locations such as /usr/share/fonts and the current user’s font directory. The account running Puppeteer must be able to read the files. A font installed only for your desktop login may be invisible to a service user, CI account, Docker user, or rootless process.
Confirm the browser can request the intended family
Inspect your CSS for a spelling mismatch, a missing weight, or a generic fallback that changes the result:
body {
font-family: "Your Font", sans-serif;
font-weight: 400;
}
Make sure the font files provide the requested weight and style. If only a regular face is installed but the page requests 700, Chromium may synthesize or substitute a different face.
Rebuild Ubuntu’s Fontconfig cache
Ubuntu’s fc-cache utility scans configured font directories and builds the font-information files used by applications that rely on Fontconfig.
- Run a forced rebuild with verbose status output:
fc-cache -f -v - Read the output for the directories scanned and any permission or malformed-font warnings.
- Check the command status immediately:
echo $?A successful command normally returns
0. - Repeat the actual Puppeteer capture or PDF job. A successful cache command alone does not prove that Chromium resolves the desired face.
The -f option forces regeneration. If existing cache files are clearly corrupted and a complete erase-and-rescan is justified, use:
fc-cache -r -v
The -r option removes existing cache files before rescanning. Use it as a diagnostic repair, not as a default first step. Command details cited here come from the Ubuntu Jammy manual for Fontconfig 2.13.1-4.2ubuntu5; behavior and package availability can differ on another Ubuntu release.
Test font resolution inside the same runtime
Desktop verification can be misleading when Puppeteer runs in CI, Docker, or a service account. Run checks as the same user and inside the same image or container as the capture job.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Rank #3
Compare user and service environments
- Confirm the process user can read the font files.
- Confirm the font directories are present in the container or VM.
- Compare environment variables such as
HOME,XDG_CACHE_HOME, andXDG_CONFIG_HOME. - Use the same working directory and launch command as production.
If a font is installed after the browser process starts, restart the job or worker so the next render performs font discovery in the refreshed environment.
Use a minimal rendering check
Create a page containing the exact problematic characters, set the intended family explicitly, and capture it before testing the full application. This separates CSS loading, web-font timing, and application JavaScript from operating-system font discovery. If a web font is loaded over the network, wait for the font and page state rather than assuming that navigation completion means every face is ready.
Keep browser installation separate from font repair
Puppeteer normally downloads a compatible Chrome for Testing during installation. Package managers or security policies can block that postinstall step. If the browser executable is missing, install it explicitly:
npx puppeteer browsers install
Alternatively, allow the package’s postinstall script according to your package manager’s policy. Changing Fontconfig caches will not repair a missing browser executable.
Rank #4
Handle launch failures independently
“No usable sandbox!” on newer Ubuntu systems
Puppeteer documents an AppArmor interaction on Ubuntu 23.10 and newer that can prevent downloaded Chrome for Testing from using user namespaces. The resulting No usable sandbox! message is a sandbox and security-policy problem, not evidence of a stale font cache.
Investigate the AppArmor profile, user-namespace availability, and the browser’s launch diagnostics. Do not add --no-sandbox merely to make a font test pass. Puppeteer’s guidance strongly discourages running without the sandbox because it reduces browser isolation.
Docker and minimal images
Containers need the shared libraries required by Chromium. A browser that exits before page rendering cannot reveal whether fonts resolve. Install the libraries appropriate to your Ubuntu base image and verify that the process can write required configuration, cache, and user-data directories.
Read-only containers are a common source of confusing failures. Provide writable locations for XDG configuration/cache and Chromium’s user-data directory, or configure them on a writable volume. Fix these launch prerequisites before interpreting a blank screenshot as a font problem.
Best Value
Common failure patterns and fixes
| What you see | Cause to investigate | Fix |
|---|---|---|
| Only one language is broken | The installed family lacks that script | Install a font with the required coverage; then rebuild Fontconfig |
| Works locally, fails in CI | Different image, user, font directory, or writable cache | Install fonts in the CI image and run checks as the job user |
fc-cache reports permission errors |
Unreadable font directory or restricted cache location | Correct ownership/permissions and rerun with the capture user |
| Browser cannot be found after dependency installation | Postinstall was skipped or browser cache is elsewhere | Run npx puppeteer browsers install and review Puppeteer cache configuration |
| Browser launches but screenshot is blank | Navigation timeout, blocked request, page error, or missing writable path | Capture console/page errors and network timing; do not assume fonts are at fault |
| Text changes between machines | Different font versions, weights, fallback order, or device scale | Pin the image and font packages, declare CSS fallbacks deliberately, and compare the same viewport |
Make rendering reliable in production
- Build fonts into the same image or machine image used for captures; do not rely on an interactive developer workstation.
- Record the Ubuntu release, Puppeteer version, Chromium build, installed font packages, and process user when diagnosing a regression.
- Use a deterministic viewport and device scale factor when comparing screenshots.
- Wait for application readiness and font loading where your page uses web fonts.
- Keep browser binaries and Fontconfig caches conceptually separate in deployment documentation.
- After an image or font-package update, run a fixture page covering the scripts and weights your product actually uses.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server when you need rendered images or PDFs without maintaining Puppeteer, Chromium dependencies, or Ubuntu font-cache setup. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.
One GET request returns PNG, JPEG, WebP, or PDF. The API supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, clicks, selector or network-idle waits, request/resource blocking, headers, cookies, user agents, Authorization, timezone and geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage data, and an OpenAPI specification. Its parameter names are compatible with those used by many screenshot APIs.
For API details, see the ScreenshotNeo documentation.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
FAQ
Should I delete ~/.cache/puppeteer?
Only when diagnosing a browser-download or executable lookup problem. It is not the normal remedy for missing glyphs.
Does fc-cache -f -v install fonts?
No. It rebuilds metadata for fonts that already exist and are readable. Install suitable files first.
Why does a screenshot show fallback despite a successful cache rebuild?
Check script coverage, CSS family and weight names, web-font loading, process user, and whether the capture runs in a different container or image.
Quick Recap
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.

