ScreenshotNeo

BlogHow-to

How to Fix Hindi Text Rendering in Selenium Headless Chrome Screenshots

Hindi text appears as boxes or malformed glyphs in Selenium screenshots? Check fonts in Chrome’s actual Linux runtime, then isolate font selection and browser differences.

By the ScreenshotNeo team4 October 20268 min read

If Hindi appears as empty boxes, disappears, or has malformed vowel signs or conjuncts in Selenium headless Chrome screenshots, start by checking Devanagari fonts in the exact Linux host or container that launches Chrome. Selenium captures the pixels Chrome rendered; its screenshot call cannot provide missing glyphs. If glyphs are present but a word is shaped incorrectly, compare another Devanagari font and test the exact text before blaming Selenium.

Chromium’s Linux font mappings name Noto Sans Devanagari for standard and sans-serif Devanagari, and Noto Serif Devanagari for serif. Those mappings were added in a Chromium source change dated March 4, 2026; older or different browser builds may rely on system font resolution. See the Chromium source change and Linux font mappings.

Diagnose the failure in order

  1. Record the environment. Note the operating system and container base image, Chrome version, ChromeDriver version, and the exact Hindi string that fails. Keep the text constant while changing one variable at a time.
  2. Compare visible and headless Chrome in the same runtime. If both render incorrectly, investigate installed fonts, CSS font selection, and whether the page’s own fonts finished loading. If visible Chrome works but automation does not, compare the container contents and the actual browser binary/version. This comparison is a diagnostic technique, not a guarantee about the cause.
  3. Check font availability where Chrome runs. A font installed on a developer workstation does not automatically exist in a CI worker or container. Confirm that the runtime can discover a Devanagari-capable font. Chromium’s Linux defaults include Noto Sans Devanagari and Noto Serif Devanagari.
  4. Check the page’s font selection and loading. If you control the page, specify an installed Devanagari font in CSS. Wait for web fonts and page content to load before taking the screenshot.
  5. Separate missing glyphs from shaping problems. Empty tofu boxes point toward missing glyph coverage or font resolution. If characters appear but vowel signs, conjuncts, or only a particular word look wrong, compare another Devanagari font and several test strings. A 2026 Noto Devanagari issue reports one Hindi word rendering incorrectly in a Google Fonts example, but does not establish the cause; not every malformed result is a missing-font problem. Review Devanagari font issue reports.
  6. Identify which headless implementation is running. Current headless Chrome shares browser code with headful Chrome. Since Chrome 132.0.6793.0, the old headless implementation is distributed separately as chrome-headless-shell. Compare the binary and version actually launched before attributing a difference to headless mode. Chrome’s headless mode documentation.

Install and select fonts in the browser runtime

Use your distribution’s package index and documentation to identify packages that provide Devanagari fonts for the exact base image. Package names and contents vary by distribution and image version; verify them rather than copying a package list blindly. After installing fonts, ensure the image used to launch Chrome includes them, then restart the browser process so it sees the runtime’s font configuration.

An Ubuntu Server answer from 2019 reported installing fonts-indic, fonts-noto, and fonts-noto-cjk as a workaround. Treat that as an anecdotal, potentially stale clue, not an official or universal recipe; the report does not isolate which package helped. Read the community report.

Where you control the page, make font choice explicit. For example, if Noto Sans Devanagari is installed and available to Chrome:

body {
  font-family: "Noto Sans Devanagari", sans-serif;
}

For serif text, test an installed serif Devanagari family such as Noto Serif Devanagari. A CSS family name does not install a font: confirm the font exists in the runtime and that the page’s stylesheet has loaded. If the page uses a remote web font, wait for it before capture; otherwise Chrome may capture the fallback font.

Runnable Selenium example

This Python example starts Chrome in headless mode, opens a page, waits for the document and available web fonts, and saves a screenshot. Replace the URL and selector with your page. It assumes Selenium, Chrome, and a compatible ChromeDriver are already installed in the runtime, along with an appropriate Devanagari font when the page needs one.

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait

url = "https://example.com/page-with-hindi"
output = Path("hindi.png")

options = Options()
options.add_argument("--headless")
options.add_argument("--window-size=1440,1200")

with webdriver.Chrome(options=options) as driver:
    driver.get(url)
    WebDriverWait(driver, 30).until(
        lambda browser: browser.execute_script(
            "return document.readyState === 'complete'"
        )
    )
    WebDriverWait(driver, 30).until(
        lambda browser: browser.execute_script(
            "return !document.fonts || document.fonts.status === 'loaded'"
        )
    )
    driver.save_screenshot(str(output))

print(f"Saved {output}")

The font wait helps with document fonts known to the page, but it cannot install a missing system font, guarantee that a third-party font request succeeded, or ensure that late JavaScript content has appeared. If a specific Hindi element is populated asynchronously, wait for that element or its expected text as well. For diagnosis, compare the same text in a page with an explicit local font family and in the original page.

