Capture a Website Screenshot in Hindi with Node.js and Puppeteer on Ubuntu
Capture a web page containing Hindi text with Node.js and Puppeteer on Ubuntu. Set up Chrome, install a Devanagari font, and choose viewport or full-page output.
Use Puppeteer to launch Chrome, open the target page, wait for its content to be ready, and save a screenshot. Hindi glyphs render only when Chrome can access a font with Devanagari coverage, so install and verify such a font on the Ubuntu host as well as configuring the browser capture.
This guide uses Puppeteer 25.12.0 documentation as its version reference. That version requires Node.js 22.12 or newer and lists Debian/Ubuntu on x64 and arm64 for Chrome for Testing support; check the current requirements for your installed Puppeteer version before setup. Puppeteer system requirements
1. Check Node.js and install Puppeteer
On the machine that will run Chrome, check the Node.js version:
node --version
npm --version
For the documented Puppeteer 25.12.0 release, Node.js must be 22.12 or newer. If your Node version is older, install a supported version using the Node.js distribution method you already manage on that host, then check the version again.
Create a small project and install Puppeteer:
mkdir hindi-screenshot
cd hindi-screenshot
npm init -y
npm install puppeteer
The puppeteer package downloads a compatible Chrome for Testing build during installation. Its browser needs Linux system libraries; if installation or launch reports a missing shared library, use the Ubuntu/Debian dependency guidance in Puppeteer’s troubleshooting documentation. Package requirements can vary with Ubuntu release and browser build.
2. Make a Devanagari font available
Chrome needs an installed or page-loaded font that contains the Hindi glyphs. On a minimal Ubuntu image, do not assume one is present. Ubuntu’s fonts-noto-core package includes Noto Sans Devanagari regular and bold font files in the cited package records.
sudo apt update
sudo apt install fonts-noto-core
Confirm the font files exist on the host before capturing:
ls /usr/share/fonts/truetype/noto/NotoSansDevanagari-Regular.ttf
ls /usr/share/fonts/truetype/noto/NotoSansDevanagari-Bold.ttf
These paths apply to the Ubuntu package records cited here; if a path differs on your release, inspect the installed package contents. Installing a system font makes it available to Chrome, but it does not force the website to use that font. The page’s CSS and font fallback rules still determine which font is selected.
If the page uses a remote web font, its download and application are site-specific. Wait for a page-specific ready signal when possible, then inspect the saved image for missing-glyph boxes or fallback typography. A fixed sleep does not guarantee that a web font has loaded.
3. Capture the page with Puppeteer
Save the following as capture.mjs. Replace the URL and output path. This example sets a predictable viewport, waits for a common network-idle condition, and captures the entire document.
import puppeteer from 'puppeteer';
const url = 'https://example.com';
const outputPath = 'website-hi.png';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setViewport({ width: 1365, height: 900 });
await page.goto(url, {
waitUntil: 'networkidle2',
timeout: 60_000,
});
await page.screenshot({
path: outputPath,
fullPage: true,
});
console.log(`Saved ${outputPath}`);
} finally {
await browser.close();
}
Run it with:
node capture.mjs
Puppeteer’s Page.screenshot() saves to the supplied path. The filename extension can determine the image format; use a .png, .jpg, or .webp path as appropriate for the format supported by your Puppeteer version. fullPage defaults to false; setting it to true captures beyond the viewport. See the screenshot API and screenshots guide.
4. Choose viewport or full-page capture
| Goal | Setting | Result |
|---|---|---|
| Capture what is currently visible | Omit fullPage or set it to false |
Captures the viewport only. |
| Capture the whole document | fullPage: true |
Extends the image to include content beyond the viewport. |
| Capture a particular component | Use an element handle’s screenshot() |
Captures that element, scrolling it into view if needed. |
Viewport width and height affect responsive layout and the visible area. Puppeteer’s headless screen defaults to 800×600 unless a window size is specified. Setting the page viewport is useful for choosing the page layout; use --window-size at launch when you need to configure the headless screen itself. A larger viewport does not supply missing Hindi fonts. Puppeteer screen configuration
Capture one element
For a component screenshot, wait for its selector and call the element handle’s screenshot method:
const card = await page.waitForSelector('.article-card');
if (!card) throw new Error('Article card was not found');
await card.screenshot({ path: 'article-card.png' });
Replace .article-card with a selector from the target page. Element screenshots are useful when the full document is long or only one Hindi text block is needed. See ElementHandle.screenshot().
5. Wait for the page content you need
networkidle2 is a navigation wait condition, not proof that every image, application update, or remote font has finished rendering. For dynamic pages, wait for a page-specific element or application signal:
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
await page.waitForSelector('.article-content', { timeout: 30_000 });
await page.screenshot({ path: 'article.png', fullPage: true });
If a remote font is central to the result, the page may expose a site-specific readiness signal you can wait for. You can also wait for the browser’s font readiness promise, but this only reflects fonts known to the document at that point; inspect the screenshot to confirm the intended glyphs and font actually appeared.
await page.evaluate(() => document.fonts.ready);
await page.screenshot({ path: 'article.png', fullPage: true });
6. Configure Chrome and screenshot output
- Browser executable: Puppeteer normally uses its downloaded Chrome for Testing build. If you intentionally manage a separate Chrome installation, Puppeteer’s launch options can select an executable path; keep the browser version compatible with Puppeteer.
- Linux libraries: Chrome may exit if required shared libraries are absent. Follow the current Puppeteer troubleshooting list for your Ubuntu version. The guide suggests using
lddto identify missing shared libraries in the browser executable. - Sandbox: Keep Chrome’s sandbox enabled where the host allows it. Puppeteer says running without a sandbox is strongly discouraged. Do not use
--no-sandboxas a routine fix. Ubuntu 23.10 and newer can have an AppArmor restriction affecting user namespaces for Puppeteer-downloaded Chrome for Testing under certain profile and path conditions; follow the documented host-specific workaround. - Viewport: Choose dimensions that match the layout you need to inspect. Responsive pages may show different content at different widths.
- Image type: Use a matching output extension and screenshot type supported by your Puppeteer version. PNG is a straightforward choice for text-heavy images.
- Page state: Authentication, consent banners, animations, lazy-loaded content, and site-specific scripts can change what appears. Arrange the state required by your use case before capturing.
For launch configuration details, see Puppeteer’s LaunchOptions reference.
7. Troubleshoot common problems
| Symptom | Likely cause | What to do |
|---|---|---|
| Hindi characters appear as empty boxes | Chrome cannot find a font with Devanagari coverage, or the intended web font has not loaded. | Install a Devanagari-capable font such as the files provided by fonts-noto-core, wait for the page’s font or content readiness condition, and inspect the output. Check the page’s CSS font fallback if the font is installed. |
Failed to launch or a shared library error |
A Chrome Linux dependency is missing. | Follow the current Puppeteer Ubuntu/Debian dependency list. Use ldd on the Chrome executable to locate unresolved libraries, then install the packages matching the host release. |
| Chrome exits with a sandbox or namespace error | The host’s security configuration may prevent Chrome’s sandbox from starting. On some Ubuntu 23.10+ setups, AppArmor affects user namespaces for the downloaded browser. | Check Puppeteer’s troubleshooting documentation for the exact Ubuntu release and browser location. Preserve sandboxing if possible; disabling it is strongly discouraged. |
| Screenshot is only 800×600 or the layout is unexpected | The default headless screen is 800×600, or the page viewport was not set as intended. | Set the viewport explicitly with page.setViewport(); if needed, configure the headless screen with --window-size. Check the target’s responsive breakpoints. |
| Some content is missing from a full-page image | Content may load after navigation, depend on scrolling, or be added by client-side code. | Wait for the page-specific selector or ready signal. For lazy-loaded content, scroll through the page or trigger the target site’s loading behavior before capturing, then inspect the image. |
| Navigation times out on an otherwise usable page | The site may keep network requests open, making a network-idle condition unsuitable. | Use a less restrictive navigation condition such as domcontentloaded, then wait for a specific content selector. Set a timeout appropriate to the host and target. |
| Capture works locally but not in a container | The container may lack fonts or Chrome libraries, or may impose sandbox restrictions. | Install the same required packages and Devanagari fonts in the runtime image, and check the container’s security profile. Reproduce the capture environment rather than relying on host-installed files. |
8. Reliability, performance, and cost
Run Puppeteer in a managed process that always closes the browser, as in the try/finally example. Set navigation and selector timeouts so a stalled target does not hang a job indefinitely. For repeatable images, pin your Node.js and Puppeteer versions, use a known browser build, install the same font packages in each environment, and keep viewport dimensions fixed. A successful navigation does not guarantee that a particular site’s fonts or dynamic content are ready, so validate the produced image when correctness matters.
Full-page images can be much taller than viewport captures, increasing rendering work, memory use, and output size. Capture only the necessary region when possible, and use a viewport screenshot or element screenshot for focused checks. Local Puppeteer has no per-screenshot API fee, but your runtime still uses CPU, memory, storage, and maintenance time; browser updates and Linux dependencies need ongoing attention. The appropriate cost depends on where and how often you run it.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Send one GET request to capture a URL as an image or PDF; see the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. 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 to get 1,000 screenshots a month with no card.
Frequently asked questions
Can Puppeteer render Hindi text without changing the website?
Usually, if a font available to the page contains the required Devanagari glyphs and the page’s font fallback can select it. Installing a system font helps Chrome find glyphs, but the page’s CSS and any remote font loading still affect the final appearance.
Should I use PNG or JPEG for Hindi text?
PNG is a practical default for screenshots with text and sharp edges. Choose another supported format when file size or an existing image pipeline calls for it, and check the result at its intended display size.
Does full-page capture include content that loads only when scrolled?
It captures beyond the viewport, but page-specific lazy-loading behavior can still affect what is present. Scroll or trigger the site’s loading behavior and verify the resulting image when those sections matter.
Why does a screenshot differ between two Ubuntu machines?
They may have different browser builds, fonts, viewport settings, page state, or system dependencies. Align those inputs and wait for the same page-ready condition to improve repeatability.


