What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchThe 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.
#1 Best Overall
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.
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:
Rank #2
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:
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →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.
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
- Wait for the state you intend to document. Navigate with an appropriate
wait_untilvalue, then wait for a selector representing finished content. - Fix the viewport. Responsive breakpoints change layout, text wrapping, and image selection.
- Control data and time. Use a test account, stable fixtures, and a predictable timezone where the page depends on them.
- Handle cookie dialogs and overlays. Dismiss them or hide them before the screenshot if they obscure the target.
- Close every browser. A context manager or
try/finallyprevents 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.
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.
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.
Best Value
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.
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.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteShould 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").
Quick Recap
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.

