Use Playwright’s Python API: install the package and browser binaries, open the URL in a headless browser, then call page.screenshot(path="screenshot.png"). PNG is Playwright’s default screenshot format, so this saves a rendered page as a PNG without image-conversion code.
This guide covers viewport and full-page captures, element screenshots, synchronous and asynchronous programs, reproducibility, common failures, and a hosted alternative when you do not want to maintain browser binaries.
Install Playwright and its browsers
Playwright needs two installations: the Python package and the browser binaries that it controls. Run both commands in the environment where your script will execute:
pip install playwright
playwright install
The second command downloads the browsers. Playwright supports Chromium, Firefox and WebKit; launching Chromium is the shortest path for a standard PNG capture.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Save a webpage as a PNG
Create a file such as capture.py with this synchronous example:
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="screenshot.png")
browser.close()
Run it with python capture.py. The browser runs headless by default, page.goto() loads the address, and the screenshot is written relative to the process’s current directory. Supply an absolute path if another process must find the file reliably:
page.screenshot(path="/tmp/example-home.png")
Use a URL you are authorized to access. A successful navigation does not prove that every image, chart or client-rendered component has reached its final state; choose a wait condition that matches the page, as described below.
Choose the capture area
Viewport screenshot
With no extra options, Playwright captures the currently visible viewport. Set its dimensions when the responsive breakpoint matters, and do so before navigation:
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")
page.screenshot(path="desktop.png")
browser.close()
Creating the page with a fixed viewport makes desktop, tablet or mobile layouts predictable. For phone emulation, establish the viewport before calling goto, otherwise the page may have already selected a different responsive layout.
Full scrollable page
Pass full_page=True to include the page’s entire scrollable height:
page.screenshot(path="full-page.png", full_page=True)
Very long documents can produce large images and consume more memory. If you only need a visible section, an element capture is usually smaller and easier to process.
One element
Locate the component with a CSS selector (or another Playwright locator) and call its screenshot method:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #2
card = page.locator("article.product-card").first
card.screenshot(path="card.png")
The locator must resolve to an element that is present and visible. If the selector matches several nodes, select the intended one with .first, .nth(index) or a more specific selector.
Control PNG output and image fidelity
PNG, JPEG and WebP
PNG is the documented default. You can request another format when storage or transfer size matters:
page.screenshot(path="preview.webp", type="webp")
page.screenshot(path="preview.jpg", type="jpeg", quality=85)
The quality option applies to JPEG and WebP, not PNG. Keep PNG when you need lossless text, transparency or pixel comparison.
CSS pixels versus device pixels
Screenshot scale controls whether output follows CSS pixels or device pixels. scale="css" keeps high-density captures smaller; scale="device" preserves the device-pixel dimensions and can create a larger file:
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →page.screenshot(path="css-scale.png", scale="css")
page.screenshot(path="device-scale.png", scale="device")
Choose one scale consistently if images are compared in tests or committed as visual baselines.
Hide or restyle unstable content
The screenshot API accepts a stylesheet option. You can hide clocks, rotating banners or other elements that make repeated captures differ:
page.screenshot(
path="stable.png",
style=".live-clock, .carousel { visibility: hidden !important; }"
)
This changes only the capture’s presentation. It does not alter your production site.
Wait for the content you actually need
Playwright’s screenshot API documents a default timeout of 30,000 milliseconds. Navigation finishing is not a universal signal that lazy images, charts or client-side data are ready. Use a targeted wait that represents the page state required by your image.
Wait for a selector
page.goto("https://example.com/dashboard")
page.wait_for_selector("main.dashboard-ready")
page.screenshot(path="dashboard.png")
Wait for a fixed delay
page.goto("https://example.com/animation")
page.wait_for_timeout(1500)
page.screenshot(path="animation.png")
A delay is simple but tied to one site’s timing. Prefer a selector or another observable condition when possible.
Use network idle carefully
page.goto("https://example.com", wait_until="networkidle")
page.screenshot(path="network-idle.png")
Pages with analytics, polling or streaming connections may never become truly idle. In those cases, wait for the specific content instead of making network idle your only readiness test.
Disable animation for repeatable images
Combine a stylesheet that turns off transitions and animations with a deterministic viewport and wait condition:
page.screenshot(
path="comparison.png",
style="*, *::before, *::after { animation: none !important; transition: none !important; }"
)
Capture in an asyncio application
If your program already uses asyncio, use Playwright’s asynchronous API rather than blocking the event loop:
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallimport 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": 1280, "height": 800})
await page.goto("https://example.com")
await page.screenshot(path="async-shot.png", full_page=True)
await browser.close()
asyncio.run(main())
Every browser, page and navigation operation is awaited. Keep the synchronous API for scripts and worker code that does not run inside an event loop.
Capture bytes instead of writing a file
Omit path and the screenshot method returns image bytes. This is useful for HTTP responses, object storage or an image-processing pipeline:
png_bytes = page.screenshot(full_page=True)
with open("in-memory-copy.png", "wb") as output:
output.write(png_bytes)
The same pattern works with the asynchronous method by awaiting it.
A production-ready example
This script fixes the viewport, waits for a page-specific marker, disables motion and uses an explicit timeout:
Recommended Free Tools
from pathlib import Path
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
URL = "https://example.com"
OUTPUT = Path("artifacts/example.png")
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1366, "height": 900})
page.set_default_timeout(30_000)
try:
page.goto(URL, wait_until="domcontentloaded", timeout=30_000)
page.wait_for_selector("body", state="visible")
page.screenshot(
path=str(OUTPUT),
full_page=True,
scale="css",
style="*, *::before, *::after { animation: none !important; transition: none !important; }",
)
except PlaywrightTimeoutError as exc:
raise RuntimeError(f"Timed out while capturing {URL}") from exc
finally:
browser.close()
Create the artifacts directory before running this version, or change the output path to an existing directory. Replace the body wait with a selector that proves your application’s data is ready.
Troubleshoot common failures
“Executable doesn’t exist” or browser launch errors
The Python package is installed but the browser binaries are missing. Run playwright install in the same environment, container image or virtual environment that runs the script. In restricted build systems, install the binaries during image creation rather than at request time.
The file is blank or missing page content
Check the URL, wait for a page-specific selector and inspect whether the site requires a login, consent interaction or JavaScript data request. A completed navigation alone does not guarantee that late content has rendered.
Timeouts
The documented screenshot timeout is 30 seconds by default. Slow pages, blocked resources and selectors that never appear can all trigger it. Increase the timeout only when the site genuinely needs longer; first verify the selector and URL, and use a narrower readiness condition than perpetual network activity.
Only the visible portion was captured
Add full_page=True. If you need one component rather than the whole document, use a locator screenshot instead.
Mobile layout is wrong
Set the viewport before goto. A desktop-sized initial viewport can cause the site to select desktop CSS before you resize it.
Images or animations differ between runs
Fix the viewport and screenshot scale, wait for the content that matters, and disable animations or hide changing selectors with the stylesheet option. Avoid assuming a universal delay works for every site.
Output cannot be opened
Confirm that the parent directory exists and that your process can write to it. When returning bytes from a web service, send the PNG bytes with an image/png content type rather than treating them as text.
Playwright, Selenium and a hosted API
Playwright is the best default when you need current browser automation, full-page or element captures, sync or asyncio integration, and control over viewport, scale and repeatability. Selenium can be reasonable when your project already uses it, but the Selenium Python Bindings PDF located for this topic is a Release 2 reference. Its screenshot method names should therefore be checked against current Selenium documentation before you copy them into a new project.
Best Value
Choose a hosted service when downloading browsers, handling concurrency and maintaining a rendering environment are more work than the screenshot itself. Compare options by the browser stack you need, whether captures are viewport, full-page or element-specific, how much page-state control is exposed, and how failures are reported.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP or PDF, so Python code does not need to install or launch Playwright browsers. Its clean-shot workflow accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled.
Only clean shots are billed. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and whether the request was billed. An MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
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 minuteFor Python, use the API call below (the complete parameter reference is in the ScreenshotNeo documentation):
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
The API supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, 12 device presets or any viewport, retina scale, PDF paper and page-range controls, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for selectors, delays or network idle, request and resource blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, image resizing, user-selected cache TTLs, signed public-image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs are accepted to ease migration.
Pricing starts with 1,000 screenshots per month free without a card. Paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000 and Business $249 for 1,000,000; yearly billing provides two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to try the 1,000 monthly shots without a card.
Operational checklist
- Install both
playwrightand its browser binaries. - Set the viewport before navigation when responsive layout matters.
- Choose viewport, full-page or locator capture deliberately.
- Use PNG unless JPEG/WebP size or quality controls are required.
- Pick CSS-pixel or device-pixel scale and keep it consistent.
- Wait for the content your use case needs, not merely for navigation to finish.
- Disable motion and hide unstable selectors for visual comparisons.
- Close the browser in a
finallyblock in long-running or failure-prone jobs.
Frequently Asked Questions
Can Playwright save a screenshot directly as PNG?
Yes. PNG is the default screenshot type, and page.screenshot(path="screenshot.png") writes the image directly.
Free tools Windows power users keep installed
One-click scans. No signup required.
How do I return the screenshot from a Python web endpoint?
Omit path so Playwright returns bytes, then send those bytes with an image/png response type.
Which Playwright browser should I launch?
Chromium is a practical default; Playwright also provides Firefox and WebKit when your compatibility target requires them.
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.




