Blog 6 min read

How to Screenshot a Website with Python: 3 Working Methods

Take website screenshots in Python using Playwright, Selenium, or a screenshot API. Complete code examples for each approach with setup instructions.

SnapRender Team
|

How to Screenshot a Website with Python: 3 Working Methods

Need to capture a website screenshot in Python? Whether you're building a web scraper, generating thumbnails, creating automated reports, or archiving pages, Python has several solid options.

This guide covers three approaches with working code you can copy-paste: Playwright (recommended for new projects), Selenium (if you're already using it), and a screenshot API (simplest, no browser management).

Method 1: Playwright (Recommended)

Playwright is the modern choice for browser automation in Python. It's maintained by Microsoft, supports Chrome, Firefox, and Safari, and has a clean synchronous API that feels natural in Python.

Installation

pip install playwright
playwright install chromium

The second command downloads a bundled Chromium binary (~150MB). This is a one-time download.

Basic Screenshot

from playwright.sync_api import sync_playwright

def take_screenshot(url: str, output_path: str = "screenshot.png"):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto(url, wait_until="networkidle")
        page.screenshot(path=output_path)
        browser.close()

take_screenshot("https://example.com")

Full-Page Screenshot

Capture the entire scrollable page, not just the visible viewport:

from playwright.sync_api import sync_playwright

def full_page_screenshot(url: str, output_path: str = "fullpage.png"):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto(url, wait_until="networkidle")
        page.screenshot(path=output_path, full_page=True)
        browser.close()

full_page_screenshot("https://example.com")

Custom Viewport Size

from playwright.sync_api import sync_playwright

def screenshot_with_size(url: str, width: int = 1920, height: int = 1080):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page(viewport={"width": width, "height": height})
        page.goto(url, wait_until="networkidle")
        page.screenshot(path="screenshot.png")
        browser.close()

screenshot_with_size("https://example.com", width=1440, height=900)

Mobile Device Emulation

from playwright.sync_api import sync_playwright

def mobile_screenshot(url: str, output_path: str = "mobile.png"):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        iphone = p.devices["iPhone 15 Pro"]
        page = browser.new_page(**iphone)
        page.goto(url, wait_until="networkidle")
        page.screenshot(path=output_path)
        browser.close()

mobile_screenshot("https://example.com")

Async Version

If you're using asyncio (FastAPI, aiohttp, etc.):

import asyncio
from playwright.async_api import async_playwright

async def take_screenshot_async(url: str, output_path: str = "screenshot.png"):
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto(url, wait_until="networkidle")
        await page.screenshot(path=output_path)
        await browser.close()

asyncio.run(take_screenshot_async("https://example.com"))

Generate PDF

from playwright.sync_api import sync_playwright

def page_to_pdf(url: str, output_path: str = "page.pdf"):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto(url, wait_until="networkidle")
        page.pdf(path=output_path, format="A4", print_background=True)
        browser.close()

page_to_pdf("https://example.com")

Error Handling

Production-ready code with timeouts and error handling:

from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeout

def safe_screenshot(url: str, output_path: str = "screenshot.png") -> bool:
    try:
        with sync_playwright() as p:
            browser = p.chromium.launch()
            page = browser.new_page()
            page.set_default_timeout(30000)

            response = page.goto(url, wait_until="networkidle", timeout=30000)

            if response and response.status >= 400:
                print(f"Page returned HTTP {response.status}")
                browser.close()
                return False

            page.screenshot(path=output_path)
            browser.close()
            return True

    except PlaywrightTimeout:
        print(f"Timeout loading {url}")
        return False
    except Exception as e:
        print(f"Error: {e}")
        return False

Method 2: Selenium

Selenium is the older browser automation tool. If you're already using it for testing or scraping, you can use it for screenshots too.

Installation

pip install selenium webdriver-manager

Basic Screenshot

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

def take_screenshot(url: str, output_path: str = "screenshot.png"):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument("--no-sandbox")
    options.add_argument("--window-size=1920,1080")

    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=options)

    driver.get(url)
    driver.save_screenshot(output_path)
    driver.quit()

take_screenshot("https://example.com")

Full-Page Screenshot

Selenium doesn't have built-in full-page capture like Playwright. You need to resize the window to the page height:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

def full_page_screenshot(url: str, output_path: str = "fullpage.png"):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument("--no-sandbox")

    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=options)

    driver.set_window_size(1920, 1080)
    driver.get(url)

    # Get the full page height
    total_height = driver.execute_script("return document.body.scrollHeight")
    driver.set_window_size(1920, total_height)

    driver.save_screenshot(output_path)
    driver.quit()

