Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Playwright’s Python API to launch a browser, open a page, and call page.screenshot(). The synchronous version is the shortest path to a working image; set full_page=True for the complete scrollable document or call a locator’s screenshot() method for one element. Install both the Python package and Playwright’s browser binaries before running any script.

Install Playwright and its browsers

Playwright supports Python 3.8 or newer according to its installation documentation; check the current requirements for your operating system before deployment. In a virtual environment, run:

python -m pip install playwright
playwright install

On Linux, a targeted install can also add Chromium and its operating-system dependencies:

playwright install --with-deps chromium

The first command installs the Python bindings. The second downloads the browser engines. If you skip the browser install, a script can fail before it creates a page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The minimal synchronous screenshot script

This complete example launches Chromium headlessly, navigates to a URL, writes a PNG, and closes the browser even though the page is created inside a managed Playwright context.

from playwright.sync_api import sync_playwright

URL = "https://example.com"

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto(URL)
    page.screenshot(path="screenshot.png")
    browser.close()

Save it as screenshot.py and run python screenshot.py. The default is headless mode, so no browser window appears. The resulting screenshot.png is the visible viewport, not necessarily the entire page.

Capture the full page or one element

Full scrollable document

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1440, "height": 900})
    page.goto("https://example.com", wait_until="networkidle")
    page.screenshot(path="full-page.png", full_page=True)
    browser.close()

full_page=True captures the page as if it were displayed on a screen tall enough to contain the complete scrollable document. The viewport width still affects responsive layout, so choose it deliberately.

One element

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://example.com")
    page.locator(".header").screenshot(path="header.png")
    browser.close()

A locator screenshot waits for the matching element and captures its bounding box. Prefer a stable selector such as a test ID or semantic role when classes are generated dynamically.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the async API in asyncio applications

If your service already has an asyncio event loop (for example, an async web handler or worker), use async_playwright instead of blocking the loop with the synchronous API.

import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto("https://example.com")
        await page.screenshot(path="screenshot.png")
        await browser.close()

asyncio.run(main())

Do not call asyncio.run() from code that is already running an event loop; await main() from that application instead. Both APIs expose the same browser engines and screenshot controls.

Make captures deterministic

A screenshot is only useful when the page has reached the state you intend to record. Navigation waits for the document’s load event by default, but modern pages may render data, fonts, or images later.

  • Wait for a state: use page.goto(url, wait_until="networkidle") when a quiet network is a reasonable signal, or wait for a specific element with page.locator(".report").wait_for().
  • Wait a known delay: page.wait_for_timeout(1000) can accommodate a short animation, but a selector-based wait is usually less brittle.
  • Control motion: disable CSS transitions or inject a style sheet when animation changes the pixels between runs. Playwright’s screenshot API can also control animation handling in supported versions.
  • Mask changing or sensitive areas: pass locators through the screenshot API’s mask option so timestamps, avatars, or personal data do not create unstable diffs.
  • Set the environment: choose a fixed viewport, device scale factor, locale, timezone, color scheme, and user agent when visual comparisons must be reproducible.

Never treat a fixed sleep as proof that a request has completed. Wait for the application’s actual ready signal where possible.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Screenshot options you will use most

Option What it controls Typical use
path Writes the image to a file. Artifacts in a test or build.
full_page Captures the complete scrollable document. Long-page documentation or audits.
clip Captures a rectangular region with x, y, width, and height. A fixed area that is not a single element.
type Selects png, jpeg, or (in current supported releases) webp. PNG for lossless diffs; JPEG/WebP for smaller files.
quality Controls lossy image quality. Use with JPEG or WebP; it is not applicable to PNG.
omit_background Requests a transparent background where supported. Compositing an isolated page or component.
scale Controls whether output follows CSS or device pixels. Keep dimensions consistent across retina and standard displays.
mask Covers selected locators in the output. Hide volatile or private regions.

Screenshot methods return image bytes when path is omitted. That is useful for an upload, an in-memory transformation, or a pixel-diff pipeline:

image_bytes = page.screenshot(type="png")
with open("screenshot.png", "wb") as f:
    f.write(image_bytes)

Check the API supported by the Playwright version installed in your environment before relying on a newer option. WebP output was added to page.screenshot() and locator.screenshot() in Playwright 1.62.

Choose a browser and context deliberately

