ScreenshotNeo

BlogHow-to

Fix Hindi Fonts and Text in Puppeteer Screenshots

Fix missing or incorrect Hindi text in Puppeteer screenshots by checking font coverage, Linux and Docker fonts, and capture timing.

By the ScreenshotNeo team4 October 20266 min read

If Hindi text is missing, shown as boxes, or rendered with unexpected glyphs in a Puppeteer screenshot, check three things in order: the CSS font stack includes a Devanagari font, that font is installed where Chromium actually runs, and the page has finished loading fonts before capture. Puppeteer captures the rendered page; Chromium and the fonts available to its browser process determine how Hindi glyphs are shaped and displayed.

1. Narrow down the rendering problem

Use the same URL, viewport, and page state for each comparison. Check whether every Hindi character is affected or only some glyphs, whether the result shows boxes or blank spaces, and whether the same page looks correct in local Chrome. These observations help identify the likely layer; they are diagnostic questions, not proof of one universal failure mode.

  1. Save a screenshot from the environment where the output is wrong.
  2. Open the same URL in the local browser and compare at the same viewport.
  3. Compare the CSS font-family stack, available font files, browser executable, and capture timing between the two environments.

2. Choose a font stack with Devanagari coverage

Listing a font in CSS does not install it. The browser tries the requested families in order, using a family that has the required character when available; if no listed available font has that glyph, it falls back to a system default. For Hindi sans-serif text, Noto’s guidance recommends a script-specific Noto Sans Devanagari family followed by the general Noto Sans family.

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

Apply the stack to the element that actually contains the Hindi text. If a more specific CSS rule overrides body, update that rule or inspect the computed style in the page.

3. Install the font in the browser’s runtime environment

For Linux or Docker deployments, the font must be present on the host or in the image where Chromium runs. Installing it on a developer workstation does not make it available inside a container. Add an appropriate Devanagari font package or bundle the font files for your base image, rebuild the image, and capture again.

Package names and installation steps vary by Linux distribution and container base image. Check Puppeteer’s current Linux troubleshooting guidance and the package documentation for your chosen image before copying a Docker snippet. Puppeteer’s troubleshooting page discusses Linux dependencies and container font installation: Puppeteer troubleshooting.

When local output is correct but deployed output is not, compare these items side by side:

  • Which font files are installed and whether they contain the affected Devanagari glyphs.
  • The CSS fallback order and the computed font-family for the Hindi element.
  • The Linux distribution and container base image.
  • The browser package and executable used by each environment.
  • Whether the screenshot waits for the page’s fonts to become ready.

4. Wait for fonts before taking the screenshot

After navigation, wait for the document’s font-loading set to become ready before capturing. This is a useful diagnostic and synchronization step: it helps avoid capturing while a web font is still loading. It does not install a missing font or add glyph coverage that the available fonts lack.

const puppeteer = require("puppeteer");

async function capture(url) {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1280, height: 900 });
    await page.goto(url, { waitUntil: "networkidle0" });
    await page.evaluate(() => document.fonts.ready);
    await page.screenshot({ path: "page.png", fullPage: true });
  } finally {
    await browser.close();
  }
}

capture("https://example.com").catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

networkidle0 waits for network activity to settle, which may not happen on pages with persistent requests. If navigation never settles, choose a navigation condition appropriate to the site, then separately wait for a page-specific selector or font readiness. The font-ready wait is the important part of this check.

5. Check Puppeteer’s browser and runtime setup

The standard puppeteer package downloads a compatible Chrome for Testing browser during installation. puppeteer-core does not manage the browser download, so you must provide and manage an executable yourself. When using a custom executable or container, check that the selected browser runs in the same environment where the fonts are installed.

See the Puppeteer installation guide and troubleshooting guide for current setup details. Compare the browser package and executable path when local and deployed screenshots differ. Browser version, operating system, font availability, and fallback behavior can all affect rendering; the documented setup does not guarantee pixel-identical output across environments.

6. Troubleshoot common symptoms

Symptom Likely cause What to check or change
Hindi characters appear as boxes or blank spaces No available font has the required glyphs, or the intended font is missing in the runtime. Confirm a Devanagari-capable font is installed where Chromium runs; use a stack such as "Noto Sans Devanagari", "Noto Sans", sans-serif.
Output differs between local and Docker The environments have different fonts, fallback order, browser setup, or capture timing. Compare the installed fonts, computed CSS, base image, executable, and font-ready wait using the same URL and viewport.
The page is captured with a temporary or fallback appearance Capture may happen before a web font finishes loading. Wait for document.fonts.ready before taking the screenshot. If the font request fails, fix that request or provide the font locally.
Waiting for networkidle0 hangs or takes too long The page may keep network requests active. Use a navigation wait condition that fits the page, then wait for a meaningful selector and document.fonts.ready.
The CSS names Noto, but the rendering is unchanged A font-family name in CSS does not make the font available to Chromium. Install or bundle the font in the browser’s host or container, rebuild the image, and capture again.
Only a few characters render incorrectly The available font coverage or a more specific CSS rule may differ for those characters. Inspect computed styles and check the selected font’s coverage for the affected glyphs; compare the fallback stack.
Browser launch fails after changing the image The image may lack browser dependencies or may use a different executable setup. Follow current Puppeteer Linux troubleshooting for the chosen distribution and verify the browser binary is available in that runtime.

7. Reliability, performance, and cost considerations

Waiting for font readiness can add time when fonts are still loading, but it prevents the capture from racing ahead of that page state. Waiting for all network activity to stop can be a larger source of delay on pages with long-lived requests, so pick navigation and selector waits to match the site.

For repeatable captures, keep the browser, operating system image, font files, CSS stack, viewport, and page state consistent. Rebuild and redeploy the image after changing installed fonts. No universal Hindi rendering failure rate or cross-platform pixel match is established by the cited guidance, so validate the actual page and runtime you use.

With a self-managed Puppeteer setup, account for the work of maintaining the browser runtime and font packages in your deployment. If you prefer a screenshot API, ScreenshotNeo takes a website URL in one request and returns an image or PDF; its stated plans start at $5 for 3,000 shots, with 1,000 per month free.

Or skip the browser setup

ScreenshotNeo takes a URL and returns a screenshot. Its capture accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.

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

See the ScreenshotNeo API documentation for request options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up for ScreenshotNeo and get 1,000 free screenshots a month, with no card.

FAQ

Will waiting for document.fonts.ready install Hindi fonts?

No. It waits for font loading to settle. The font files still need to be available to the browser, and the chosen family needs the required glyphs.

Can a screenshot API fix a missing Hindi font in my page?

A screenshot service captures how the page renders in its browser environment. For a page that depends on a particular font, ensure the page can load that font and verify the resulting image. ScreenshotNeo’s documented cleanup focuses on consent banners, popups, and chat widgets; the product facts here do not promise Hindi font repair.

Will Puppeteer screenshots look identical on every Linux image?

No universal pixel-identical rendering guarantee follows from the browser and font setup guidance. Keep the runtime and fonts consistent, then compare the output in the environment that matters.

Where should I report a problem with my container setup?

Start with Puppeteer’s current troubleshooting guidance and the documentation for the exact Linux distribution and base image you deploy.