full_page_screenshot("https://example.com")

Selenium Limitations

  • No native wait_until="networkidle", so you need explicit waits or sleeps
  • Full-page screenshots require manual window resizing
  • WebDriver management adds complexity
  • No built-in device emulation presets
  • No WebP output format

For new projects, Playwright is the better choice. Use Selenium only if your project already depends on it.

Method 3: Screenshot API

If you don't want to install or manage a browser, a screenshot API handles everything server-side. You send a URL, it returns an image.

Installation

pip install snaprender

Basic Screenshot

from snaprender import SnapRender

client = SnapRender("YOUR_API_KEY")

image = client.screenshot(url="https://example.com")

with open("screenshot.png", "wb") as f:
    f.write(image)

Full-Page with Options

from snaprender import SnapRender

client = SnapRender("YOUR_API_KEY")

image = client.screenshot(
    url="https://example.com",
    format="webp",
    width=1920,
    height=1080,
    full_page=True,
    block_ads=True,
    block_cookie_banners=True,
    dark_mode=True
)

with open("screenshot.webp", "wb") as f:
    f.write(image)

Mobile Screenshot

from snaprender import SnapRender

client = SnapRender("YOUR_API_KEY")

image = client.screenshot(
    url="https://example.com",
    device="iphone_15_pro",
    format="png"
)

with open("mobile.png", "wb") as f:
    f.write(image)

Using requests Directly

If you prefer not to use the SDK:

import requests

response = requests.get(
    "https://app.snap-render.com/v1/screenshot",
    params={
        "url": "https://example.com",
        "format": "png",
        "width": 1920,
        "height": 1080
    },
    headers={"X-API-Key": "YOUR_API_KEY"}
)

if response.status_code == 200:
    with open("screenshot.png", "wb") as f:
        f.write(response.content)
else:
    print(f"Error: {response.json()}")

Comparison

Feature Playwright Selenium Screenshot API
Setup complexity Medium Medium Minimal
Browser download ~150MB Chromium ChromeDriver None
Full-page capture Built-in Manual resize Built-in
Mobile emulation Built-in presets Manual config Built-in presets
Output formats PNG, JPEG, PDF PNG only PNG, JPEG, WebP, PDF
Ad blocking Manual implementation Manual implementation Built-in
Cookie banners Manual implementation Manual implementation Built-in
Async support Yes No Yes (via aiohttp)
Memory usage 50-300MB per tab 50-300MB per tab None (server-side)

Batch Screenshots

Here's a practical example of screenshotting multiple URLs:

With Playwright (Async)

import asyncio
from playwright.async_api import async_playwright

async def batch_screenshots(urls: list[str]):
    async with async_playwright() as p:
        browser = await p.chromium.launch()

        for url in urls:
            page = await browser.new_page()
            try:
                await page.goto(url, wait_until="networkidle", timeout=30000)
                filename = url.replace("https://", "").replace("/", "_") + ".png"
                await page.screenshot(path=filename)
                print(f"Captured: {url}")
            except Exception as e:
                print(f"Failed: {url} — {e}")
            finally:
                await page.close()

        await browser.close()

urls = [
    "https://github.com",
    "https://stackoverflow.com",
    "https://python.org"
]

asyncio.run(batch_screenshots(urls))

With Screenshot API

from snaprender import SnapRender
from concurrent.futures import ThreadPoolExecutor

client = SnapRender("YOUR_API_KEY")

def capture(url: str):
    try:
        image = client.screenshot(url=url, format="webp")
        filename = url.replace("https://", "").replace("/", "_") + ".webp"
        with open(filename, "wb") as f:
            f.write(image)
        print(f"Captured: {url}")
    except Exception as e:
        print(f"Failed: {url} — {e}")

urls = [
    "https://github.com",
    "https://stackoverflow.com",
    "https://python.org"
]

with ThreadPoolExecutor(max_workers=5) as executor:
    executor.map(capture, urls)

Which Method Should You Use?

Use Playwright if:

  • You need full browser control (clicking, typing, scrolling before capture)
  • You're building a scraping or testing pipeline
  • You want to avoid third-party API dependencies

Use Selenium if:

  • Your project already uses Selenium for other tasks
  • You don't want to learn a new library

Use a Screenshot API if:

  • You want the simplest code with the least maintenance
  • You don't want to install or manage Chromium
  • You need features like ad blocking and cookie banner removal out of the box
  • You're deploying to environments where running a browser is impractical (serverless, shared hosting)

SnapRender offers 500 free screenshots per month with no credit card required. Get your API key in 30 seconds and start capturing.

Try SnapRender Free

500 free screenshots/month, no credit card required.

Sign up free