ScreenshotNeo

BlogHow-to

Fix Hindi Text Rendering in Java Selenium Website Screenshots on Linux

Fix missing or malformed Hindi glyphs in Linux Selenium screenshots by checking runtime fonts, CSS fallback, and browser setup.

By the ScreenshotNeo team4 October 20266 min read

If Hindi text appears as empty boxes, broken marks, or malformed glyphs in Java Selenium screenshots on Linux, first check whether the Linux runtime that launches Chrome has a Devanagari-capable font available. Selenium drives the browser; it does not supply fonts. If you control the page, add a Devanagari-aware CSS font stack and retest in the same container or CI image used for capture.

1. Identify where the rendering fails

A screenshot is the browser’s rendered page captured as pixels. Missing glyphs usually point to font availability or font fallback, while a browser/driver startup failure is a separate compatibility problem. Chromium’s Linux font resolution depends on available fonts and fontconfig configuration, and Noto documents how browsers move through a CSS family list when a font lacks a character. Chromium source; Noto web font guidance.

Before changing anything, record the Linux distribution or container base image, Chrome/Chromium version, Selenium version, ChromeDriver version, headless or headed mode, and the exact sample text that fails. Check the runtime where Chrome actually runs; a font installed on the host may not exist inside the browser container.

2. Check the Linux font environment

Inspect the font inventory and fontconfig resolution from the same container, VM, or CI runner that launches Chrome. Confirm that at least one installed family covers Devanagari. Use the package manager and official repositories for your specific distribution to install an appropriate font; package names and availability vary, so do not assume one command applies to every Linux image. Restart the browser after changing fonts.

Chromium source records a March 4, 2026 change adding Linux default mappings for Devanagari, including Noto Sans Devanagari and Noto Serif Devanagari. That source change does not mean every distribution or older browser package includes those mappings. Chromium’s fallback test data also uses a mock fontconfig setup and test fonts, so its specific Lohit Devanagari result is not a universal production recommendation. Chromium source.

3. Set a script-aware CSS font stack

If you can change the website CSS, specify a family intended for the desired style and retain general and generic fallbacks. Noto recommends script-specific Devanagari families followed by a general Noto family and a generic family. The browser tries later entries when an earlier font lacks a needed character. Noto web font guidance.

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

/* Serif Hindi */
.article {
  font-family: "Noto Serif Devanagari", "Noto Serif", serif;
}

For a site that serves its own web fonts, verify that the font request succeeds in the browser and that the font contains the required characters. If only some punctuation, digits, conjuncts, or combining marks are wrong, test those exact characters: script coverage can differ between families. Do not assume that setting a family name installs the font on Linux.

4. Run a minimal Java Selenium capture

This example launches Chrome headless, sets a predictable viewport, loads a page, and saves a screenshot. Run it in the same Linux environment as the failing job. It uses Selenium 4 APIs; add a Selenium Java dependency through your project’s normal build configuration. Selenium documents Chrome options and Chrome/ChromeDriver compatibility. Selenium Chrome documentation.

import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.WebDriver;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;

public class HindiScreenshot {
    public static void main(String[] args) throws Exception {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless=new");
        options.addArguments("--window-size=1440,1000");

        WebDriver driver = new ChromeDriver(options);
        try {
            driver.manage().window().setSize(new Dimension(1440, 1000));
            driver.get("https://example.com"); // Replace with the page under test.
            File screenshot = ((ChromeDriver) driver).getScreenshotAs(OutputType.FILE);
            Files.copy(screenshot.toPath(), Path.of("screenshot.png"));
        } finally {
            driver.quit();
        }
    }
}

For a self-contained rendering check, point the test at a local HTML fixture containing the exact Hindi text and CSS. That separates font availability from the target website’s network, scripts, and styling. Keep the real site’s CSS for the next comparison: if the fixture works but the real page does not, inspect its computed font family, loaded web fonts, and element-specific styles.

5. Compare rendering modes and versions

Chrome supports headless screenshots and fixed window sizes. Compare headed and headless output only when both runs use the same machine image, browser version, font inventory, page state, and viewport. A difference can help isolate a mode-specific condition; the documentation does not establish that headless mode inherently breaks Hindi rendering. Chrome Headless documentation.

Separately confirm Chrome and ChromeDriver major versions align. Selenium’s Chrome guidance says Selenium 4 is compatible with Chrome 75 and greater by default and calls out matching Chrome/ChromeDriver major versions. Version alignment helps automation work reliably, but it does not install Devanagari fonts. Selenium Chrome documentation.

6. Retest systematically

  1. Use a fixed viewport and the same exact sample text on every run.
  2. Capture the minimal fixture, then the actual target page.
  3. Change one variable at a time: runtime fonts, CSS family stack, browser version, or rendering mode.
  4. Inspect the resulting image for letters, vowel marks, conjuncts, digits, and punctuation.
  5. Rebuild or restart the actual container/runner after installing fonts, then recapture.

Common errors and fixes

Symptom Likely cause Fix
Every Hindi character is a box No available font covers the required Devanagari glyphs, or fallback cannot find one. Install a suitable font in the browser runtime and verify its visibility through that runtime’s fontconfig.
Some marks or punctuation are wrong The selected family lacks some characters or the page’s stack does not reach a suitable fallback. Test the affected characters and use a script-specific family followed by a general family and generic fallback.
Host browser works, CI screenshot fails The CI/container image has a different font inventory or fontconfig setup. Inspect and update the image that actually runs Chrome; do not rely on fonts installed only on the build host.
Font CSS is present but output is unchanged The named font is not installed or its web font failed to load. Check the runtime font inventory and browser network/font loading; restart after installation.
ChromeDriver session fails to start Browser/driver compatibility or setup issue, not necessarily a glyph issue. Check Chrome and ChromeDriver major versions and Selenium’s Chrome setup guidance.
Headless and headed images differ Some other condition may differ between runs, such as fonts, viewport, page state, or browser build. Hold those inputs constant and compare again; treat mode as a diagnostic variable.

Performance, reliability, and cost

Font installation is a deployment concern: bake required fonts into the image that runs Chrome so CI jobs do not depend on workstation state. Reuse a stable browser image and pin compatible browser/driver versions for reproducibility. The sources provide no benchmark for the relative speed of font stacks or Linux font packages, so choose by glyph coverage and visual match rather than an assumed performance ranking. Browser-based capture cost and runtime depend on your own infrastructure and page behavior.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a screenshot or PDF; see the API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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 accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents screenshot tools. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account to get 1,000 screenshots per month with no card.

FAQ

Does Selenium render Hindi text itself?

No. Selenium controls the browser; the browser and its font environment render the glyphs.

Will upgrading Chrome always fix missing Hindi glyphs?

No. Browser builds can differ in font mappings, but the runtime still needs an available font with the required glyphs.

Should I use Noto Sans or Noto Serif Devanagari?

Choose the family that matches the page’s intended typography, then include the corresponding general family and a generic fallback.

Is headless Chrome the cause?

Not by itself according to the cited documentation. Compare modes under controlled conditions to diagnose a difference.