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.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Playwright’s Python screenshot API when you need a rendered website image rather than a desktop capture. Install the Python package and its browser binaries, open a page, navigate to a URL, and call page.screenshot(). The same API supports synchronous and asynchronous programs, viewport or full-page images, element-only captures, and in-memory bytes for further processing.

This guide walks through a working setup, explains the capture modes and options that matter in production, and shows when a hosted service such as ScreenshotNeo can remove browser-infrastructure work.

What a Python screenshot API actually captures

Playwright automates a real browser engine (Chromium, Firefox, or WebKit) and captures the page after it has been rendered. It is not an operating-system screenshot utility: it does not photograph your desktop, other windows, or the browser chrome. The output is the web document inside the page viewport, the complete scrollable document, or a selected element.

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

The official Playwright guides document both sync and async Python APIs, file output and byte buffers, full-page capture, and locator-based element screenshots. See the Screenshots guide and library setup guide.

Install Playwright and browser binaries

Use the same Python environment that will run your script:

python -m pip install playwright
python -m playwright install

The second command downloads the supported Chromium, Firefox, and WebKit browser binaries. Installing only the Python package is not enough on a new machine or container. In a locked-down build environment, make sure the process can write Playwright’s browser-cache directory or configure the cache location according to your deployment system.

Verify the installation

Save the following as quickshot.py and run python quickshot.py. It writes example.png in the current directory.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.screenshot(path="example.png")
    browser.close()

This follows the official getting-started sequence: start Playwright, launch an engine, create a page, navigate, capture, and close the browser.

How to take a screenshot with Playwright Python

Synchronous capture to a file

The synchronous API is convenient for scripts, command-line jobs, and ordinary worker processes:

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, wait_until="load")
    page.screenshot(path="screenshot.png")
    browser.close()

page.goto returns after the chosen navigation condition. For pages that continue loading data, add an explicit wait for a meaningful selector or application state rather than assuming the first paint is final.

Asynchronous capture

Use the async API when your application already runs an asyncio event loop, such as an async web service or job queue:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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", wait_until="load")
        await page.screenshot(path="screenshot.png")
        await browser.close()

asyncio.run(main())

Do not mix synchronous calls into an async event loop. Conversely, a small synchronous script does not need the additional async structure.

Choose the capture mode

Requirement Code Result
Visible viewport page.screenshot(path="screenshot.png") The currently sized browser viewport.
Entire scrollable page page.screenshot(path="screenshot.png", full_page=True) A stitched image of the page content, not the operating-system screen.
Bytes for processing or upload screenshot_bytes = page.screenshot() An image byte buffer; write it yourself or pass it to storage, a response, or a pixel-diff tool.
One element page.locator(".header").screenshot(path="header.png") The rendered bounds of the matching locator.

Full-page images

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

Full-page mode is useful for documentation and visual regression, but very tall pages can create large images and higher memory use. If a site lazy-loads content only while scrolling, ensure that the required content is actually loaded before capture; Playwright’s screenshot option alone does not guarantee that every application-specific lazy loader has finished.

Capture to memory

from pathlib import Path

image_bytes = page.screenshot()
Path("screenshot.png").write_bytes(image_bytes)

The buffer form avoids a temporary file and lets you upload directly to object storage, return an HTTP response, or compare pixels in a test pipeline.

Capture a single element

header = page.locator(".header")
header.screenshot(path="header.png")

Use a stable CSS selector, role, or test identifier. If the locator matches zero elements, or several elements when one is required, the capture fails; make the locator specific and wait for it to appear.

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

Control viewport, browser engine, and output

Set a deterministic viewport

page = browser.new_page(viewport={"width": 1440, "height": 900})

Set the viewport before navigation so responsive CSS chooses the intended layout. The Page API reference notes that many sites do not expect a phone-sized viewport simply because the browser window is narrow; use context screen and viewport settings deliberately. The documentation does not establish a universal screenshot-quality winner among Chromium, Firefox, and WebKit, so choose the engine that matches the browser behavior you need to represent.

Use a different engine

with sync_playwright() as p:
    browser = p.firefox.launch()
    page = browser.new_page(viewport={"width": 1280, "height": 800})
    page.goto("https://example.com")
    page.screenshot(path="firefox.png")
    browser.close()

Run separate captures when cross-engine rendering is part of your test matrix; do not infer equivalence from one engine.

