ScreenshotNeo

BlogHow-to

How to Capture a Right-to-Left Arabic Web Page Screenshot in Chrome Headless

Set Arabic page direction correctly, capture it with Chrome Headless or Puppeteer, and fix common issues with mixed text, fonts, and page readiness.

By the ScreenshotNeo team4 October 20268 min read

For a page whose main content is Arabic and reads right to left, declare both its language and direction in the document HTML: <html lang="ar" dir="rtl">. Then capture it with Chrome Headless using --screenshot and an explicit --window-size. Use Puppeteer when you need a repeatable script, a full-page image, or a screenshot of one element.

A screenshot command captures the page as it renders; it does not repair incorrect HTML direction, missing Arabic fonts, or content that has not finished loading. The examples below cover those parts as well as viewport, full-page, and element captures.

1. Set the page language and direction

On a page you control, put lang="ar" and dir="rtl" on the root <html> element:

<!doctype html>
<html lang="ar" dir="rtl">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>مثال</title>
  </head>
  <body>
    <main>
      <h1>مرحباً بكم</h1>
      <p>هذه صفحة عربية من اليمين إلى اليسار.</p>
    </main>
  </body>
</html>

lang identifies the document language; dir sets its base writing direction. They are separate declarations. The W3C recommends using the HTML dir attribute for base direction and declaring the language with lang. Do not use CSS as the mechanism for setting the base direction of HTML text. [W3C: HTML text direction]

Direction belongs to the script and text content, not just the language label. A page can contain Arabic paragraphs alongside Latin product names, URLs, numbers, or code. Those mixed-direction runs may need their own markup or isolation, especially if punctuation appears on an unexpected side. [W3C: Inline markup and bidirectional text]

If you are capturing a third-party page, you usually cannot change its HTML. The capture will reflect the page’s existing direction settings and styles. You can use a browser automation script to inspect the rendered result, but do not assume a screenshot option can fix a page’s direction.

2. Capture a viewport with Chrome Headless

For a one-off viewport screenshot, run Chrome with a target viewport size and URL:

chrome --headless --screenshot --window-size=1280,1000 --timeout=5000 'https://example.com/'

Chrome saves screenshot.png in the current working directory. Change the URL and dimensions for your page and desired viewport. --timeout is a maximum wait in milliseconds before capture; it does not prove that every asynchronous element, image, or font is ready. [Chrome Headless documentation]

To make the capture predictable, run the command from a directory where you can write the output file, use the same Chrome installation and environment you intend to use in production, and set the window size explicitly. The CLI example captures a viewport. For explicit full-page, element, or scripted readiness control, use Puppeteer.

3. Use Puppeteer for repeatable captures

Install Puppeteer in a Node.js project using the package manager and version appropriate to your environment, then save this as an ES module such as capture.mjs. Pin the Puppeteer version in production and consult the documentation matching that version because the live API can evolve.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 1000 });
  await page.goto('https://example.com/', { waitUntil: 'networkidle2' });
  await page.screenshot({ path: 'arabic-page.png', fullPage: true });
} finally {
  await browser.close();
}

Page.screenshot() takes the capture. fullPage: true requests the full document rather than just the current viewport; it defaults to false. Puppeteer also provides element screenshots and a clip region for capturing a selected part of the page. [Puppeteer screenshot guide] [Puppeteer screenshot options]

Capture a single element

Wait for the target element, then call its screenshot method. Use a selector that is specific to the content you need:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 1000 });
  await page.goto('https://example.com/', { waitUntil: 'networkidle2' });
  const article = await page.waitForSelector('main article');
  if (!article) throw new Error('Article element was not found');
  await article.screenshot({ path: 'arabic-article.png' });
} finally {
  await browser.close();
}

The selected element must exist and be in a capturable state. If the selector matches several elements, make it more specific or select the intended match explicitly. For a rectangular region not tied to an element, use the documented clip screenshot option and ensure the coordinates and dimensions fit the rendered page. [Puppeteer screenshot options]

Choose a readiness condition

The example uses waitUntil: 'networkidle2' as a navigation condition. Pages with persistent requests, client-side rendering, or delayed content may need a different readiness strategy. Wait for a meaningful selector when the content has a clear completion signal, and wait for fonts before capture when font loading affects the output:

await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('main article');
await page.evaluate(() => document.fonts.ready);
await page.screenshot({ path: 'arabic-page.png', fullPage: true });

