Menu
Sign up

Screenshots in Python: Playwright, pyppeteer or an API

Website screenshots from Python in 2026: pyppeteer is unmaintained and ships Chromium 117, Playwright is current. Tested code, and an API option.

Published November 6, 2026 · 4 min read

To take website screenshots from Python today, use Playwright for Python: pip install playwright, playwright install chromium, then page.screenshot(path="shot.png", full_page=True). pyppeteer, the Python port of Puppeteer that many tutorials still use, is unmaintained — its own README says so — and when we ran it on 2026-11-06 it downloaded Chromium 117, a browser from 2023. If you would rather not run a browser at all, a screenshot API takes the URL over HTTP. This page compares the three with code we ran on that date.

pyppeteer: works, but frozen in 2023

The pyppeteer README opens with: "This repo is unmaintained and has been outside of minor changes for a long time. Please consider playwright-python as an alternative." The last release on PyPI, 2.0.0, is from February 2024.

It still runs. In the official Playwright Python image (Python 3.12), pip install pyppeteer==2.0.0 and a first launch() downloaded a 183 MB Chromium build into ~/.local/share/pyppeteer, and a full-page screenshot worked. browser.version() reported HeadlessChrome/117.0.5938.0. That is the problem: a browser three years behind misses CSS and JavaScript features that current sites use, renders some pages differently from what visitors see, and gets no security fixes — while it loads pages from the internet.

# pyppeteer — shown for comparison; prefer Playwright for new code
import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(args=["--no-sandbox"])
    page = await browser.newPage()
    await page.setViewport({"width": 1280, "height": 800})
    await page.goto("https://example.com", waitUntil="networkidle2")
    await page.screenshot({"path": "page.png", "fullPage": True})
    await browser.close()

asyncio.run(main())

If you maintain code like this, moving to Playwright is mostly renaming: newPage → new_page, options become keyword arguments, fullPage becomes full_page.

Playwright for Python: the current choice

Playwright for Python (1.64.1 when we tested) installs its own matched browser builds and has a synchronous API, which keeps scripts simple:

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}, device_scale_factor=2)
    page.goto("https://example.com", wait_until="networkidle")

    page.screenshot(path="viewport.png")                    # the visible area
    page.screenshot(path="full.png", full_page=True)        # the whole page
    page.locator("h1").screenshot(path="heading.png")       # one element
    jpeg = page.screenshot(type="jpeg", quality=80)         # bytes, no file

    browser.close()

Setup: pip install playwright, then playwright install --with-deps chromium downloads Chromium and, on Debian or Ubuntu, the system libraries it needs. In Docker, the official mcr.microsoft.com/playwright/python image has both; our test above ran there and took about a second for all four captures of a local page, with the viewport file at 2560×1600 (2×) as set.

For many pages, use the async API and a few pages in parallel:

import asyncio
from playwright.async_api import async_playwright

async def shoot(browser, url, path):
    page = await browser.new_page(viewport={"width": 1280, "height": 800})
    try:
        await page.goto(url, wait_until="networkidle", timeout=30_000)
        await page.screenshot(path=path, full_page=True)
    finally:
        await page.close()

async def main(urls):
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        semaphore = asyncio.Semaphore(4)  # at most four pages at a time
        async def limited(i, url):
            async with semaphore:
                await shoot(browser, url, f"shot-{i}.png")
        await asyncio.gather(*(limited(i, u) for i, u in enumerate(urls)))
        await browser.close()

asyncio.run(main(["https://example.com", "https://example.org"]))

Everything that makes Puppeteer screenshots go wrong applies here too, because it is the same Chromium: lazy images that stay blank in full-page captures, fixed headers in the middle, missing emoji fonts in containers. Our measured write-ups for full-page screenshots and emoji and fonts carry over one to one; our Playwright screenshot guide covers Playwright's extras (masking, animations="disabled").

Selenium

Selenium also takes screenshots from Python (driver.save_screenshot()), but its full-page method, get_full_page_screenshot_as_file(), exists only for Firefox; with Chrome you end up resizing the window, stitching, or calling the DevTools protocol yourself. For screenshots specifically, Playwright is less work.

Or no browser at all: an API

Running Chromium from Python means a 150–200 MB browser, its system libraries, and memory per page — fine on a server you control, awkward in AWS Lambda, Cloud Functions or a small container. A screenshot API moves that elsewhere:

import os, requests

r = requests.post(
    "https://shareglint.com/v1/screenshots?wait=true",
    headers={"Authorization": f"Bearer {os.environ['OG_API_KEY']}"},
    json={"url": "https://example.com", "full_page": True, "lazy_load": True, "format": "png"},
    timeout=60,
)
r.raise_for_status()
print(r.json()["url"])  # the finished screenshot

lazy_load scrolls through the page first and block_cookie_banners accepts consent dialogs. A viewport capture is 1 render of quota, a full page 2, and the same URL with the same options within 24 hours is free (pricing). The Python screenshot API guide has async and webhook versions. An API only reaches public pages; for an intranet or pages behind a login, run Playwright yourself.

Which to choose

  • New Python code that drives a browser: Playwright.
  • Existing pyppeteer code: move it to Playwright; the browser it ships is three years old,, and the changes are mostly mechanical renames of methods and options.
  • Screenshots in serverless functions or many sites at scale, public pages only: an API.

FAQ

Is pyppeteer still maintained?

No. Its README says the repository is unmaintained and recommends playwright-python instead. The last release, 2.0.0, is from February 2024, and on 2026-11-06 it still downloaded Chromium 117 from 2023.

What is the Python equivalent of Puppeteer?

Playwright for Python, maintained by Microsoft. Its API is close to Puppeteer's (page.goto, page.screenshot) and it has both a synchronous and an asyncio interface. Version 1.64.1 was current when we tested.

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

With Playwright: page.screenshot(path='full.png', full_page=True) after page.goto(url). For lazy-loaded images, scroll through the page first; the same rules as in Puppeteer apply.

Can I take screenshots in Python without installing a browser?

Yes, with a screenshot API: one HTTP request with the URL returns the image. That suits serverless functions and small servers where installing Chromium and its system libraries is a burden.