Animation and sensitive regions

For visual tests, freeze or disable animations and mask dynamic or private regions where appropriate. Playwright exposes screenshot options such as mask and animations; exact option behavior can vary by installed Playwright version, so check the current screenshot documentation for your version. The official locator API source includes an element screenshot example and animation handling: locator API reference.

Make captures repeatable

  1. Wait for the state you intend to document. Navigate with an appropriate wait_until value, then wait for a selector representing finished content.
  2. Fix the viewport. Responsive breakpoints change layout, text wrapping, and image selection.
  3. Control data and time. Use a test account, stable fixtures, and a predictable timezone where the page depends on them.
  4. Handle cookie dialogs and overlays. Dismiss them or hide them before the screenshot if they obscure the target.
  5. Close every browser. A context manager or try/finally prevents orphaned browser processes in repeated jobs.

A minimal selector wait looks like this:

page.goto("https://example.com", wait_until="domcontentloaded")
page.locator("main").wait_for(state="visible")
page.screenshot(path="ready.png")

Troubleshooting common failures

“Executable doesn’t exist” or browser launch errors

Install the binaries with python -m playwright install. In CI, run it during image creation and verify that the runtime user can read the cache.

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

Timeout while navigating

The server may be slow, a third-party request may never finish, or the URL may require authentication. Use a realistic timeout, wait for a specific application selector instead of indefinite network idle, and inspect the URL from the same network environment as the worker.

Blank or half-rendered image

Capture only after the content selector is visible and any client-side data request has completed. For lazy content, scroll or trigger the application’s loading behavior before taking a full-page shot.

Cookie banner, chat bubble, or modal covers the page

Locate and dismiss the overlay, or hide its selector before capture. Keep this cleanup in a helper so every page in a batch follows the same policy.

Element screenshot fails

Check that the selector is correct, unique, visible, and inside the page rather than a cross-origin frame. Wait for the element and capture its locator, not a guessed coordinate.

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

Huge files or memory pressure

Prefer a viewport capture for monitoring, limit full-page captures to pages that need them, and process byte buffers without retaining many images simultaneously. Close each browser and context after the job.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When a hosted screenshot API is a better fit

Playwright gives you control, but you must package browser binaries, manage workers, handle overlays, and operate retries. For a service/API recommendation, ScreenshotNeo is #1: it produces clean shots, bills only clean shots, and its lowest paid plan is $5.

Or skip the browser setup

ScreenshotNeo accepts one GET request and returns PNG, JPEG, WebP, or PDF. Before capture it can accept cookie/consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and whether it was billed.

Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

cURL:

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

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}`);

See the ScreenshotNeo API documentation for parameters and response details. Its 63 options include full-page capture with lazy-image loading, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper/margins/page ranges, custom CSS and JavaScript, pre-capture clicks, selector hiding, selector/delay/network-idle waits, request and resource blocking, headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, async jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

The MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Plans include 1,000 screenshots per month free with no card; paid tiers start at $5 for 3,000 shots. Yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.

Cost, reliability, and operational choices

  • Self-hosted Playwright: no per-capture API charge, but you operate browser downloads, CPU, memory, concurrency, retries, and cleanup.
  • ScreenshotNeo: usage is metered by clean shots; failed loads and cache hits are identified as non-billed responses. A hosted endpoint avoids maintaining browser workers and adds async webhooks and bulk requests.
  • Either approach: record the URL, viewport, engine or service parameters, timestamp, and outcome so a changed image can be explained rather than guessed.

There is no documented benchmark here proving one browser engine or service produces universally more faithful pixels. Choose based on control, deployment burden, cleanup needs, and whether your workload is one script or a recurring capture system.

Frequently Asked Questions

Can Playwright capture a screenshot without saving a file?

Yes. Call page.screenshot() without path to receive image bytes, then upload or process the buffer.

Is a full-page screenshot the same as a desktop screenshot?

No. full_page=True captures the page’s scrollable document. It does not include the operating-system desktop or browser controls.

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

Should a Python web service use sync or async Playwright?

Use the API style that matches the surrounding application: synchronous code for simple scripts and async code for an existing asyncio service or queue.

How do I capture only a header or card?

Create a locator for the element and call its screenshot method, for example page.locator(".header").screenshot(path="header.png").

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.