ScreenshotNeo

BlogHow-to

How to screenshot an Indian-language webpage with Puppeteer in Node.js

Capture Indian-language webpages with Puppeteer, wait for content and fonts, and fix missing glyphs by checking font coverage and the browser environment.

By the ScreenshotNeo team4 October 20268 min read

To screenshot an Indian-language webpage with Puppeteer, navigate to the page, wait for its meaningful content and available fonts to load, then call page.screenshot(). If characters appear as empty boxes, the screenshot call may have worked while Chromium lacked a font that covers the page’s actual script. Check font loading and coverage in the same operating system or container that produces the image.

“Indian language” is not one font-coverage target. Identify the scripts on the page—such as Devanagari, Tamil, Bengali, Telugu, Kannada, Malayalam, Gujarati, Gurmukhi, or Odia—and inspect the output for missing glyphs, broken conjuncts, clipping, and unexpected fallback.

1. Install Puppeteer and run a screenshot

The puppeteer package downloads a compatible Chrome for Testing browser during installation. Use this when you want Puppeteer to manage its browser. The puppeteer-core package does not download a browser and is intended for a browser you manage separately or access remotely. Check the installation guide for the version and environment you use, since supported Node.js and browser requirements can change. Puppeteer installation guide

npm install puppeteer

Save the following as screenshot.mjs, replace the example URL with the target page, and run it with Node.js:

import puppeteer from 'puppeteer';

const url = 'https://example.com/page-in-indian-language';
const browser = await puppeteer.launch();

try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 1000, deviceScaleFactor: 1 });

  await page.goto(url, { waitUntil: 'networkidle2' });

  // Wait for the page's available web fonts to finish loading.
  await page.evaluate(() => document.fonts.ready);

  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

networkidle2 is a navigation readiness condition used in Puppeteer’s screenshot guide. It does not prove that an application has finished rendering meaningful content. If the page is client-rendered or loads content lazily, wait for a page-specific selector or state before capturing. Puppeteer’s screenshot guide shows page and selected-element captures: Screenshots guide.

2. Wait for the right content and fonts

document.fonts.ready resolves when the document’s font loading and related layout work have settled for the fonts the page has requested. It does not install a missing font, prove that every character has a suitable glyph, or guarantee the page’s application content is ready.

When the page has a reliable ready marker, wait for it explicitly. For example, if the rendered article is placed in main article, add this after navigation and before the font wait:

await page.waitForSelector('main article', { visible: true });
await page.evaluate(() => document.fonts.ready);

Use a selector that means the content you need is actually present; a generic body selector may exist before client-side rendering finishes. If a page’s text is inserted after a known interaction or API response, wait for that specific state as well.

Do not assume screenshot capture has the same font-wait behavior as PDF generation. Puppeteer’s PDF guide documents waiting for fonts by default for PDF output; use an explicit font readiness wait in screenshot code. PDF generation guide

3. Diagnose missing or incorrect Indian-language glyphs

  1. Identify the script in the actual content. A language name does not tell you whether a page includes one script or several. Pages may also mix Indic scripts with Latin numerals, punctuation, or names.
  2. Check whether the intended web font loaded. In browser DevTools, inspect the page’s font network requests and console errors. A failed font request or incorrect CSS font-family can make Chromium fall back to another font.
  3. Confirm that a loaded or installed font covers the needed characters. A font can load successfully and still lack glyphs for some characters. Use a font that covers the script and text in question, either supplied by the page or installed/bundled in the rendering environment.
  4. Inspect the PNG itself. Look for tofu boxes, missing vowel signs, broken conjuncts, fallback changes within a word, clipping, or unexpected line wrapping. A successful page.screenshot() call only means an image was captured; it does not validate glyph correctness.
  5. Reproduce in the production environment. If a local machine looks right but a Linux container does not, compare installed fonts, browser version, and platform dependencies. Install or bundle the needed fonts in the environment that actually captures the page.

Changing screenshot options alone cannot provide glyphs that no available font contains. Puppeteer’s troubleshooting documentation includes platform-specific browser dependency guidance and example font packages; use the instructions applicable to your target image rather than assuming one package list fits every system. Puppeteer troubleshooting

4. Capture a selected element instead of the whole page

If you only need the language content, capture its element. This can avoid unrelated page regions and produce a smaller image. The selector must match an element present after the page has rendered.

const article = await page.waitForSelector('main article', { visible: true });
await page.evaluate(() => document.fonts.ready);
await article.screenshot({ path: 'article.png' });