Choose the condition based on the page. Waiting for network quiet can take too long or fail to signal completion on pages that keep connections open; waiting only for the DOM can be too early for content inserted later. A selector or application-specific readiness signal is often the clearest condition when available.

4. Select the right capture scope

Need Approach Check
One viewport Chrome Headless CLI or Puppeteer screenshot without fullPage Set the viewport dimensions explicitly.
Entire document Puppeteer fullPage: true Check long-page layout and lazy-loaded content.
One component Puppeteer element screenshot Wait for the element and verify the selector identifies the intended target.
One region Puppeteer screenshot clip option Confirm the crop’s position and size in the page coordinate space.

Chrome’s documented CLI screenshot example establishes viewport capture; use Puppeteer’s documented options when you need explicit full-page or clipped capture. [Chrome Headless documentation] [Puppeteer screenshot options]

5. Troubleshoot Arabic screenshots

Symptom Likely cause What to check
Arabic flows left to right The document’s base direction is missing or incorrect. For a page you control, check for dir="rtl" on the root HTML element. Use HTML direction markup rather than CSS to establish the base direction.
Arabic appears correctly but Latin text or punctuation looks misplaced Bidirectional text contains mixed Arabic and Latin runs. Inspect the relevant inline content and apply appropriate markup or isolation to mixed-direction text. Language alone does not set the direction of each run.
Arabic glyphs are missing or look different across machines The runtime may not have a font with the needed glyph coverage, or a different font may be used as fallback. Inspect fonts available in the same OS or container running Chrome and verify the page’s chosen font covers Arabic. There is no universal font package or identical fallback guarantee; validate the target runtime.
Some content is absent The page had not rendered it when the capture began, or it loads asynchronously. Wait for a meaningful selector or readiness signal. Treat the CLI timeout as a maximum wait, not proof that all assets are ready.
Output has unexpected dimensions or a different responsive layout The viewport was implicit or differs from the intended display size. Set --window-size in the CLI or page.setViewport() in Puppeteer before navigation/capture.
Full document is cut off A viewport capture was used, or the full-page option was omitted. Use Puppeteer with fullPage: true and check the result on very long or dynamically sized documents.
Element capture fails The selector did not match, the target is not ready, or it is outside a capturable state. Wait for the element, verify the selector, and inspect its visibility and layout before taking the screenshot.

6. Performance, reliability, and cost

For a single capture, the CLI avoids writing an automation script. For repeated jobs, Puppeteer lets you set navigation and readiness conditions and choose viewport, full-page, element, or clipped output. Capture time depends on the page and its runtime; the cited documentation gives no benchmark for Arabic-page captures.

Reliability depends on reproducing the browser environment, viewport, page readiness, and available fonts. Pin the Puppeteer version, capture in the same operating-system or container environment used for the real job, and inspect representative outputs when the page or runtime changes. Do not equate a fixed timeout or network-idle condition with proof that every visual asset is complete.

The CLI and Puppeteer are browser-software approaches; their documentation does not state a per-screenshot service price. If operating a browser yourself, account for the infrastructure and maintenance needed to run it. If you prefer a hosted request instead, ScreenshotNeo has a free tier and published paid tiers described below.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. Its API can return PNG, JPEG, WebP, or PDF. For an Arabic page, provide the target URL and request your desired output; the page’s HTML and rendering environment still determine its direction and font appearance. See the ScreenshotNeo API documentation for options.

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,
)
r.raise_for_status()
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}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Cookie and consent banners are accepted before capture and more than 60 known consent platforms, newsletter popups, and chat widgets are removed; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Learn about ScreenshotNeo or sign up free for 1,000 screenshots a month, with no card required.

FAQ

Does setting lang="ar" make a page right to left?

No. Use dir="rtl" to declare base direction and lang="ar" to identify Arabic.

Can the Chrome Headless CLI capture the full page?

The documented CLI screenshot option captures a screenshot, but the cited CLI documentation does not establish a full-page switch. Puppeteer documents fullPage: true.

Why does an Arabic page render differently on another machine?

Font availability and fallback can vary by operating system and container. Check Arabic glyph coverage in the environment that produces the screenshot.

Will a screenshot API correct a page with the wrong direction?

No. It captures the rendered page. Correct the source markup or page behavior when you control it, then capture again.