ScreenshotNeo

BlogGuides

Best Playwright Screenshot Tools for Python

Compare Playwright’s built-in screenshot, pytest, and trace workflows for Python, with runnable examples for full-page, element, and test-failure captures.

By the ScreenshotNeo team4 October 20269 min read

Direct answer: For most Python projects, use Playwright’s built-in page.screenshot() for a viewport or full-page image, and locator.screenshot() for a specific element. For automated test artifacts, use the Playwright pytest plugin; for debugging how a visual state happened, record a trace and inspect its screenshots and DOM snapshots in Trace Viewer. These are complementary Playwright workflows, not separate third-party screenshot products.

This guide covers when to use each option, runnable synchronous and asynchronous examples, test failure capture, repeatability, limitations, and troubleshooting. See the official Playwright Python Screenshots guide and ScreenshotNeo API documentation.

1. Which Playwright screenshot workflow should you choose?

Need Use What you get
Capture the visible browser page page.screenshot() An image file or image bytes
Capture the whole scrollable page page.screenshot(full_page=True) A tall image of the full page
Capture one card, chart, or component locator.screenshot() An image of the located element
Save test evidence automatically Playwright pytest plugin options Screenshots associated with test runs
Understand the actions and page state around a capture Tracing and Trace Viewer A trace archive with action timeline, screenshots, and snapshots

The simplest and most direct tool is the built-in screenshot API. A full-page screenshot is “a screenshot of a full scrollable page, as if you had a very tall screen and the page could fit it entirely,” as described in the Playwright Python Screenshots documentation. Choose pytest capture or tracing when the context of a test run matters as much as the image.

2. Install Playwright and prepare a page

Install the Python package and its browser binaries, then create a browser context with a fixed viewport if consistent dimensions matter.

python -m pip install playwright
python -m playwright install chromium

Save the following as capture.py and run it with python capture.py. It captures both the initial viewport and the full page.

from pathlib import Path
from playwright.sync_api import sync_playwright

URL = "https://example.com"

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context(viewport={"width": 1440, "height": 900})
    page = context.new_page()
    page.goto(URL, wait_until="networkidle", timeout=60_000)

    page.screenshot(path="viewport.png")
    page.screenshot(path="full-page.png", full_page=True)

    browser.close()

Use a project-appropriate URL and readiness condition. Some sites keep network connections open, so networkidle may never be a suitable signal; in those cases wait for a meaningful selector or use a bounded delay after navigation.

3. Capture a viewport, a full page, or image bytes

Viewport image

By default, page.screenshot() captures the currently visible viewport. Pass a path to write an image, or omit it and use the returned bytes for further processing.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1280, "height": 800})
    page.goto("https://example.com", wait_until="domcontentloaded")

    png_bytes = page.screenshot()
    with open("page.png", "wb") as image_file:
        image_file.write(png_bytes)

    browser.close()

Full-page image

Set full_page=True to capture the scrollable page as one image. Very long pages can create large image files and consume more memory; consider whether a viewport capture or several targeted captures meet the need.

page.screenshot(path="whole-page.png", full_page=True)

Async version

Use Playwright’s async API when the surrounding application already uses asyncio. Do not call the synchronous API from an async event loop.

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(viewport={"width": 1440, "height": 900})
        await page.goto("https://example.com", wait_until="domcontentloaded")
        await page.screenshot(path="page.png", full_page=True)
        await browser.close()

asyncio.run(main())

4. Screenshot one element with a locator

Use a locator when the intended subject is a component or region, such as a product card, chart, or navigation bar. Locator screenshots wait for actionability and scroll the element into view. The locator API is preferred to the discouraged ElementHandle.screenshot() approach.

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", wait_until="domcontentloaded")

    card = page.locator(".product-card").first
    card.screenshot(path="product-card.png", animations="disabled")

    browser.close()

Use a selector that identifies one intended element. If the selector can match multiple elements, choose .first, .nth(index), or a more specific locator deliberately. A covered element may not actually be visible in the resulting image. For a scrollable container, the screenshot captures only the container content currently scrolled into view; it does not stitch every internal scroll position into one image.

5. Screenshot options for stable output

Screenshot options let you control output type, scale, animation handling, page styling, and timeout. Use only the controls that address your capture requirement.

Option Purpose Practical note
path Write image output to a file Without a path, screenshot APIs return bytes.
type Select PNG or JPEG output Check the installed Playwright version for format support; WebP support was added in version 1.62.
quality Set lossy image quality where supported Relevant to JPEG and supported lossy formats, not PNG.
full_page Capture the whole scrollable page Can produce a tall, memory-heavy image.
scale Choose output pixel scaling "css" means one image pixel per CSS pixel; device scale can produce larger output on high-DPI settings.
animations Control animation during capture "disabled" helps avoid transient animation frames.
style Apply CSS for the capture Can hide or normalize dynamic elements without changing application files.
timeout Bound the screenshot operation Set a value appropriate to the page and environment.
page.screenshot(
    path="stable.png",
    full_page=True,
    animations="disabled",
    scale="css",
    style=".timestamp { visibility: hidden !important; }",
    timeout=30_000,
)

Fix the browser context viewport using browser.new_context(viewport={"width": ..., "height": ...}) when layout dimensions matter. A fixed viewport and disabled animations improve repeatability, but do not guarantee identical pixels across operating systems, browser builds, fonts, or application states. Validate the exact environment used for comparisons.