For full-page capture, use { fullPage: true } as in the first example. Long pages may load images or text only when scrolled into view. If the target uses lazy loading, scroll through the page and wait for its content before capturing; a full-page screenshot option does not itself establish that every lazy resource has loaded. Puppeteer documents screenshots of selected elements and pages in its screenshot guide.

5. Choose the browser installation model

Setup Use it when Font responsibility
puppeteer You want Puppeteer to download a compatible Chrome for Testing browser. Ensure the capture environment has suitable fonts; browser download does not guarantee coverage for every script.
puppeteer-core You manage the browser yourself or connect to a remote browser. Manage fonts and browser dependencies on the machine or service that renders the page.

If an installation environment blocks package install scripts, Puppeteer’s installation documentation explains how to install the browser separately. Consult the official guide for the applicable package-manager and browser setup details: Installation.

6. Troubleshooting common problems

Symptom Likely cause What to do
Characters show as empty squares or boxes. No available font covers one or more required glyphs, or the intended font failed to load. Check font requests and CSS, then install or bundle a font with coverage for the actual script in the capture environment.
Some letters render while others are boxes. The selected font covers only part of the page’s characters or mixed scripts. Check all scripts and characters on the page, including punctuation and numerals; verify a fallback font can cover the missing glyphs.
Conjuncts or marks look wrong. A fallback font, incomplete font coverage, or different rendering environment may affect shaping. Confirm the intended font loaded and compare the output on the production operating system and browser setup.
The screenshot has old or incomplete text. Navigation became idle before client-side rendering or a later content update completed. Wait for a page-specific selector or application state, then wait for document.fonts.ready.
Text wraps or clips differently in a container. Fonts, viewport dimensions, scale factor, or browser environment differ from local capture. Use a fixed viewport and device scale factor, install the same font assets, and inspect output from the target container.
Puppeteer cannot launch Chrome. The browser is missing, installation scripts were blocked, or platform dependencies are unavailable. Follow the installation and troubleshooting guidance for the exact environment; verify the managed browser was installed or configure the browser you manage.
networkidle2 never arrives or is too slow. The page keeps network connections open, or the target has slow third-party resources. Choose a readiness condition suited to the page, such as a meaningful selector; do not treat network idleness as the only signal of content readiness.

7. Performance, reliability, and cost

Launching a browser has more overhead than capturing another page in an already-running browser. For repeated captures, reuse a browser process where appropriate, create a fresh page for each capture, and close pages and the browser when finished. Limit parallel pages to what the host can support; each page consumes memory and CPU, and the target website may impose its own limits.

Reliability depends on the target page as well as Puppeteer: network delays, scripts, third-party fonts, lazy loading, and changing page structure can all affect the result. Prefer an explicit content-ready condition over a fixed sleep when the page exposes a stable selector. Keep the viewport and capture environment consistent if screenshots are compared over time. Inspect representative output images because navigation success does not validate the rendered script.

Self-hosted Puppeteer has no per-screenshot API charge, but browser compute, memory, storage, font setup, and maintenance consume infrastructure and engineering time. The cost depends on your runtime and capture volume; measure it in the environment you operate rather than relying on a universal benchmark.

8. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. Its capture flow accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each of those steps can be turned off. Check the ScreenshotNeo documentation for request options and configuration.

For an Indian-language page, pass its URL and save the returned image. Confirm the rendered output for the target script, just as you would with a self-hosted browser.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/page-in-indian-language -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://example.com/page-in-indian-language",
    },
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/page-in-indian-language',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

The Node.js snippet uses Bun’s Bun.write to save the response. With Node.js, use this equivalent file-saving version:

import { writeFile } from 'node:fs/promises';

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/page-in-indian-language',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
  • Cookie banners, popups, and chat widgets are removed before the shot.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed. Response headers report the page verdict and billing status.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Every feature is on every plan.

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

9. FAQ

Does Puppeteer need a special Indian-language screenshot option?

No. Use Puppeteer’s regular screenshot method and make sure Chromium has an appropriate font for the characters the page renders.

Will document.fonts.ready fix missing characters?

No. It waits for font loading to settle; it does not add fonts or guarantee their character coverage.

Should I use puppeteer or puppeteer-core?

Use puppeteer when you want Puppeteer to download a compatible browser. Use puppeteer-core when you provide or connect to a separately managed browser.

Where can I check the current Node.js requirement?

Check Puppeteer’s system requirements for the version you install; requirements can change.

Sources