ScreenshotNeo

BlogHow-to

Chrome Headless Screenshot में Devanagari Font Missing: Fix on Linux

Fix missing Devanagari glyphs in Linux Chrome screenshots by checking the actual runtime, installing a script-capable font, and verifying CSS and font readiness.

By the ScreenshotNeo team4 October 20268 min read

If Devanagari text is missing or displayed as empty boxes in a Chrome headless screenshot on Linux, first check the fonts installed in the exact container, VM, or CI worker that launches Chrome. Install a Devanagari-capable font there, confirm the browser can resolve it, check the page’s CSS fallback, and capture only after the page and any web fonts are ready.

For Linux’s standard sans-serif mapping, Chromium’s March 4, 2026 source change names Noto Sans Devanagari; it names Noto Serif Devanagari for serif text and Noto Sans Mono for fixed-width text. That change does not establish which released Chrome version first includes the mappings, and those fonts still need to be installed and resolvable in your runtime. See the Chromium source change.

Why Devanagari goes missing

Chrome can render a character only if the selected font has the necessary glyph. A Linux host may have a suitable font while the isolated image running headless Chrome does not. A page can also specify a web font that covers Latin characters but not Devanagari, leaving the browser to find a fallback. If the runtime has no suitable fallback, glyphs can appear as boxes or be absent.

Puppeteer’s Linux and container guidance recommends including required system dependencies and fonts in the runtime image. A font installed on a developer’s workstation does not automatically become available in a separate CI job or container. Puppeteer troubleshooting: Linux dependencies.

Headless mode itself is not a separate rendering engine in current Chrome: Chrome documents that headless and headful modes are unified. Since Chrome 132, the old Headless Shell is a separate standalone binary, so identify the binary your automation actually starts before applying version-specific advice. Chrome Headless documentation.

Fix it step by step

  1. Identify the renderer. Record the Chrome or Chromium version, executable path, and whether your automation uses regular Chrome or chrome-headless-shell. Do this inside the same job or image that produces the screenshot.
  2. Inspect fonts in that runtime. Use the font listing and query tools available for your Linux distribution to check whether a Devanagari-capable family, such as Noto Sans Devanagari, is installed and discoverable. Verify script coverage with your distro’s font tools or the font package documentation; a family name alone does not prove the installed file includes the needed glyphs.
  3. Install the appropriate package in the image. Find the Devanagari font package in the package index for your base distribution. Package names and repositories vary, so do not assume an Ubuntu command or package name applies to Alpine, Fedora, Arch, or another image.
  4. Refresh font discovery if required. Follow the distribution’s cache-refresh procedure, then restart Chrome. The exact cache command varies by image.
  5. Check CSS fallback. If the page pins a Latin-only web font, add a Devanagari-capable family after it in the font-family list, or choose a family with the required glyphs. Test with plain Devanagari text and a known installed family to separate a CSS or web-font issue from system font resolution.
  6. Wait for content and fonts. Wait for the page’s required content and web fonts before calling the screenshot API. In browser automation, use the driver’s page-load or selector wait and, where appropriate, wait for document.fonts.ready. This is a practical readiness check; it is not a guarantee that every application’s later updates are finished.
  7. Rebuild and reproduce. Rebuild the image and rerun the capture in the same container or worker. Installing fonts only in an interactive shell that is not used by the job will not fix the job’s environment.

Runnable Puppeteer example