6. Use pytest to save screenshots from tests

The Playwright pytest plugin can save screenshots automatically after tests. Install the plugin and invoke it with screenshot capture enabled:

python -m pip install pytest-playwright
python -m playwright install chromium
pytest --screenshot=only-on-failure

To request a full-page screenshot on failure, enable screenshot capture as well as the full-page option:

pytest --screenshot=only-on-failure --full-page-screenshot

The full-page flag depends on screenshot capture being enabled. These CLI settings apply to the plugin’s default fixtures. If a test creates its own browser, context, or page objects, the plugin arguments do not automatically configure those objects; call page.screenshot() yourself in that flow.

Use automatic capture when you want artifacts from a test run without adding screenshot calls to every test. Use explicit screenshot code when you need a particular point in the test, filename, selector, or capture options.

7. Record a trace when the screenshot needs context

A standalone screenshot shows what the page looked like. A trace can help explain how the page reached that state: Trace Viewer presents screenshots in an action timeline alongside action details, DOM snapshots, source locations, and logs.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context()
    context.tracing.start(screenshots=True, snapshots=True, sources=True)

    page = context.new_page()
    page.goto("https://example.com", wait_until="domcontentloaded")
    page.get_by_role("link").first.click()

    context.tracing.stop(path="trace.zip")
    browser.close()

Open the archive with the Playwright CLI:

python -m playwright show-trace trace.zip

Tracing is useful for diagnosing interactions and test failures. It creates a trace archive rather than a simple image, so use direct screenshot calls when the required deliverable is only a PNG or JPEG.

8. Troubleshooting common screenshot problems

Symptom Likely cause Fix
Browser executable is missing The Playwright package is installed but browser binaries are not. Run python -m playwright install chromium (or install the browser your project uses).
Navigation times out The site remains busy or the chosen load condition is too strict. Try domcontentloaded, then wait for a specific selector that signals the content you need.
Screenshot contains a loading state Navigation completed before application content was ready. Wait for a meaningful locator or a bounded delay after navigation.
Element screenshot times out The locator is missing, ambiguous, hidden, or never becomes actionable. Inspect the selector and page state; target a unique visible element.
Element is missing or obscured An overlay covers it, or the page state differs from expectations. Dismiss the overlay or capture after the intended state is reached; locator capture cannot make a covered element visible.
Only part of a scrollable widget appears Locator screenshot captures its current scrolled content. Scroll the widget to the desired position and capture separately, or use an application-specific export.
Full-page output is unexpectedly large The page is tall or contains large images. Use a viewport or element capture, or choose an appropriate output format and scale.
Visual comparison changes between runs Animations, dynamic content, viewport, fonts, browser, or OS differ. Fix the context viewport, disable animations, normalize changing elements with screenshot style, and keep the rendering environment consistent.
Pytest did not save a screenshot Capture options were omitted, or the test uses manually created objects. Enable the plugin screenshot option; for custom pages call page.screenshot() explicitly.
WebP type is rejected The installed Playwright version may not support WebP. Check the installed version; WebP support for page and locator screenshots was added in Playwright 1.62.

9. Performance, reliability, and cost considerations

  • Performance: Full-page screenshots can be much larger than viewport captures, and trace archives also include diagnostic context. Capture only the region and artifacts needed. The cited Playwright documentation does not establish a universal speed ranking among these workflows.
  • Reliability: Set the viewport, wait for the content you need, and disable or normalize animations for more repeatable captures. Network-idle waiting can be unsuitable for pages with persistent traffic. Browser, font, operating-system, and app-state changes can still alter pixels.
  • Cost: Playwright is an open-source browser automation library; the cited screenshot workflows do not specify a per-capture service fee. Your practical costs come from the compute and storage used to run browsers and retain images or traces.
  • Choosing artifacts: Save image bytes when your program will process or upload the image; use files for simple local artifacts, pytest capture for test evidence, and traces for visual debugging context.

10. Or skip the browser setup

If you need a screenshot without installing and running a browser, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request accepts a URL and returns a PNG, JPEG, WebP, or PDF. See the API documentation.

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}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

Cookie banners are accepted and removed along with known consent platforms, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, failed loads, and cache hits are not billed, and response headers report page verdict and billing status. AI agents can use the MCP server’s take_screenshot, get_page_info, and capture_pdf tools. The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots.

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

11. Frequently asked questions

Can Playwright Python return screenshot data without saving a file?

Yes. Screenshot methods return image bytes when you do not provide a path, so you can process or upload the result in memory.

Should I use sync or async Playwright?

Use the API style that fits the application. The async API is appropriate when the project already uses asyncio; the sync API is straightforward for ordinary scripts.

Does a full-page screenshot include every item inside an independently scrolling widget?

No. Full-page capture concerns the page’s scrollable document. A locator screenshot of a scrollable container captures its currently scrolled content.

Are pytest screenshots and traces interchangeable?

No. A screenshot is an image artifact; a trace is a diagnostic archive that can associate screenshots with actions and page snapshots.

Does using a fixed viewport guarantee pixel-identical screenshots?

No. It controls layout dimensions, but browser version, operating system, fonts, dynamic data, and application state can still affect rendering.

Sources