How to Capture a Website Screenshot with a Specific Browser Locale for Documentation
Set a browser locale before navigation to capture localized website screenshots with Playwright. Learn how locale, timezone, repeatability, and site behavior affect documentation.
To capture a website in a specific browser locale with Playwright, set locale on the browser context before navigating, then capture the page with page.screenshot(). Locale affects navigator.language, the Accept-Language request header, and number and date formatting. Set timezoneId separately when the displayed time or date depends on timezone. Playwright’s locale and timezone documentation describes these browser emulation settings.
1. Install Playwright and choose the locale
Use a locale tag such as en-GB or de-DE. If the screenshot also needs a regional time display, choose a timezone such as Europe/Berlin. Locale and timezone are separate settings: timezone emulation in the browser does not change the test runner’s timezone.
npm init -y
npm install playwright
npx playwright install chromium
This example uses Chromium. If your documentation requires another browser engine, install and use the corresponding Playwright browser. Keep the engine consistent across captures.
2. Capture a full page with Playwright
Save this as capture-locale.mjs. It creates a context with the requested locale, timezone, and viewport before opening the target URL.
import { chromium } from 'playwright';
const url = process.argv[2] ?? 'https://example.com';
const output = process.argv[3] ?? 'screenshot.png';
const browser = await chromium.launch();
try {
const context = await browser.newContext({
locale: 'de-DE',
timezoneId: 'Europe/Berlin',
viewport: { width: 1280, height: 720 },
});
try {
const page = await context.newPage();
await page.goto(url, { waitUntil: 'load', timeout: 30_000 });
await page.screenshot({ path: output, fullPage: true });
} finally {
await context.close();
}
} finally {
await browser.close();
}
Run it with node capture-locale.mjs https://example.com docs-de.png. The script uses a finite navigation timeout and closes the context and browser even if navigation or capture fails.
waitUntil: 'load' waits for the page load event, but does not guarantee that every application has finished rendering its content. For a page that updates after load, wait for a meaningful selector or application-specific state before taking the screenshot:
await page.goto(url, { waitUntil: 'load', timeout: 30_000 });
await page.locator('main h1').waitFor({ state: 'visible', timeout: 15_000 });
await page.screenshot({ path: output, fullPage: true });
Choose a selector that indicates the content you actually need. A fixed delay can help with a known animation or delayed update, but it is less reliable than waiting for the expected page state.
3. Configure locale in a Playwright test
For a test suite, configure the locale in Playwright’s project settings so screenshots use the same context settings. Add or adapt a project in playwright.config.js:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
locale: 'de-DE',
timezoneId: 'Europe/Berlin',
viewport: { width: 1280, height: 720 },
screenshot: 'only-on-failure',
},
});
Then capture from a test after navigating and waiting for the required content:
import { test, expect } from '@playwright/test';
test('capture the German documentation page', async ({ page }) => {
await page.goto('https://example.com', { waitUntil: 'load' });
await expect(page.locator('main')).toBeVisible();
await page.screenshot({ path: 'docs-de.png', fullPage: true });
});
Project-level settings keep runs consistent. Use a per-test configuration when only a particular test needs a different locale; the exact override pattern can depend on the installed Playwright Test version and project setup. The browser context API is also available directly when you need explicit control over context creation. See the BrowserContext locale option and the Page screenshot API.
4. Decide what the screenshot should include
- Viewport screenshot: omit
fullPageor set it tofalseto show the visible viewport. - Full-page screenshot: set
fullPage: trueto capture the page’s full scrollable content. Long pages can create large images; consider whether a viewport or focused element gives readers better context. - Element screenshot: capture a locator when the evidence is a specific section. Keep enough surrounding context for the image to make sense in documentation.
- Output format: Playwright’s screenshot API supports output format options. Use PNG for crisp interface details and JPEG when a smaller photographic image is more useful; check the current API for format-specific options.
- Dynamic content: use screenshot style injection to hide or adjust known dynamic elements when you need repeatable output. Avoid hiding content that is part of the documentation being demonstrated.
See the official screenshot options for the options supported by your installed version.
5. Verify the website’s localized result
Locale configures browser signals; the website decides what to do with them. A site may choose language or regional content using its own URL, account, cookies, location, or application logic. A browser locale alone does not guarantee a translation or regional storefront.
Before publishing a documentation image, inspect the result and confirm the visible content is the intended one. If it is not, check whether the site provides a locale-specific URL or requires a site preference to be selected. Those behaviors vary by site.
You can inspect the browser signals in the page:
console.log(await page.evaluate(() => ({
language: navigator.language,
languages: navigator.languages,
date: new Intl.DateTimeFormat().format(new Date()),
})));
This helps confirm browser-side language and formatting, but it does not confirm which request headers a server received or how the site selected its content.
6. Keep documentation captures repeatable
For comparable screenshots across runs, hold these inputs steady:
- Locale and timezone.
- Viewport dimensions and browser engine.
- Target URL, account state, cookies, and any locale selection made on the site.
- Navigation and readiness condition.
- Screenshot scope, such as viewport, full page, or element.
Playwright supports screenshot styles that can suppress known dynamic elements or adjust their appearance. Prefer waiting for a meaningful state and applying a narrow style adjustment over relying on a broad delay. Network activity can continue for reasons unrelated to the visible content, so no single wait condition guarantees a stable screenshot on every site.
7. cURL, Python, and Node.js options
cURL cannot set a browser locale or render a website. The locale-specific workflow requires a browser that can emulate browser context settings, such as Playwright. cURL can send an Accept-Language header to inspect a server response, but that does not reproduce browser-side locale formatting or create a rendered screenshot.
curl -L -H 'Accept-Language: de-DE' https://example.com
For Python, Playwright provides the same browser context settings. Install it and its browser, then run this script:
python -m pip install playwright
python -m playwright install chromium
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
try:
context = await browser.new_context(
locale='de-DE',
timezone_id='Europe/Berlin',
viewport={'width': 1280, 'height': 720},
)
try:
page = await context.new_page()
await page.goto('https://example.com', wait_until='load', timeout=30_000)
await page.locator('main').wait_for(state='visible', timeout=15_000)
await page.screenshot(path='screenshot.png', full_page=True)
finally:
await context.close()
finally:
await browser.close()
asyncio.run(main())
For a Node.js one-off capture without the earlier command-line wrapper, the essential sequence is:
import { chromium } from 'playwright';
const browser = await chromium.launch();
try {
const context = await browser.newContext({
locale: 'en-GB',
timezoneId: 'Europe/London',
viewport: { width: 1280, height: 720 },
});
try {
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'load', timeout: 30_000 });
await page.screenshot({ path: 'screenshot.png' });
} finally {
await context.close();
}
} finally {
await browser.close();
}
8. Timezone and test-runner behavior
Set timezoneId on the browser context to emulate the page’s browser timezone. Playwright documents that this does not change the timezone used by the test runner itself. If test code formats dates outside the browser and depends on a particular timezone, configure the runner environment separately, for example with the TZ environment variable where supported:
TZ=Europe/Berlin npx playwright test
Use this only when the test process itself needs that timezone. The browser’s timezoneId and the runner’s environment setting address different execution environments.
9. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The screenshot stays in the default language | The site does not use browser locale alone, or a saved preference, cookie, URL, or account setting takes precedence. | Verify the browser signals, inspect the site’s own locale controls, and use a locale-specific URL or preference if the site provides one. |
| Dates or times are still unexpected | Locale and timezone are separate, or the site formats values itself. | Set timezoneId on the context as well as locale; check whether page code or server content controls the displayed value. |
| Navigation times out | The page did not reach the chosen lifecycle event before the timeout, possibly because of slow or ongoing activity. | Check the URL and browser access, keep a finite timeout, and wait for the specific content needed instead of requiring an unnecessarily late lifecycle event. |
| The page is blank or incomplete in the image | Capture happened before client-side rendering or the relevant content appeared. | Wait for a visible, meaningful selector or application state before calling screenshot(). |
| Screenshots vary between runs | Viewport, browser engine, cookies, page state, animation, or dynamic content changed. | Keep capture inputs constant, wait for the same state, and use a narrowly scoped screenshot style adjustment for known dynamic elements. |
| Browser launch fails on a new machine or CI runner | The browser binary or its system dependencies may not be installed in that environment. | Run Playwright’s browser installation command for the browser you use and follow the official setup instructions for the runner. |
10. Performance, reliability, and cost
Browser automation requires starting a browser and loading the page, so capture time depends on browser startup, site response, page rendering, and the amount of content captured. Reuse a browser process for multiple captures where your application architecture allows it, while creating a separately configured context for each locale or isolated session. Full-page images can be larger and slower to produce than viewport captures.
For reliable documentation, use explicit finite timeouts, wait for the content that matters, and preserve the capture inputs alongside the output when reproducibility is important. A successful screenshot only proves what appeared in that browser session; it does not prove that every visitor or server region sees the same localized result.
Playwright is software rather than a per-screenshot hosted service; your costs depend on the machine and infrastructure used to run it. If you prefer a hosted capture request, ScreenshotNeo is a website screenshot API and MCP server for developers. Its API accepts a URL and returns an image or PDF. See the ScreenshotNeo API documentation for the request options.
Or skip the browser setup
A hosted screenshot API can simplify ordinary URL captures, but the API facts here do not establish that it emulates a requested browser locale. Use Playwright when the locale setting itself is essential to the capture. For a standard URL capture, ScreenshotNeo’s one-call request is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture, and each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and billing status. Its MCP server includes take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card required.
FAQ
Does setting locale translate a website automatically?
No. It sets browser locale signals and formatting behavior. Each site chooses whether and how to respond to them.
Should I set the locale before or after navigation?
Before navigation. Create the configured context first so the browser uses those settings for the page request and rendering.
Can I use a language-only tag such as de?
Playwright accepts locale identifiers; use a specific regional tag such as de-DE when regional conventions matter, and verify the resulting page.
Does browser timezone emulation change Node.js or Python date formatting?
It emulates the browser context timezone. Test-runner code runs in a separate environment and may need its own timezone configuration.
Can I use Puppeteer instead?
Puppeteer documents page and element screenshots. The sources cited here do not establish a current Puppeteer locale setup procedure, so check the API for your installed version before relying on a locale-specific workflow. See Puppeteer’s screenshot guide.


