ScreenshotNeo

BlogHow-to

How to Capture Web Page Screenshots in Multiple Languages for Localization Documentation

Capture repeatable screenshots across locales with Playwright. Set browser locale, verify the page’s language, and keep each variant easy to reproduce.

By the ScreenshotNeo team4 October 202610 min read

To capture web page screenshots in multiple languages, create a fresh Playwright browser context for each locale, set locale and any needed regional settings, open the correct localized route, verify that the page actually rendered the intended language, then save the screenshot with a filename that identifies the locale and viewport. A browser locale changes browser signals and formatting; it does not guarantee that a site translates itself.

This guide shows a runnable Node.js script for Playwright, how to choose capture framing and regional settings, how to make a repeatable batch, and what to record so localization evidence can be regenerated. For the API details, see Playwright’s screenshot API, browser configuration options, and context isolation guide.

1. Decide what each localized screenshot must prove

Before launching a browser, make a small capture matrix. The locale should match the question the image is meant to answer: translation coverage, regional number and date formatting, location-specific content, or layout differences. Keep the matrix narrow enough that each variation is intentional.

Dimension Set it when Example
Locale You need browser language signals and locale-aware formatting. en-GB, de-DE, ja-JP
Localized URL or route The site selects language from its path or domain. /de/checkout or a regional host
Account preference or cookie The application stores a language choice in session state. Saved locale in a prepared storage state
Timezone Visible timestamps or dates depend on local time. Europe/Berlin
Geolocation and permission The page requests location or changes content based on it. Coordinates plus the geolocation permission
Viewport and color scheme You are documenting responsive layout or dark mode. Same 1280 × 800 viewport for every locale

Playwright documents locale, timezone, geolocation, permissions, viewport, and color scheme as context or test configuration options. Locale influences navigator.language, the Accept-Language request header, and locale-aware formatting, but applications can additionally depend on a URL, account setting, cookie, or in-page language switcher. Verify the rendered page rather than inferring success from the browser configuration.

2. Install Playwright and prepare the capture script

Use a supported Node.js version and install Playwright in a project directory. Install the browser binary as well; the script below uses Chromium.

npm init -y
npm install playwright
npx playwright install chromium

Save the following as capture-locales.mjs. Change the URL, locale list, selectors, and optional regional settings to match the site. The script creates one isolated context per locale, navigates, checks an optional language marker, captures a full page, and closes the context even if navigation or capture fails.

import { chromium } from 'playwright';
import { mkdir } from 'node:fs/promises';

const target = 'https://example.com';
const variants = [
  { locale: 'en-GB', timezoneId: 'Europe/London', path: '/en-gb' },
  { locale: 'de-DE', timezoneId: 'Europe/Berlin', path: '/de-de' },
];

const outputDir = 'screenshots';
const viewport = { width: 1440, height: 900 };
// Set this to an element whose lang attribute or text reliably identifies the page.
const languageMarker = 'html';

await mkdir(outputDir, { recursive: true });
const browser = await chromium.launch({ headless: true });

try {
  for (const variant of variants) {
    const context = await browser.newContext({
      locale: variant.locale,
      timezoneId: variant.timezoneId,
      viewport,
      colorScheme: 'light',
      // Add geolocation and permissions only if the page needs them:
      // geolocation: { latitude: 52.52, longitude: 13.405 },
      // permissions: ['geolocation'],
      // For authenticated pages, load a deliberately prepared state:
      // storageState: 'playwright/.auth/docs-user.json',
    });

    try {
      const page = await context.newPage();
      const url = new URL(variant.path, target).href;
      const response = await page.goto(url, {
        waitUntil: 'domcontentloaded',
        timeout: 45_000,
      });

      if (!response || !response.ok()) {
        throw new Error(`${variant.locale}: navigation returned ${response?.status() ?? 'no response'} for ${url}`);
      }

      // Replace with an application-specific assertion when possible.
      const htmlLang = await page.locator(languageMarker).getAttribute('lang');
      if (htmlLang && !htmlLang.toLowerCase().startsWith(variant.locale.slice(0, 2).toLowerCase())) {
        throw new Error(`${variant.locale}: expected matching HTML lang, got ${htmlLang}`);
      }

      // Prefer a stable app-ready signal to a fixed sleep.
      // await page.getByRole('heading', { name: 'Localized heading' }).waitFor();
      await page.screenshot({
        path: `${outputDir}/page-${variant.locale}-desktop.png`,
        fullPage: true,
        animations: 'disabled',
      });
      console.log(`Saved ${variant.locale}: ${url} (HTML lang=${htmlLang ?? 'not set'})`);
    } finally {
      await context.close();
    }
  }
} finally {
  await browser.close();
}

