How to Take Website Screenshots in Python
Need to capture a webpage as an image from Python? There are three main approaches, each with different trade-offs. This guide walks through all three with working code, then compares them side-by-side.
Method 1: Playwright
Playwright is Microsoft's browser automation library. It ships a bundled Chromium binary and provides a clean async API.
Installation
pip install playwright
playwright install chromiumThe playwright install command downloads a Chromium binary (~150 MB). This is a one-time step.
Basic Screenshot
from playwright.sync_api import sync_playwright
def screenshot_playwright(url: str, output: str = "screenshot.png") -> None:
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1280, "height": 720})
page.goto(url, wait_until="networkidle")
page.screenshot(path=output)
browser.close()
screenshot_playwright("https://example.com")Full-Page Screenshot
page.screenshot(path="full.png", full_page=True)Dark Mode
page = browser.new_page(
viewport={"width": 1280, "height": 720},
color_scheme="dark",
)Capture a Specific Element
element = page.query_selector(".hero-section")
if element:
element.screenshot(path="hero.png")Pros and Cons
Pros: Full browser fidelity, supports Firefox and WebKit too, excellent async support, actively maintained.
Cons: 150 MB Chromium download, ~200 MB RAM per browser instance, you manage concurrency and process lifecycle, Chrome updates can break scripts.
Method 2: Selenium
Selenium is the oldest browser automation framework. It works with Chrome via ChromeDriver.
Installation
pip install selenium webdriver-managerwebdriver-manager automatically downloads the correct ChromeDriver for your Chrome version.
Basic Screenshot
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def screenshot_selenium(url: str, output: str = "screenshot.png") -> None:
options = Options()
options.add_argument("--headless=new")
options.add_argument("--window-size=1280,720")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)
try:
driver.get(url)
driver.implicitly_wait(5)
driver.save_screenshot(output)
finally:
driver.quit()
screenshot_selenium("https://example.com")Full-Page Screenshot (Chrome DevTools Protocol)
Selenium does not natively support full-page screenshots in Chrome. You need the CDP workaround:
import base64
def full_page_screenshot_selenium(driver, output: str) -> None:
metrics = driver.execute_cdp_cmd("Page.getLayoutMetrics", {})
width = metrics["contentSize"]["width"]
height = metrics["contentSize"]["height"]
driver.execute_cdp_cmd("Emulation.setDeviceMetricsOverride", {
"mobile": False,
"width": width,
"height": height,
"deviceScaleFactor": 1,
})
result = driver.execute_cdp_cmd("Page.captureScreenshot", {
"format": "png",
"captureBeyondViewport": True,
})
with open(output, "wb") as f:
f.write(base64.b64decode(result["data"]))Pros and Cons
Pros: Mature ecosystem, huge community, works with Chrome, Firefox, Edge, and Safari.
Cons: ChromeDriver version mismatches are painful, slower than Playwright, full-page capture requires CDP hacks, verbose API.
Method 3: SnapSharp API
The SnapSharp API handles browser rendering in the cloud. You send a URL, get an image back. No local browser needed.
Installation
pip install snapsharpBasic Screenshot (SDK)
from snapsharp import SnapSharp
import os
snap = SnapSharp(os.environ["SNAPSHARP_API_KEY"])
image = snap.screenshot("https://example.com", width=1280, height=720)
with open("screenshot.png", "wb") as f:
f.write(image)Basic Screenshot (raw HTTP)
import os
import requests
API_KEY = os.environ["SNAPSHARP_API_KEY"]
def screenshot_api(url: str, output: str = "screenshot.png", **kwargs) -> None:
params = {"url": url, "width": 1280, "height": 720, **kwargs}
response = requests.get(
"https://api.snapsharp.dev/v1/screenshot",
params=params,
headers={"Authorization": f"Bearer {API_KEY}"},
)
response.raise_for_status()
with open(output, "wb") as f:
f.write(response.content)
screenshot_api("https://example.com")Full-Page + Dark Mode
image = snap.screenshot(
"https://example.com",
full_page=True,
dark_mode=True,
format="webp",
)Batch Screenshots with Concurrency
import concurrent.futures
urls = [
"https://example.com",
"https://github.com",
"https://linear.app",
"https://vercel.com",
]
def capture(url: str) -> str:
domain = url.split("//")[1].split("/")[0]
image = snap.screenshot(url, width=1280)
path = f"{domain}.png"
with open(path, "wb") as f:
f.write(image)
return path
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool:
results = list(pool.map(capture, urls))Error Handling
from snapsharp import AuthError, RateLimitError, TimeoutError
try:
image = snap.screenshot("https://example.com")
except AuthError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
except TimeoutError:
print("Page took too long to render")Pros and Cons
Pros: No local browser, elastic scaling, dark mode / full-page / PDF / element capture built-in, ad blocking, handles Chrome updates for you.
Cons: Requires network access, costs money at scale (100 free/month), adds ~2–4s network latency compared to local capture.
Comparison Table
| Feature | Playwright | Selenium | SnapSharp API |
|---|---|---|---|
| Setup | pip install + browser download | pip install + ChromeDriver | pip install snapsharp |
| Local browser required | Yes (Chromium) | Yes (Chrome) | No |
| Full-page capture | Built-in | CDP hack | Built-in |
| Dark mode | color_scheme param | Manual emulation | dark_mode=True |
| Element capture | Built-in | Manual crop | selector param |
| PDF output | Built-in | Limited | Built-in |
| Ad blocking | Manual (route interception) | Manual (extensions) | block_ads=True |
| Concurrency | You manage processes | You manage drivers | Elastic (cloud) |
| RAM per capture | ~200 MB | ~250 MB | 0 (server-side) |
| Best for | E2E tests, local tooling | Legacy projects, cross-browser | Production APIs, serverless |
Which Should You Choose?
- Playwright if you're already running browser tests and want screenshots as a side effect.
- Selenium if you're locked into an existing Selenium test suite.
- SnapSharp API if you want zero-ops, serverless-compatible screenshot capture that scales without managing Chrome processes.
All three produce accurate screenshots. The difference is operational: how much infrastructure do you want to own?