Puppeteer Screenshot of a Tamil Web Page: Fix Missing Glyphs on Ubuntu
Fix missing Tamil glyphs in Puppeteer screenshots on Ubuntu by checking font coverage, web-font loading, and the exact browser runtime.
If Tamil letters appear as empty boxes, replacement characters, or incomplete shapes in a Puppeteer screenshot, first check which fonts are available to the Chromium process that takes the screenshot. The fonts installed on your workstation may not exist in the Ubuntu container or CI runner. Install or provide a Tamil-capable font in that runtime, confirm the page uses it, and wait for any web font to finish loading before capturing.
Noto Tamil is a suitable font family to investigate. Ubuntu’s Jammy package catalogue describes fonts-noto-core as including “No Tofu” font families with broad Unicode coverage, but package names and contents can vary by Ubuntu release. Check the release actually used in deployment. The Noto Tamil project records Noto Sans Tamil UI builds and the SIL Open Font License 1.1.
1. Identify which layer is failing
Keep these failure types separate. A missing glyph after the page has rendered points toward font coverage, CSS selection, or font loading. A browser that cannot start has a browser installation, Linux dependency, or sandbox issue; installing a font will not repair it.
| Symptom | First place to check |
|---|---|
| Boxes or missing shapes only in the screenshot runtime | Fonts installed in the host, container, or CI image that launches Chrome |
| Some Tamil characters work and others do not | Whether the selected font covers the exact code points in the page |
| Fallback font appears despite a declared web font | Font request failures, CSP, @font-face URL, and font loading timing |
Failed to launch or missing shared library |
Chrome installation, Linux dependencies, and sandbox environment |
Reproduce the issue using the same Ubuntu image, Chromium executable, environment variables, and user context as the failing job. A successful screenshot from a developer laptop does not establish that the CI runtime has the same fonts.
2. Install and verify a Tamil font on Ubuntu
On an Ubuntu image where the package is available, install the Noto core fonts package in the image or host that runs Chrome. The cited Ubuntu package details are for Jammy, so first check the package catalogue for your release.
sudo apt-get update
sudo apt-get install -y fonts-noto-core
fc-cache -f
Check the fontconfig view from the same environment and user account that will launch Puppeteer:
fc-list : family | grep -i 'Noto Sans Tamil\|Noto Tamil'
fc-match 'Noto Sans Tamil'
These commands help establish whether fontconfig can find a matching family; they do not prove that every character on the target page is covered or that CSS selects the face. If the package does not provide the family in your particular release, inspect that release’s packages or bundle a suitable font asset with your application. When bundling a font, retain its license and attribution requirements; Noto Tamil identifies its license as SIL Open Font License 1.1.
3. Confirm page CSS and wait for web fonts
If the site supplies its own font, verify its @font-face URL, network response, and Content Security Policy. A failed web-font request can silently leave Chromium using a fallback font without Tamil coverage. For a controlled test page, explicitly request the candidate family and include a fallback stack:
<style>
body {
font-family: "Noto Sans Tamil", "Noto Sans", sans-serif;
}
</style>
Do not assume that declaring a family means the browser loaded it. Inspect computed styles for the Tamil text element and check DevTools or the page’s network logs for font failures. A font stack can select different faces for different characters, so inspect representative text from the actual page.
For a web-delivered font, await the browser’s font set before taking the screenshot. Here is a complete Node.js example using Puppeteer:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com/tamil-page', {
waitUntil: 'networkidle0',
timeout: 60000,
});
await page.evaluate(async () => {
await document.fonts.ready;
});
const fontInfo = await page.evaluate(() => {
const sample = document.querySelector('body');
return {
computedFamily: getComputedStyle(sample).fontFamily,
fontStatus: document.fonts.status,
};
});
console.log(fontInfo);
await page.screenshot({ path: 'tamil-page.png', fullPage: true });
} finally {
await browser.close();
}
})();
Replace the example URL with the page under investigation. networkidle0 is useful for many pages, but pages with persistent connections may never become idle; in that case use a more suitable navigation condition and wait explicitly for the relevant selector and document.fonts.ready. The computed family string reports CSS selection, not definitive per-glyph coverage.
4. Capture a minimal reproduction
When the full site is complex, isolate a short representative Tamil string in a minimal page. Run the fixture in the target Ubuntu runtime, wait for fonts, and inspect the resulting image. Include characters from the affected text rather than relying on a generic sample. If the fixture works but the real page does not, investigate its CSS, font requests, CSP, and timing. If both fail, investigate runtime font availability and coverage.
For repeatable deployments, bake the needed package or licensed font assets into the container image instead of installing fonts only during an interactive debugging session. This makes the browser’s font environment part of the deployment configuration and reduces differences between machines.
5. Check Puppeteer and Chrome startup separately
Puppeteer’s browser download and browser launch are separate from font rendering. Puppeteer normally downloads Chrome for Testing during installation, but package managers that suppress install scripts can leave the browser missing. The documented recovery command is:
npx puppeteer browsers install
If Chrome is present but will not launch, inspect Linux shared library dependencies using Puppeteer’s suggested check (run it against the Chrome executable used by Puppeteer):
ldd /path/to/chrome | grep not
Install the missing libraries appropriate to the Ubuntu release and image. Puppeteer’s troubleshooting guide also documents an AppArmor-related sandbox issue affecting Puppeteer-downloaded Chrome for Testing on Ubuntu 23.10 and newer. Diagnose that as a launch issue. Puppeteer strongly discourages disabling Chrome’s sandbox; do not use --no-sandbox as a font fix.
6. Troubleshooting checklist
| Problem | Likely cause | Action |
|---|---|---|
| Tamil is correct locally but boxed in CI | The CI image lacks the local machine’s font | Install or bundle a Tamil-capable font in the image that launches Chromium; verify with fontconfig there. |
| Font package installs, but glyphs remain missing | The selected face lacks a needed glyph, or CSS chooses another face | Inspect the exact characters, computed styles, and font matching; test a known Tamil-capable family explicitly. |
| A site’s web font is declared but not used | Font request failed, was blocked, or had not finished loading | Check network errors, CSP, and @font-face paths; wait for document.fonts.ready. |
| Only some text is wrong | Mixed fonts, fallback behavior, or characters outside the chosen face’s coverage | Test a minimal sample containing the affected characters and inspect how the page styles the specific element. |
| Screenshot is taken too early | Rendering begins before web fonts finish loading | Wait for the relevant page state and font set before page.screenshot(). |
| Puppeteer cannot find Chrome after install | Install scripts were skipped or browser installation did not run | Run npx puppeteer browsers install as documented, then confirm the executable path. |
| Chrome reports a missing library | Required Linux shared library is absent | Use ldd chrome | grep not and add the release-appropriate dependency. |
| Chrome fails with a sandbox or AppArmor error | Host security configuration or browser sandbox startup problem | Follow Puppeteer’s Linux troubleshooting guidance for the actual Ubuntu release; keep the sandbox enabled where possible. |
7. Performance, reliability, and cost
Installing a font in the base image adds an image-build dependency and may increase image size; bundling a font adds asset and license management. Either approach can make captures more reproducible when the font is available before Chrome starts. Waiting for all network activity to stop can add latency or stall on pages with long-lived requests, so use an appropriate navigation condition and wait for the font and content that matter.
For reliability, capture from the same immutable runtime image used in production, log navigation and font request failures, and inspect a representative screenshot after changing fonts or browser versions. No specific Tamil rendering result can be assumed without checking the image from the target runtime.
The local method uses Puppeteer and Ubuntu packages; its direct usage cost depends on the compute environment you already operate. Account for browser installation, image maintenance, and capture execution when comparing it with a hosted screenshot service.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. It takes a URL in one GET request and returns a screenshot image or PDF. For a quick capture, save the response as a WebP file:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/tamil-page -o shot.webp
See the ScreenshotNeo API documentation for the request options and response details. Cookie and consent banners, newsletter popups, and chat widgets are removed before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers identify the page verdict and billing status. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card, and 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 installing Noto Tamil guarantee every Tamil glyph will render?
No. Confirm the actual characters are covered and that Chromium selects a loaded face for the text. A page’s own CSS or web font can change which face is used.
Should I add --no-sandbox to fix boxes in Tamil text?
No. Sandbox configuration concerns browser startup and security, not glyph coverage. Diagnose font availability and rendering separately from launch errors.
Why does the Ubuntu package command differ from another guide?
Package availability and contents depend on the Ubuntu release. Check the catalogue for the exact release used by your host or container rather than assuming Jammy metadata applies.
Can a screenshot service guarantee the same font rendering as my Ubuntu container?
Do not assume so. If exact rendering matters, verify the rendered image in the target environment and confirm the font and page configuration used there.
Sources
- Puppeteer installation guide: browser download behavior and manual installation.
- Puppeteer troubleshooting: Linux dependencies, Docker, and AppArmor considerations.
- Noto Tamil project: project and license information.
- Ubuntu Jammy fonts-noto-core package: release-specific package description.


