How to Capture Website Screenshots with Playwright Chromium
Launch Chromium with Playwright, capture a website as an image, and choose the right settings for full-page, element, and reliable screenshots.
To capture a website screenshot with Playwright Chromium, launch Chromium, open a page, navigate to the URL, and call page.screenshot(). Set path to save an image file. Use fullPage: true in JavaScript or full_page=True in Python to capture the full scrollable page.
1. Install Playwright and Chromium
Install Playwright for your language and install its browser binary. Run these commands from your project directory:
# JavaScript / Node.js
npm install playwright
npx playwright install chromium
# Python
python -m pip install playwright
python -m playwright install chromium
Playwright’s browser install command downloads a compatible Chromium build. If your environment already manages browser binaries, use the Chromium installation method appropriate to that environment.
2. Capture a website screenshot in JavaScript
This CommonJS script writes the current viewport as a PNG. Save it as screenshot.js and run node screenshot.js:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
} finally {
await browser.close();
}
})();
Wait for the screenshot promise to finish before closing the browser. The try/finally ensures Chromium is closed even if navigation or capture fails.
3. Capture a website screenshot in Python
This synchronous Python script has the same flow and saves a PNG:
from playwright.sync_api import sync_playwright
with sync_playwright() as playwright:
browser = playwright.chromium.launch()
try:
page = browser.new_page()
page.goto("https://example.com")
page.screenshot(path="screenshot.png")
finally:
browser.close()
4. Choose the capture area and output
Viewport or full page
By default, a page screenshot captures the visible viewport. To include the entire scrollable document, enable full-page capture:
// JavaScript
await page.screenshot({ path: 'full-page.png', fullPage: true });
# Python
page.screenshot(path="full-page.png", full_page=True)
A full-page screenshot can be much taller and larger than a viewport screenshot, especially on long pages. It can also take longer to render and write.
Whole page or one element
Use page.screenshot() for the page. To capture a specific matching element, take a locator screenshot instead:
// JavaScript
await page.locator('.header').screenshot({ path: 'header.png' });
# Python
page.locator(".header").screenshot(path="header.png")
If the locator does not match an element, or matches an element that never becomes visible, the capture cannot complete. Wait for the intended locator and make sure the selector is unique when the target matters.
Save a file or keep screenshot bytes
Supplying path writes the image to disk. If you omit it, the screenshot API returns image bytes. Bytes are useful when you want to pass the result to an image-processing or comparison step without first writing a file:
// JavaScript
const pngBytes = await page.screenshot();
# Python
png_bytes = page.screenshot()
Format and quality
PNG is the default. The output format can be selected as PNG, JPEG, or WebP; a filename extension can also be used to infer the format. JPEG and WebP support a quality value from 0 to 100. JPEG’s documented default quality is 80. WebP quality 100 is lossless; lower values are lossy. Quality does not apply to PNG.
// JavaScript
await page.screenshot({ path: 'page.jpg', type: 'jpeg', quality: 80 });
await page.screenshot({ path: 'page.webp', type: 'webp', quality: 90 });
# Python
page.screenshot(path="page.jpg", type="jpeg", quality=80)
page.screenshot(path="page.webp", type="webp", quality=90)
Pixel scale
The default scale is device, which respects the device pixel ratio and can produce larger images on high-DPI screens. Choose css for one output pixel per CSS pixel, which can reduce output dimensions:
// JavaScript
await page.screenshot({ path: 'css-pixels.png', scale: 'css' });
# Python
page.screenshot(path="css-pixels.png", scale="css")
5. Make capture timing reliable
A screenshot shows the page’s state when capture occurs. A navigation completing does not guarantee that every delayed image, animation, or application widget has reached the state you want. Pick a readiness signal that fits the site: a relevant navigation load state, a locator becoming visible, or an application-specific condition. There is no single fixed delay that is correct for every website.
// JavaScript: wait for a target element
await page.goto('https://example.com');
await page.locator('main').waitFor({ state: 'visible' });
await page.screenshot({ path: 'ready.png' });
# Python: wait for a target element
page.goto("https://example.com")
page.locator("main").wait_for(state="visible")
page.screenshot(path="ready.png")
Use a bounded timeout for production automation so a missing element does not wait forever. When a page changes dynamically, wait for the specific content that matters to the screenshot rather than adding an arbitrary sleep.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser executable is missing | The Playwright package is installed, but its Chromium binary is not. | Run npx playwright install chromium or python -m playwright install chromium for the language in use. |
| Navigation times out | The site is slow, unreachable, or keeps background requests open; the chosen readiness condition may be too strict. | Check the URL and network access. Choose a suitable navigation or page-specific readiness signal, and set a deliberate timeout. |
| Screenshot is blank or incomplete | The page was captured before its meaningful content appeared, or the target content did not load. | Wait for the page element or content that should appear. Check navigation errors and the page state before capture. |
| Element screenshot fails | The selector matched no visible element, or matched the wrong element. | Check the selector, wait for the intended element to become visible, and make the selector specific. |
| Output file is missing | The script did not reach the screenshot call, the path is unexpected, or the browser closed before capture completed. | Await the screenshot call, use an explicit path, and inspect navigation or runtime errors. Close the browser after capture. |
| Image is unexpectedly large | Full-page capture includes a long document, or device scale uses a high pixel ratio. | Capture only the viewport or a locator, or set scale: 'css' / scale="css". |
| Output looks soft or file size is high | The chosen format and pixel dimensions do not match the intended use. | Choose PNG for lossless output, or JPEG/WebP with a suitable quality. Consider CSS pixel scale when device pixels are unnecessary. |
7. Performance, reliability, and cost
- Performance: Chromium startup and page rendering are part of the capture time. Reuse a browser for multiple pages in a controlled batch when appropriate, and close it reliably when work ends. Full-page and high-DPI captures need more rendering, memory, and output space than a small viewport capture.
- Reliability: Use explicit readiness conditions, bounded timeouts, and cleanup in
finallyblocks. Sites can block automated browsers or show consent prompts, so output depends on the site’s response to the browser. - Cost: Playwright is an open-source browser automation library, but running Chromium still uses your machine or compute environment. Factor in runtime, memory, storage, and any hosted infrastructure you operate; this workflow does not bill per screenshot through Playwright itself.
8. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. It removes cookie and consent banners from more than 60 known platforms, along with newsletter popups and chat widgets, before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. AI agents can capture through its MCP server tools: take_screenshot, get_page_info, and capture_pdf.
For a PNG response saved as a file, see the ScreenshotNeo API documentation for options and authentication details:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.png
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.png", "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 require('node:fs/promises').writeFile('shot.png', Buffer.from(await res.arrayBuffer()));
The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is available on every plan. Sign up for free and get 1,000 screenshots a month with no card.
9. FAQ
Does Playwright take a screenshot of a page that requires login?
It can capture whatever the browser page can access. Your script must establish the required authenticated state before taking the screenshot.
Can I take screenshots in CI?
Yes. Install the Chromium build in the CI environment, ensure it can reach the target site, and save the output to a path your job can collect.
Does full-page capture include content that only loads while scrolling?
It captures the full scrollable document, but lazy-loaded content may need to be triggered or awaited before the screenshot. Check the page-specific content readiness before capture.