Playwright can drive Chromium, Firefox, and WebKit. Select the engine that matches the compatibility question: Chromium for a Chromium-based production flow, Firefox for Gecko behavior, or WebKit for Safari-like rendering. You can launch headed mode while diagnosing layout or authentication problems:

browser = p.chromium.launch(headless=False, slow_mo=200)

Close the browser in a finally block when your script has multiple failure paths. For repeated captures, reuse one browser process and create separate contexts or pages rather than launching a new process for every URL.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Authentication, headers, and dynamic pages

Create a context with the conditions your site expects:

context = browser.new_context(
    viewport={"width": 1440, "height": 900},
    color_scheme="dark",
    locale="en-US",
    timezone_id="America/New_York",
    extra_http_headers={"Authorization": "Bearer TOKEN"},
)
page = context.new_page()

For a logged-in flow, establish the session with the UI or load a previously saved storage state. Keep credentials out of source control. If content is loaded only after scrolling, scroll or wait for the relevant locator before taking a full-page image; otherwise lazy images may remain absent.

Troubleshooting common failures

“Executable doesn’t exist” or browser launch failure

Run playwright install (or the targeted --with-deps chromium command on Linux) in the same environment that runs Python. Containers also need the system libraries required by the selected engine.

The image is blank or incomplete

Confirm the URL is reachable from the execution host, wait for a page-specific selector, and inspect the page in headed mode. A network-idle wait can hang on applications with persistent connections; replace it with a deterministic selector wait.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The locator screenshot times out

The selector may match nothing, be hidden, or be inside a frame. Verify it with page.locator("selector").count(), wait for visibility, and use frame_locator() for an iframe.

Fonts or images differ between runs

Use a fixed browser engine, viewport, scale, locale, and timezone. Wait for the intended fonts and images, disable animation, and mask timestamps or other changing content.

Full-page output has surprising dimensions

Responsive breakpoints depend on viewport width, while device scale affects pixel dimensions. Set both explicitly and remember that very long documents can consume substantial memory.

Navigation errors, bot checks, or consent overlays

Inspect the response and page content instead of assuming the screenshot represents the target. Supply required cookies, headers, or authentication only when you are authorized to access the page. A consent dialog or chat widget can obscure the result; close it through an explicit, tested locator before capture.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and cost considerations

  • Launching a browser is expensive compared with taking another page screenshot; keep a browser alive for batches and isolate jobs with contexts.
  • Full-page images and high device scales increase memory and file size. Use a viewport clip or a lower scale when a complete document is unnecessary.
  • Set realistic navigation and assertion timeouts, record the failing URL, and retain a diagnostic screenshot or trace for retries.
  • Retries should be bounded. Repeating a page with a permanent 404, authentication failure, or bot challenge only increases latency.
  • Run untrusted URLs in an appropriately isolated environment. Restrict credentials, network access, and filesystem permissions according to your threat model.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. It removes cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—let Claude, Cursor, or another MCP client request captures without custom browser code.

One GET request is enough:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for all options, including full-page and element captures, device presets, custom CSS and JavaScript, waits, headers, cookies, geolocation, caching, signed links, asynchronous webhooks, bulk requests, and PDF output.

Python

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)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create a free ScreenshotNeo account.

FAQ

Does Playwright save screenshots as bytes or only files?

Both. Supplying path writes a file; omitting it returns bytes that your Python code can upload or process.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I capture a PDF with page.screenshot()?

No. Screenshots produce raster images. Use Playwright’s PDF capabilities for PDF output in supported Chromium workflows, or use a dedicated capture API such as ScreenshotNeo’s capture_pdf tool.

Which engine should a visual regression suite use?

Use the engine that represents the browser behavior you need to protect, and keep that choice fixed for comparable baselines. Add other engines only when cross-engine rendering is part of the requirement.

Frequently Asked Questions

Does Playwright save screenshots as bytes or only files?

Both. Supplying path writes a file; omitting it returns bytes that your Python code can upload or process.

Can I capture a PDF with page.screenshot()?

No. Screenshots produce raster images. Use Playwright’s PDF capabilities for PDF output in supported Chromium workflows, or use a dedicated capture API such as ScreenshotNeo’s capture_pdf tool.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which engine should a visual regression suite use?

Use the engine that represents the browser behavior you need to protect, and keep that choice fixed for comparable baselines. Add other engines only when cross-engine rendering is part of the requirement.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.