Run it with node capture-locales.mjs. The sample paths assume the site serves language-specific routes. If it uses one URL and a language menu, perform the site’s documented language-selection action after navigation and before asserting or capturing. Do not treat a matching browser locale as proof of complete translation.

3. Select the right capture framing and output

Use the same framing in all variants if the goal is comparison. Playwright supports viewport screenshots, full-page screenshots, locator screenshots, and screenshots returned as a buffer. Its screenshot options also cover output path, format, quality, clipping, scale, and background handling; check the API reference for options available in your installed Playwright release.

Capture Use it for Example
Viewport The visible state at a fixed screen size, useful for responsive comparison. page.screenshot({ path: 'view.png' })
Full page Long pages where the complete scrollable document is evidence. page.screenshot({ path: 'full.png', fullPage: true })
Locator A single translated component or region. page.locator('[data-testid="checkout"]').screenshot({ path: 'checkout.png' })
Buffer Post-processing, upload, or image comparison without first writing a file. const png = await page.screenshot()

For example, capture a specific component after waiting for it to become visible:

const checkout = page.locator('[data-testid="checkout-summary"]');
await checkout.waitFor({ state: 'visible' });
await checkout.screenshot({ path: `screenshots/checkout-${variant.locale}.png` });

Use a consistent viewport, browser engine, scale, format, page state, and capture mode across languages. Playwright screenshot scale can be CSS pixels or device pixels; device-pixel captures are larger and can aid high-density visual review, but are less convenient for direct pixel-for-pixel comparisons unless used consistently.

4. Configure language and regional behavior correctly

Locale is a browser input

Set locale when creating the context, before opening the page. It affects browser language behavior and formatting APIs. It does not rewrite hard-coded strings, guarantee that the server chooses the expected language, or set a user’s saved account preference. For server-negotiated language, inspect the response and rendered text as well as the page language metadata.

Timezone and geolocation are separate

Set timezoneId when visible time or date output must match a region. For location-aware pages, configure coordinates and grant the page geolocation permission. The context option example is:

const context = await browser.newContext({
  locale: 'de-DE',
  timezoneId: 'Europe/Berlin',
  geolocation: { latitude: 52.52, longitude: 13.405, accuracy: 10 },
  permissions: ['geolocation'],
  viewport: { width: 1440, height: 900 },
});

Only provide geolocation and permission when they are relevant. Permission support can vary by browser and version; confirm the behavior in the engine used for the documentation capture.

Authentication and stored language preference

If the page requires login, initialize the context with an approved Playwright storage state or perform the login flow. Storage state can contain cookies and local storage, so keep it out of public repositories and avoid capturing personal or confidential account data. A locale saved in application state may override the browser setting; set or clear that state deliberately for every variant.

5. Make the captures repeatable

  1. Use clean contexts. Browser contexts have independent cookies and storage. Create a new one for every locale so a choice made in one run does not silently affect the next.
  2. Use stable readiness checks. Wait for a page-specific heading, component, or application-ready marker. Navigation reaching domcontentloaded only means the document was parsed; it does not prove that client-side translation or lazy content is ready.
  3. Handle animations and dynamic content. Disable animations for visual evidence when appropriate. If banners, clocks, carousels, or personalized content matter, set them to a documented deterministic state rather than hiding a meaningful state accidentally.
  4. Keep geometry constant. Reuse viewport, browser engine, screenshot scale, and capture mode. Localized strings often alter line wraps and page height; that difference is evidence, so do not resize each locale to make it look alike.
  5. Record provenance. Save a short manifest next to the images with URL, locale, viewport, browser and Playwright versions, date, timezone, route, and relevant consent or account state.

Useful names are checkout-de-DE-desktop.png and checkout-en-GB-desktop.png. A manifest could use one JSON record per file:

