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.

Use Playwright’s Python API to render HTML in a browser and save the result as a PNG. For HTML you already have in Python, load it with page.set_content(); for a live webpage, use page.goto(). Then call page.screenshot(path="output.png"). Choose a viewport screenshot for the visible screen, or set full_page=True to capture the full page.

Convert HTML to PNG with Playwright

Playwright is a good fit when the output needs to reflect browser layout, CSS, or JavaScript. Its Python API can launch Chromium, Firefox, or WebKit; the example below uses Chromium. Playwright runs browsers headlessly by default, so a visible desktop browser window is not required.

Prepare Playwright

Install the Playwright Python package and the browser runtime you intend to use by following the current official Playwright installation instructions. Installation requirements can depend on your operating system and the selected browser, so check those instructions for the environment where the script will run rather than assuming the Python package alone is sufficient.

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

Use the synchronous API for a standalone script or the asynchronous API if your application already uses asyncio. The examples here use the synchronous API first.

Render HTML supplied by your Python program

from playwright.sync_api import sync_playwright

html = """


  
  


  

Hello, PNG

This image was rendered from HTML in Python.

""" with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page(viewport={"width": 1280, "height": 800}) page.set_content(html) page.screenshot(path="output.png", full_page=True) browser.close()

After it finishes, output.png is saved in the script’s current working directory. Set the viewport deliberately if the layout depends on screen width: responsive CSS can produce different line breaks and element positions at different dimensions.

Capture a live webpage

For a page available at a URL, navigate to it instead of supplying a string of HTML. A successful navigation does not necessarily mean that every image or application-specific widget is ready, so wait for the content your capture depends on before taking the screenshot.

from playwright.sync_api import sync_playwright

url = "https://example.com"

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1280, "height": 800})
    page.goto(url)
    page.screenshot(path="page.png", full_page=True)
    browser.close()

Replace the example URL with the page you are authorized to access. For a page that requires a particular load state or application content, use the relevant Playwright navigation and waiting APIs before capture instead of relying on an arbitrary fixed delay.

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

Choose what the PNG should show

Viewport or whole page

Without full_page=True, the screenshot represents the current viewport. This is usually right for a browser-window preview or a fixed-size image. Set full_page=True when the output should include the page beyond the visible screen; Playwright captures the full page rather than only the initial viewport.

A full-page image can be very tall. If a downstream system imposes image-dimension or memory limits, consider whether a viewport capture or several smaller captures better fit that system. No universal maximum image size or performance comparison is established, so the appropriate choice depends on your page and runtime.

One element

To capture a specific element, take a screenshot of a Playwright locator rather than the entire page:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.set_content('<article><h1>Card</h1><p>Only this element is captured.</p></article>')
    page.locator("article").screenshot(path="article.png")
    browser.close()

A locator screenshot captures the element’s currently visible content. If the element itself is scrollable, that does not necessarily include everything hidden inside its scroll area; scroll or otherwise prepare the element if the hidden content must appear.

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

Save bytes instead of a file

If another part of your Python program will process or transmit the image, omit the path argument. The screenshot call returns image bytes:

png_bytes = page.screenshot(full_page=True)

You can then pass png_bytes to code that accepts bytes, or write it to a file yourself. To make the page background transparent, Playwright documents the omit_background=True screenshot option; transparency applies to PNG, not JPEG.

Make captures more repeatable

Dynamic pages may still be loading fonts, images, or application data when the first view appears. Decide what “ready” means for your page, and wait for that condition before taking the shot. For example, wait for a meaningful selector that appears only after the content is rendered. A delay can be useful for a known animation or deferred update, but a fixed delay alone does not prove that a page is ready.

Control animation and timing

Playwright provides screenshot options for handling animations, which can help make repeated captures less sensitive to an element being at a different animation frame. Use the screenshot options appropriate to the effect and desired output; disabling or fast-forwarding an animation changes what the image represents. The documented default screenshot timeout is 30 seconds. If capture work can legitimately take longer, set an appropriate timeout for the operation and investigate why rendering takes that long rather than increasing it blindly.

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

Use the asynchronous API when needed