Check your test text and CSS

Use a fixed sample that contains the characters involved in the failure, including any conjuncts and vowel signs relevant to your page. Do not change the sample between font comparisons. A minimal test page can help distinguish browser/runtime font coverage from application CSS or remote font loading:

<!doctype html>
<meta charset="utf-8">
<style>
  body { font-family: "Noto Sans Devanagari", sans-serif; font-size: 32px; }
</style>
<p>नमस्ते दुनिया</p>

Serve or open this page in the same browser runtime and compare it with the application page. If the sample fails too, focus on runtime fonts and font resolution. If it works but the application does not, inspect the application’s computed font family, font requests, CSS, and timing. This is a way to narrow the cause, not proof of any single diagnosis.

What Selenium and Chrome headless options can and cannot fix

Selenium’s save_screenshot records the rendered browser viewport. Chrome’s screenshot command-line options also capture rendered output; neither supplies absent font files. Chrome documents --headless for headless operation and Selenium integration. Do not add unrelated rendering flags as a substitute for checking font coverage. In particular, the available evidence does not support --disable-gpu as a Hindi-font fix. Headless mode and Selenium example · Chrome screenshot documentation.

For full-page output, ensure the capture method actually supports full-page capture; a basic screenshot command may capture only the current viewport. This is separate from whether Hindi glyphs are available and shaped correctly.

Troubleshooting common symptoms

Symptom Likely area to inspect Next step
Hindi is shown as empty squares or boxes Missing glyph coverage or font fallback in the runtime Check installed and discoverable Devanagari fonts in the host/container launching Chrome; test with an explicit installed family.
It works locally but not in CI or a container Different image contents, font packages, browser binary, or versions Compare OS/image, Chrome and ChromeDriver versions, and installed fonts in both environments.
Some characters show, but marks or conjuncts look wrong Font-specific shaping/rendering, text differences, or fallback across fonts Keep the string fixed and test another Devanagari font; inspect whether the intended font actually loaded.
Only the first screenshot is wrong Capture may happen before fonts or asynchronous content are ready Wait for the relevant element and font loading; check failed font requests and late page scripts.
CSS names Noto Sans Devanagari but output still falls back The family may not be installed, discoverable, or selected by the computed CSS Verify the runtime font installation and inspect the element’s computed font family in that browser.
Headless and visible results differ Different browser executable/version or environment, including old headless shell Record the launched binary and version; compare current unified headless Chrome with the actual setup in use.
Changing --disable-gpu has no effect The issue is likely unrelated to that flag Return to font coverage, CSS selection, loading, and browser identity checks.

Performance, reliability, and cost

Installing fonts in a reusable container or machine image avoids repeating setup for each capture and makes environments easier to compare. Keep the browser, driver, image, and font installation consistent between local reproduction and CI. A screenshot taken before fonts or page content finish loading can be unreliable even when the runtime has the correct files, so wait for the specific condition your page requires rather than relying only on a fixed short delay.

Font packages add files to the runtime image, and a longer readiness wait adds time to each capture. Choose only packages needed for your supported scripts and verify the result in the target image. The sources here provide no measured rendering benchmark or success rate, so treat performance impact as environment-dependent.

Or skip the browser setup

If you need a website screenshot without maintaining Chrome and Selenium, ScreenshotNeo is a website screenshot API and MCP server. It can capture PNG, JPEG, WebP, or PDF from one GET request. The page still needs to render its Hindi font correctly for the captured pixels to show the intended text, so confirm the source page’s font and rendering first.

See the ScreenshotNeo API documentation. Example request:

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

ScreenshotNeo accepts cookie and consent banners like 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, timeouts, failed loads, and cache hits cost nothing, and response headers indicate the page verdict and whether the request was billed. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

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

FAQ

Does Selenium have a Hindi rendering switch?

The cited guidance points to fonts, page font selection, loading, and the browser runtime. Selenium’s screenshot call captures Chrome’s rendered output; it does not add glyphs.

Which Devanagari fonts does Chromium map on Linux?

The March 2026 Chromium source change maps standard and sans-serif Devanagari to Noto Sans Devanagari and serif to Noto Serif Devanagari. Actual behavior depends on the Chrome build and system font setup.

Should I install fonts-noto-cjk for Hindi?

Do not assume that package alone fixes Hindi. The cited Ubuntu community answer listed it alongside other packages as an anecdotal bundle, without isolating its effect. Verify the Devanagari font coverage supplied by packages in your distribution.

Does current headless Chrome use a separate renderer?

Chrome’s current headless mode shares code with headful Chrome. The old headless implementation has been separately distributed as chrome-headless-shell since Chrome 132.0.6793.0.