Python guide · Published October 16, 2026 · 9 min read

Take a Website Screenshot in Python: 5 Ways Compared (Selenium vs Playwright vs API)

Quick answer

To take a screenshot of a website in Python, install Playwright (pip install playwright and playwright install chromium), open the URL and call page.screenshot(path="page.png", full_page=True). Use Selenium if you already have it, the headless Chrome CLI for a dependency-free one-off, and a screenshot API when you need thousands of captures without running browsers.

5methods tested on the same page
2 of 5give a full page with one option in any browser
657 pxviewport height Selenium gave us for an 800 px window
0browsers to install with an API

"Screenshot in Python" means two different things on Stack Overflow: capturing your desktop, and capturing a web page from a URL. This guide is about the second one. We ran all five approaches against the same Wikipedia article on a MacBook with Chrome installed, using the code below unchanged, and wrote down what each one returned.

The comparison

MethodFull pageElementWaits for contentSetupOur result
PlaywrightYes, one flagYesAuto-waits on locatorspip + browser download1280×4611, full article
SeleniumFirefox only, or CDP in ChromeYesExplicit waitspip; driver auto-managed1280×657, viewport
Headless Chrome CLINo, fixed windowNoNoChrome only1280×800, viewport
html2imageNo, fixed sizeNoNopip + Chrome1280×800, viewport
Screenshot APIYes, one parameterYes (selector)Yes (wait parameters)pip install requestsDepends on parameters

Timings on a single cold run ranged from about 1.4 s (Selenium, Chrome CLI) to 3.5 s (Playwright with a full-page capture). That is one run on one laptop, so treat it as a rough order, not a benchmark.

1Playwright for Python

Full pageElementAuto-waitChromium, Firefox, WebKit
bash
pip install playwright playwright install chromium
python
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://en.wikipedia.org/wiki/Screenshot") page.screenshot(path="full.png", full_page=True) page.locator("#firstHeading").screenshot(path="title.png") browser.close()

Of the four local methods, this is the only one that captured the whole article without extra code. Options use snake_case in Python (full_page, omit_background), and there is an async API (playwright.async_api) if your app is already async. Every option is explained in our Playwright screenshot guide.

Pick it when you write a new script or need full pages, elements or several browsers.
Skip it when you cannot download a browser (locked-down servers, serverless size limits).

2Selenium

ElementViewport only in ChromeHuge ecosystem
python
from selenium import webdriver options = webdriver.ChromeOptions() options.add_argument("--headless=new") options.add_argument("--window-size=1280,800") driver = webdriver.Chrome(options=options) try: driver.get("https://en.wikipedia.org/wiki/Screenshot") driver.save_screenshot("viewport.png") finally: driver.quit()

Selenium Manager downloads the matching chromedriver automatically, so pip install selenium is enough. The surprise in our run: the PNG was 1280×657, not 1280×800. --window-size sets the outer window, and the browser's own UI takes part of that height. If the exact viewport matters, set a taller window or capture through the DevTools Protocol.

For full pages you need Firefox's save_full_page_screenshot() or the CDP command Page.captureScreenshot in Chrome. Both are in our Selenium screenshot guide with working code.

Pick it when the screenshot is part of an existing Selenium test suite.
Skip it when you start from scratch and only need images.

3Headless Chrome from subprocess

No Python packagesViewport onlyNo waiting
python
import subprocess from pathlib import Path CHROME = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" # or "google-chrome" on Linux out = Path("cli.png").resolve() subprocess.run([ CHROME, "--headless", f"--screenshot={out}", "--window-size=1280,800", "--hide-scrollbars", "https://en.wikipedia.org/wiki/Screenshot", ], check=True, capture_output=True, timeout=60)

Chrome's own --screenshot flag writes a PNG of the window size you pass, and the result was exactly 1280×800. Passing an absolute path, as above, keeps the output location independent of where the script is started. There is no way to wait for a selector, so pages that render late come out half empty.

Pick it when you need a quick thumbnail of a static page and cannot add dependencies.
Skip it when the page is a JavaScript app or you need the full height.

4html2image