In an asyncio-based application, use Playwright’s asynchronous Python interface and await each browser operation. The structure is otherwise similar:

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(viewport={"width": 1280, "height": 800})
        await page.set_content("<h1>Hello</h1>")
        await page.screenshot(path="output.png", full_page=True)
        await browser.close()

asyncio.run(main())

Do not mix synchronous Playwright calls into an event loop that already owns the application’s asynchronous work; choose one interface for the workflow.

Playwright or a document renderer?

Use a browser automation workflow when browser behavior, JavaScript, target-browser layout, or a viewport/full-page/element capture matters. Playwright’s documented Python browser launch APIs cover Chromium, Firefox, and WebKit, so you can choose the browser engine relevant to the page.

WeasyPrint may be worth considering for document-like rendering when browser automation is unnecessary. Its version 52.5 tutorial describes writing PNG output to a file or in-memory bytes, but that reference is old. It does not establish the current WeasyPrint API or release behavior; verify the current documentation and release notes before building a new workflow around PNG output. No formal performance benchmark between WeasyPrint and Playwright is available, and the two are not interchangeable for every page.

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

Or skip the browser setup

If your HTML is already served at a URL, ScreenshotNeo can return a screenshot through one GET request. This is a URL-based screenshot API, so it is not a direct replacement for page.set_content() when your markup exists only as a local Python string.

import requests

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

See the ScreenshotNeo API documentation for request details. ScreenshotNeo removes cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are not billed. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for ScreenshotNeo’s free plan.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

The browser does not launch

Check that the Playwright package and the browser runtime are installed for the same environment in which the script runs, and follow the current installation guidance for your operating system. A browser installed in a different virtual environment or machine will not necessarily be available to the script.

The PNG is blank or missing page content

Confirm that navigation or set_content() completed, then wait for a page-specific selector or other condition that indicates the required content is present. If the content depends on JavaScript, check that it executes without an application error. Do not treat a longer fixed sleep as a guaranteed fix.

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

Images or fonts are absent

Check that referenced assets can load from the rendering environment and that capture occurs after the page reaches the state your output requires. A local HTML file or a string of markup may refer to relative assets that are not available from its current page context; provide accessible asset URLs or use an appropriate base URL for the content.

The capture times out

The screenshot API’s documented default timeout is 30 seconds. Identify whether the delay comes from navigation, the readiness condition, or screenshot rendering, then adjust the relevant wait or timeout if the page legitimately needs more time. A timeout is a failed capture, not evidence that a PNG was produced.

The element image is clipped

Check whether the selected locator is the element you intended and whether its content is inside a scrollable region. Locator screenshots do not necessarily expand an element’s own inner scroll area; capture the relevant state or use a whole-page capture if that better matches the requirement.

The result changes between runs

Fix the viewport and make readiness criteria explicit. Account for animations and dynamic content, and avoid assuming a fixed wait produces identical results across pages or environments. If you need browser-specific fidelity, use the same Playwright browser engine for each run.

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.

Performance, reliability, and cost considerations

A local Playwright workflow gives you control over the browser engine, viewport, page readiness, and capture target, but your script must manage its browser runtime and page lifecycle. Close the browser after capture, as in the examples, and make waits correspond to actual page conditions. The supplied API documentation establishes a 30-second default screenshot timeout, not a general guarantee about total end-to-end runtime or page availability.

For repeated work, reuse a browser process where appropriate rather than launching one for every single page, while creating page contexts that isolate the state you need. Measure your own pages and environment: no comparative speed, memory, or reliability benchmarks are established here. If you instead use a hosted screenshot API, review its billing and failure semantics for your workload; ScreenshotNeo states that only clean shots are billed and identifies verdict and billing information in response headers.

Frequently Asked Questions

Can I convert HTML that is only stored in a Python string?

Yes. Pass the markup to Playwright’s page.set_content() and take a page screenshot; a URL-based screenshot API is not a direct substitute for local, unserved markup.

Can Playwright save the screenshot without writing a file?

Yes. Call page.screenshot() without path to receive PNG bytes for use elsewhere in your program.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Does WeasyPrint currently support PNG output?

The cited version 52.5 tutorial documents PNG output, but that old reference does not establish the current API. Check current WeasyPrint documentation and release notes before relying on it.

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.