How to Screenshot a Web Page with a Right-to-Left Layout in Playwright
Set a page to right-to-left before capturing it in Playwright. Learn how to capture the viewport, full page, or a single element and troubleshoot RTL screenshots.
Set the document direction to right-to-left before taking the screenshot, then use Playwright’s page.screenshot(). For a page that is meant to be RTL, set dir="rtl" on the root <html> element in the application. Add the matching language attribute when known: direction and language are separate settings.
This guide covers viewport, full-page, element, and visual-regression captures; how to set RTL for a test; and common issues that can make an image look wrong. The examples use JavaScript and Playwright.
1. Set direction on the document
For a page predominantly written in Arabic, Hebrew, or another right-to-left script, use semantic document markup:
<html dir="rtl" lang="ar">
Replace ar with the correct language tag for the page. The dir attribute sets text direction; lang identifies the language and does not set direction. Setting direction on the root gives the document a base direction for bidirectional text. It does not guarantee every component’s visual layout is correct: CSS, embedded content, and application-specific layout rules still matter. See [MDN’s documentation for the dir attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir).
When you own the application, make RTL part of its normal rendering state and capture that state. This is more representative than changing direction only after navigation. For a test of an RTL mode that the app already supports, use the app’s actual locale, route, or setting.
2. Capture the page with Playwright
Install Playwright and its browser if they are not already part of the project:
npm install playwright
npx playwright install chromium
Save the following as screenshot-rtl.mjs. It navigates to a page, waits for the document to load, and writes a viewport screenshot. Change the URL to the page you want to capture.
import { chromium } from 'playwright';
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1440, height: 1000 },
deviceScaleFactor: 1,
});
await page.goto('https://example.com', { waitUntil: 'load' });
await page.screenshot({ path: 'rtl-page.png' });
} finally {
await browser.close();
}
Run it with node screenshot-rtl.mjs. The default page screenshot is the current viewport. The page must actually be in RTL mode before capture; Playwright does not infer direction from the script or the language.
3. Set RTL in a test when you cannot change the app
For a test-only rendering check, set the document root’s direction after navigation and before taking the screenshot:
await page.goto('https://example.com', { waitUntil: 'load' });
await page.evaluate(() => {
document.documentElement.dir = 'rtl';
});
await page.screenshot({ path: 'rtl-page.png' });
This changes the root element’s direction property, which reflects the dir attribute. If the test also needs a language value, set it explicitly, for example document.documentElement.lang = 'ar'. Choose the language that matches the content.
A late direction change may not reproduce the application’s real RTL experience. Styles can override direction, and layouts may depend on app state, physical left/right CSS properties, or components that only initialize correctly in the RTL route. Treat this technique as a controlled visual check; use the app’s real RTL mode for a representative capture.
4. Choose viewport, full-page, or element capture
| Capture | Playwright call | Use it for |
|---|---|---|
| Viewport | page.screenshot({ path: 'rtl.png' }) |
The currently visible screen at the configured viewport. |
| Full page | page.screenshot({ path: 'rtl-full.png', fullPage: true }) |
The full scrollable document in one tall image. |
| One element | page.getByRole('main').screenshot({ path: 'rtl-main.png' }) |
A focused region, such as the main content, after selecting an appropriate locator. |
Example full-page and element captures:
await page.screenshot({ path: 'rtl-full.png', fullPage: true });
const main = page.getByRole('main');
await main.screenshot({ path: 'rtl-main.png' });
Full-page capture is a screenshot of the full scrollable page, rather than just the current viewport. A locator screenshot targets the selected element. Use the form that matches the artifact you need; the APIs and options are documented in [Playwright’s screenshot guide](https://playwright.dev/docs/screenshots) and [Page API](https://playwright.dev/docs/api/class-page#page-screenshot).
For long pages with lazy-loaded images or content that appears only while scrolling, make sure that content has loaded before capturing. A full-page image does not by itself prove that every lazy resource or application state has finished rendering.
5. Capture an RTL visual-regression baseline
With Playwright Test, use a screenshot assertion to capture and compare a page in a test:
import { test, expect } from '@playwright/test';
test('RTL page screenshot', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('rtl-page.png');
});
Make sure the test navigates to the application’s real RTL state, or apply the test-only direction change before the assertion if that is what you intend to verify. Screenshot assertions wait for consecutive captures to stabilize before comparing. Differences can still come from operating system, browser version, fonts, hardware, and rendering setup. Generate and compare baselines in a consistent environment. See [Playwright’s visual comparisons guidance](https://playwright.dev/docs/test-snapshots).
Dynamic timestamps, rotating content, animations, or other changing regions can make comparisons noisy. Stabilize the page state or use Playwright’s screenshot assertion options to handle known dynamic regions, consulting the documentation for the installed version.
6. Troubleshooting RTL screenshots
| Symptom | Likely cause | What to do |
|---|---|---|
| The screenshot still looks left-to-right. | The captured page did not have RTL direction, or application CSS overrides it. | Inspect document.documentElement.dir before capture. Prefer the application’s RTL mode and check its CSS direction rules. |
| Text direction changed but the layout did not mirror. | dir establishes directionality; it does not automatically rewrite every layout choice in CSS or every component. |
Check the app’s RTL styles and component behavior. Use logical CSS properties where appropriate in the application, and test the actual RTL route. |
| Arabic or Hebrew glyphs look missing or different. | The capture environment may not have the expected fonts available or loaded. | Ensure the page’s fonts finish loading and use a consistent browser and host environment for baselines. |
| The screenshot is cut off at the viewport. | The default page screenshot captures the viewport. | Use fullPage: true for the full scrollable document, or a locator screenshot for a particular element. |
| An element screenshot fails or captures the wrong region. | The locator may not identify the intended element, or the element may not be ready. | Choose a locator that uniquely identifies the target and wait for it to be visible before calling its screenshot method. |
| Visual tests fail across machines. | Browser, OS, fonts, hardware, or rendering differences can change pixels. | Capture and compare with a consistent environment and neutralize known dynamic page regions. |
7. Performance, reliability, and cost
A viewport screenshot captures less content than a full-page screenshot, while a full-page capture can involve a much taller image and more page content. Use a viewport capture when the visible screen is the evidence you need; use full-page capture when below-the-fold content matters. Element screenshots can keep the output focused. Set the viewport explicitly when consistent dimensions matter.
For reliable captures, establish the intended page state before capturing: navigate to the correct RTL route, wait for the relevant content and fonts, and avoid comparing images produced with different browser or host environments. A successful screenshot call only captures the rendered state it sees; it does not establish that the site’s RTL implementation is correct.
Playwright is a browser automation library; this workflow has no per-screenshot ScreenshotNeo charge. Your own costs depend on where and how you run browsers, including compute and maintenance. If you need a managed screenshot API instead, ScreenshotNeo’s feature set and request options are listed in its API documentation.
8. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. A single GET request can return an image or PDF. For an ordinary screenshot request, use:
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. This one-call example captures a page as served; it does not set dir="rtl" on a site that is not already in RTL mode.
- Cookie banners are accepted and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card required.
9. FAQ
Does setting lang="ar" make a page RTL?
No. Set the direction with dir="rtl"; use lang to identify the page’s language.
Should I use CSS or the dir attribute?
Use the semantic dir attribute for document direction. CSS can style or override directionality, but injecting a style is not the semantic way to set the document’s base direction.
Can Playwright capture just the main content?
Yes. Select the content with a locator and call its screenshot() method.
Will changing the root direction fix every RTL layout issue?
No. It sets the document’s base direction, but application styles and components determine many visual layout details. Capture the app’s real RTL mode when possible.