HTML strings and URLsFixed size
python
from html2image import Html2Image hti = Html2Image(size=(1280, 800), output_path=".") hti.screenshot(url="https://en.wikipedia.org/wiki/Screenshot", save_as="h2i.png") # It also renders your own HTML and CSS: hti.screenshot(html_str="<h1>Invoice #1042</h1>", css_str="h1 { color: #0f172a; }", save_as="invoice.png")

html2image is a thin wrapper around the same headless Chrome flag as method 3, with a friendlier API and the ability to render HTML strings. It finds an installed Chrome or Edge, or you pass browser_executable. If rendering your own templates is the main job, our HTML to image guide compares the options. The trade-offs are the same as the CLI: fixed size and no waiting.

Pick it when you turn generated HTML into images (cards, receipts, charts).
Skip it when you need full-page captures of real sites.

5A screenshot API

Full pageNo browserScalesPaid above free tier
python
import os import requests r = requests.get( "https://api.snapshotflow.com/screenshot", headers={"X-Api-Key": os.environ["SNAPSHOTFLOW_API_KEY"]}, params={ "url": "https://en.wikipedia.org/wiki/Screenshot", "full_page": "true", "width": 1280, "format": "webp", "block_cookie_banners": "true", "wait_until": "networkidle2", }, timeout=60, ) r.raise_for_status() with open("api.webp", "wb") as f: f.write(r.content)

The browser runs on the API side, so your Python environment only needs requests. That matters on AWS Lambda, in small containers and in notebooks. For hundreds of URLs at once, the batch endpoint captures up to 10 per request. Parameters such as wait_for_selector, selector, dark_mode and device_scale_factor replace the code you would otherwise write around Playwright.

Pick it when screenshots are a product feature, run in volume or run where Chrome cannot.
Skip it when the page is only reachable inside your private network (or self-host the API there).

Tools that look right but capture the wrong thing

LibraryWhat it actually captures
pyautogui.screenshot()Your monitor, pixel by pixel. The page must be open and visible.
PIL.ImageGrab.grab()Your monitor or a region of it. Same limitation.
mssFast multi-monitor screen capture. Great for desktop apps, not for URLs.
pyppeteerWeb pages, but its README says the repo is unmaintained and suggests playwright-python.

If you search "screenshot in python" and land on one of these, that is why your code cannot see anything below the fold or anything on a headless server.

Which one to pick

Your situationUse
New script, full pages, JavaScript-heavy sitesPlaywright
Screenshots inside existing Selenium testsSelenium
One static page, no packages allowedHeadless Chrome CLI
Rendering your own HTML templates to PNGhtml2image (or an API with an html parameter)
Hundreds of URLs, Lambda, notebooks, no browserScreenshot API

Takeaways

  • Playwright and an API give you a full-page capture with a single option; Selenium does it in one call only on Firefox.
  • Selenium's window size is not the viewport size; check your output dimensions.
  • The CLI and html2image are fine for static pages and generated HTML, not for apps that render late.
  • Desktop capture libraries cannot screenshot a URL.

Sources

FAQ

What is the best Python library to screenshot a website?

For most scripts, Playwright for Python. It installs its own browser, supports full-page and element screenshots in one call, and waits for elements automatically. Use Selenium if your project already runs Selenium tests.

How do I take a full-page screenshot of a website in Python?

With Playwright: page.screenshot(path='page.png', full_page=True). Selenium needs Firefox (save_full_page_screenshot) or a Chrome DevTools command, and the headless Chrome CLI and html2image only capture a fixed window size.

Can PIL ImageGrab or pyautogui screenshot a website?

They capture your physical screen, not a URL. They work only if the page is open and visible on your monitor, and they cannot capture content below the fold.

Is pyppeteer still a good choice?

The pyppeteer README says the repository is unmaintained and suggests playwright-python as the alternative, so new code should use Playwright instead.

Why is my Selenium screenshot shorter than the window size I set?

With --window-size, the size includes the browser window itself, so the page viewport is smaller. In our test, --window-size=1280,800 in headless Chrome produced a 1280x657 screenshot.

Screenshots from Python without a browser

One requests.get() returns a full-page PNG, WebP or PDF, with cookie banners blocked and JavaScript rendered. The free tier gives you 300 screenshots, no credit card required.