This Node.js example navigates to a page, waits for document fonts to settle, and saves a full-page PNG. It assumes Puppeteer and a Devanagari-capable font are already available in the environment that launches Chrome.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com', { waitUntil: 'networkidle0' });
    await page.evaluate(() => document.fonts.ready);
    await page.screenshot({ path: 'page.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

Replace the example URL with the page you need to capture. networkidle0 can wait indefinitely or be unsuitable for pages with persistent network activity; use a navigation timeout and wait for a specific content selector when that better reflects readiness. Font readiness only covers fonts known to the document at that point. If the page injects content or changes styles afterward, wait for that application state too.

To isolate the font stack, temporarily set a known installed family in a test page:

await page.evaluate(() => {
  document.body.style.fontFamily = '"Noto Sans Devanagari", sans-serif';
});
await page.evaluate(() => document.fonts.ready);

Use a family installed in the runtime; this CSS does not install a font. For a production site, set the fallback in the site’s stylesheet rather than overriding the whole document from the capture script.

Choose the right font and fallback

  • Sans-serif: Noto Sans Devanagari is the family named in Chromium’s Linux standard/sans-serif mapping change.
  • Serif: Noto Serif Devanagari is named for the serif mapping.
  • Monospace: Chromium’s change names Noto Sans Mono for fixed-width text. Check actual Devanagari coverage in the font file available to your runtime before relying on it for script characters.

These are mappings described in a Chromium source change, not proof that every released Chrome build or downstream package has the same behavior. Installing a suitable font explicitly and specifying an appropriate CSS fallback makes the runtime’s intent clearer.

body {
  font-family: "Your Latin Web Font", "Noto Sans Devanagari", sans-serif;
}

h1, h2 {
  font-family: "Your Latin Web Font", "Noto Serif Devanagari", serif;
}

Use the real Latin font family your page loads, and verify the Devanagari family is installed. If the web font itself includes Devanagari glyphs, it may render those characters directly; otherwise the browser proceeds through the fallback list.

Common errors and fixes

Symptom Likely cause What to do
Boxes or blank glyphs only in CI The CI image lacks a Devanagari-capable font, even if the developer workstation has one. Install the appropriate font package in the image used by the job, then verify font discovery there.
Only some characters are missing The chosen font or fallback does not cover all characters in the text. Check the actual font’s script coverage and test with another installed Devanagari-capable font.
Text renders with an unexpected style A fallback family is being selected because the primary font lacks glyphs, or the intended family is not available. Inspect computed CSS and loaded fonts; install the intended family or adjust the fallback stack.
It works locally but fails in a container Fonts were installed on the host, not in the container filesystem used by Chrome. Add the font dependency to the container image and rebuild it.
Installing a font did not change the screenshot Chrome may still be running with an old font set, the cache may need refreshing, or the job may use a different image or binary. Follow the distro’s cache procedure, restart Chrome, and confirm the executable and font set from the capture job.
Some text is correct but web-font text is not The page’s custom font may lack Devanagari coverage or the capture may happen before page content and fonts are ready. Add a suitable fallback, wait for fonts and application content, then capture again.
Advice for headless Chrome does not match the job The automation may use a different Chrome version or the standalone Headless Shell. Print the actual executable path and version from the runtime; use documentation for that binary.
Package install command fails The command targets a different distribution or a repository not enabled in this image. Search the package index and documentation for the image’s own distribution and repositories.

Changing --headless, GPU, or sandbox flags does not install missing glyphs. Diagnose the font files and browser selection first.

Performance, reliability, and cost

Font installation adds dependencies to the browser image and can increase its size; the exact increase depends on the package and image, so check your own build output. Bake the font into the image rather than installing it during every screenshot job. This makes captures less dependent on network access and avoids repeating package setup.

For reliable captures, pin or record the browser image and font package set, and test a representative page containing the Devanagari characters your application needs. A successful page load does not prove every glyph rendered correctly. A small visual regression fixture can catch changes in fonts or browser images.

Rendering locally has no per-capture API fee, but it requires maintaining the browser runtime and its dependencies. If you already operate browser automation, the font package is usually the direct fix. A screenshot API can avoid maintaining browser setup, but it cannot make a page’s missing or unsuitable source font correct by itself.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. A single request returns an image or PDF. For a page whose Devanagari font renders correctly in the browser, capture it with this request; see the API documentation for options.

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

Replace https://stripe.com with your page URL. ScreenshotNeo accepts the page’s cookie or consent banner as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

FAQ

Does headless mode use a different font engine?

Current Chrome documentation says headless and headful modes are unified. Check whether your automation instead launches the standalone Headless Shell, and verify the exact binary and version.

Will upgrading Chrome fix missing Devanagari by itself?

Do not assume so. A March 2026 Chromium source change added Linux Devanagari defaults, but it does not establish the first released Chrome version containing them. The mapped font still needs to be available in the runtime.

Can CSS fix a font that is not installed?

No. CSS can select an available font or define a fallback order; it does not provide the font file. Install a suitable family in the browser’s runtime or load a web font that covers the needed characters.

Should I add a Devanagari font to every Linux image?

Add it to images that render pages requiring Devanagari glyphs. Keep the dependency in the same image and execution context as Chrome.