Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Call Playwright’s screenshot method without a path. In synchronous Python, page.screenshot() returns image data as bytes; in asynchronous Python, use await page.screenshot(). The bytes stay in memory, so you can send them to an image processor, object store, HTTP response, or another service without creating a local image file.

The examples below cover both APIs, full-page and element captures, output formats, reliability controls, troubleshooting, and a hosted alternative when you do not want to operate a browser.

What “in-memory” means in Playwright

Playwright writes a screenshot to disk only when you provide path. Omit that argument and the Python API returns the encoded image as a bytes value. PNG is the default format. The official [Screenshots guide](https://playwright.dev/python/docs/screenshots) demonstrates this pattern, while the [Page API](https://playwright.dev/python/docs/api/class-page) documents the available options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In-memory capture is useful when a web request should return an image directly, when a queue consumer uploads bytes to object storage, or when a computer-vision pipeline needs an array rather than a filename. It also avoids temporary-file cleanup and the permissions problems that come with writing to a container’s filesystem.

Prerequisites and browser installation

  1. Install the Python package: pip install playwright.
  2. Install at least one supported browser for Playwright: playwright install chromium. In a CI image you may need the project’s documented system-dependency option as well.
  3. Use a URL that your execution environment can reach, and wait for the page state your capture requires.

Playwright’s [library guide](https://playwright.dev/python/docs/library) shows the supported installation workflow. Keep the package and browser binaries aligned; after upgrading Playwright, run the browser installation command again if the required revision changed.

Synchronous Python: return bytes directly

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", wait_until="networkidle")

    screenshot_bytes = page.screenshot()
    # screenshot_bytes is a Python bytes object.
    # Pass it to an image library, upload client, or HTTP response.

    browser.close()

Do not add path when you want a purely in-memory result. The browser and context are closed after the capture so their processes do not remain alive.

Asynchronous Python: use await inside asyncio

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

        screenshot_bytes = await page.screenshot()
        # screenshot_bytes is bytes; no image file is created.

        await browser.close()

asyncio.run(main())

Choose the async API when the surrounding application already uses asyncio (for example, an async web framework or worker). A synchronous script is simpler with the sync API; do not call synchronous Playwright operations from an active event loop.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the capture region

Viewport screenshot

The default captures the currently visible viewport. Set the viewport when deterministic dimensions matter:

page = browser.new_page(viewport={"width": 1440, "height": 900})
page.goto("https://example.com")
screenshot_bytes = page.screenshot()

Full scrollable page

Pass full_page=True to capture the full scrollable document rather than only what is visible. Long pages can consume substantial memory, so use a bounded viewport or an element capture when you only need a region.

screenshot_bytes = page.screenshot(full_page=True)

One element

Use a locator’s screenshot() method for a matched element. The [Locator API](https://playwright.dev/python/docs/api/class-locator) states that Playwright scrolls the element into view and waits for actionability.

header_bytes = page.locator("header").screenshot()
card_bytes = page.locator(".product-card").first.screenshot()

If another element covers the target, Playwright does not make the covered content visible for you. A scrollable container capture includes only the content currently represented by that element, not an automatic image of every hidden scroll position. Resolve overlays or scroll the container deliberately before capturing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Format, quality, scale and transparency

Option Use Important constraint
type="png" Lossless default, suitable for text and transparency. quality does not apply to PNG.
type="jpeg" Smaller photographic images. No alpha transparency; documented default quality is 80.
type="webp" Modern compact output. Quality 100 is lossless; lower values are lossy. WebP screenshot support is recorded in the 1.62 release notes.
scale="device" Default device-pixel rendering. High-DPI contexts produce larger images.
scale="css" One output pixel per CSS pixel. Usually reduces byte size on high-DPI captures.
omit_background=True Transparent-capable capture. Does not apply to JPEG.

Example:

webp_bytes = page.screenshot(
    type="webp",
    quality=85,
    scale="css",
)

png_with_alpha = page.screenshot(omit_background=True)

Check the [Page API](https://playwright.dev/python/docs/api/class-page) for the options supported by the Playwright version installed in your project. The [release notes](https://playwright.dev/python/docs/release-notes) are the authoritative place to verify version-specific additions such as WebP support.

Make captures repeatable and safe

Wait for the right state

page.goto() returning means navigation reached the requested load state, not necessarily that an application’s data is rendered. Wait for a meaningful selector, a controlled delay, or an application-specific readiness signal:

page.goto("https://example.com", wait_until="domcontentloaded")
page.locator("main").wait_for(state="visible")

Use networkidle only when it represents a stable state for that site; analytics, polling, and advertisements can keep connections open.

Control animation and dynamic regions

The screenshot API supports animation handling, masking and an injected stylesheet. Disable or freeze moving elements where visual consistency matters, and mask personal or changing regions before bytes leave the process. Test the result for the specific page: hiding animation can change the frame that is captured.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Authenticate without exposing secrets

Create a browser context with the required cookies or headers, and keep credentials out of source control. If a page is protected by a bot challenge or CAPTCHA, automation may be blocked; do not attempt to defeat access controls.

Send the bytes without writing a file

Base64 for JSON

import base64

encoded = base64.b64encode(screenshot_bytes).decode("ascii")
payload = {"mime_type": "image/png", "data": encoded}

HTTP response (Flask example)

from flask import Flask, Response

app = Flask(__name__)

@app.get("/shot")
def shot():
    # Produce screenshot_bytes using a managed browser/context.
    return Response(screenshot_bytes, mimetype="image/png")

For large or frequent captures, stream or upload the bytes rather than retaining many full-page images in one process. A bytes object remains in memory until references to it are released.

Common errors and fixes

  • “Executable doesn’t exist.” Run playwright install chromium in the same environment as the Python package, and ensure the container includes required libraries.
  • Timeout while navigating. Check DNS, proxy and authentication; increase the navigation timeout only after fixing connectivity, and wait for a selector instead of indefinitely waiting for network idle.
  • Locator timeout or strict-mode error. Make the locator specific (for example, .product-card plus .first), and wait for visibility before the screenshot.
  • Blank or incomplete image. Capture after the application’s data-rendered selector appears. Lazy images may require scrolling or an explicit readiness condition.
  • Element is covered. Dismiss the modal or hide the covering locator before capture; Playwright will not reveal an obscured element automatically.
  • Unexpectedly huge files. Use scale="css", JPEG/WebP where appropriate, a smaller viewport, or an element screenshot. Full-page and device-scale captures naturally contain more pixels.
  • Transparency fails. Use PNG or WebP with omit_background=True; JPEG cannot carry an alpha channel.
  • WebP option rejected. Verify the installed Playwright version against the [release notes](https://playwright.dev/python/docs/release-notes) and upgrade if your deployment requires WebP screenshots.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability and cost considerations

Launching a browser for every request adds startup latency. For a service, keep a browser process alive and create isolated contexts or pages per job, then close pages and contexts promptly. Limit concurrency according to available CPU and memory; full-page, high-DPI images are more expensive than viewport captures. Reuse a page only when you can reliably clear cookies, storage and application state between jobs.

Screenshot bytes are encoded before the method returns. If your next component accepts a file-like object, wrap them with io.BytesIO(screenshot_bytes) rather than writing a temporary file. Record the URL, viewport, format and Playwright version with each job when reproducibility matters.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

ScreenshotNeo provides a hosted screenshot API and MCP server. It removes cookie/consent banners, newsletter popups and chat widgets before capture; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, with the result identified by X-Page-Verdict and X-Billed headers. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.

One GET request returns PNG, JPEG, WebP or PDF. The service also supports full-page and element capture, device presets and custom viewports, retina scale, waits, custom CSS/JavaScript, clicks, selector hiding, request/resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data and an OpenAPI specification. Parameter names used by other screenshot APIs are accepted to ease migration.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo documentation for parameters and response handling. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

FAQ

Does omitting path guarantee zero disk I/O?

It prevents Playwright from being asked to save the screenshot file. Your operating system or browser may still use normal temporary resources, but the screenshot result is returned to Python as bytes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I capture an element that is outside the viewport?

Yes. Locator screenshots scroll the target into view first, subject to actionability and obstruction checks.

Which API should a new asyncio application use?

Use playwright.async_api and await browser, navigation and screenshot operations so they cooperate with the application’s event loop.

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.