{
  "file": "checkout-de-DE-desktop.png",
  "url": "https://example.com/de-de/checkout",
  "locale": "de-DE",
  "timezone": "Europe/Berlin",
  "viewport": { "width": 1440, "height": 900 },
  "capture": "fullPage",
  "browser": "Chromium",
  "capturedAt": "2026-10-04"
}

Treat that date as an example and record the actual capture date in your workflow.

6. Common problems and fixes

Symptom Likely cause Fix
Page stays in the default language The app uses a language route, cookie, profile setting, or switcher rather than browser negotiation. Use the correct localized URL or explicitly set the app’s language preference, then assert the resulting language.
html lang is missing or unexpected The site omits or mislabels language metadata, or the locale is not selected. Check visible text and application state; report the metadata issue rather than silently claiming the intended locale rendered.
One locale inherits another locale’s content The same context or persistent profile was reused and retained cookies or storage. Create a new context per variant; seed only intentional storage state.
Navigation or selector timeout Network slowness, a wrong route, a consent wall, or a selector that does not match the locale-specific page. Check the final URL and response status, use an accurate readiness selector, and set a bounded timeout appropriate to the environment.
Screenshot is blank or only partly rendered The page is still loading client-side content, a lazy region has not rendered, or a failed request left a shell. Wait for an app-ready marker and inspect the page before saving. Scroll or interact if the target content loads lazily.
Date or number formatting does not match the region Locale and timezone are distinct, or the application formats values itself. Set the appropriate locale and timezone separately; verify the actual displayed value.
Geolocation prompt or location-dependent content is absent Permission was not granted, coordinates are missing, or the site does not use browser location. Configure coordinates and grant geolocation permission; check whether the site instead relies on account or IP location.
Full-page image is unwieldy The document is very tall or has sticky elements repeated during full-page capture. Capture the viewport or relevant locator, or split evidence into named sections.
Images differ between runs despite same locale Changing content, personalization, animations, fonts, or browser versions affect rendering. Fix the page state, wait for fonts and target content, disable nonessential animation, and record browser and configuration versions.

7. Performance, reliability, and storage costs

The main time cost is launching the browser, loading each page, waiting for the right state, and encoding/writing the image. Reuse one browser process for a batch, as in the script, while keeping separate contexts for variant isolation. Begin with sequential captures for dependable behavior; if parallelizing, cap concurrency to avoid excessive memory use, rate limiting, and load on the target site.

Full-page images consume more time, memory, and disk than viewport or element captures, particularly on long pages. Prefer the smallest framing that proves the documentation point. PNG is lossless and useful when text or visual comparison matters; JPEG and WebP can reduce output size where the downstream documentation system supports them. Keep output format consistent across a comparison set. The actual file size and runtime depend on the page and environment, so measure your own workflow rather than relying on a generic benchmark.

For reliability, use explicit timeouts, check navigation responses, verify the selected language, close contexts in a finally block, and log failures by locale. Retry transient navigation failures selectively; repeated retries can conceal a persistent site issue. Store screenshots and manifests together, and regenerate them when the page, browser, locale setup, or capture code changes.

8. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It can capture a page with one GET request; the ScreenshotNeo API documentation describes its request options. For a localized page, pass the locale-specific URL you want documented:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/de-de/checkout -o checkout-de-DE.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com/de-de/checkout"},
    timeout=90,
)
r.raise_for_status()
open("checkout-de-DE.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/de-de/checkout'
});
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(({ writeFile }) => writeFile('checkout-de-DE.webp', Buffer.from(await res.arrayBuffer())));

ScreenshotNeo removes cookie and consent banners, 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 response headers identify the page verdict and billing result. 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. Keep checking that the requested URL renders the language you need: a screenshot service does not establish that a site translated itself.

Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.

9. FAQ

How do I take screenshots of a website in different languages?

Create a clean browser context for each locale, navigate to the appropriate localized page, verify the rendered language, and save each capture under a locale-specific filename.

How can I capture localized screenshots for documentation?

Use a repeatable capture matrix and preserve the locale, route, viewport, browser, capture date, and any relevant consent or account state with each image.

How do I change the browser language for screenshots?

Set Playwright’s locale option when creating the browser context. If the application uses its own language preference, set that too and verify the result.

Should I use full-page captures for every language?

No. Use full-page captures for whole-document evidence, viewport captures for visible responsive layout, and locator captures for a particular localized component.

References