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.

To save HTML as a PNG in Python, render it in a real browser and use the browser’s screenshot API. Playwright is a direct option: open the page, then call page.screenshot(path="page.png"). Add full_page=True to capture the full scrollable document, or target a specific element with a locator. This works for web pages and, with a file URL, local HTML.

Use Playwright to render HTML and save a PNG

A browser engine applies the page’s HTML, CSS, fonts, and JavaScript before capturing the rendered result. That matters because an HTML file is a description of a page, not an image; converting its text directly will not reproduce a browser layout.

The example below opens a web page in Chromium, sets a predictable viewport, waits for network activity to settle, then saves a full-page PNG:

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.
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1440, "height": 900})
    page.goto("https://example.com", wait_until="networkidle")
    page.screenshot(path="page.png", full_page=True)
    browser.close()

Change the URL and output filename for your own page. The screenshot type is inferred from the filename extension: .png selects PNG. Playwright’s Python screenshot API also supports JPEG and WebP. PNG is lossless, so PNG quality settings do not apply.

Install Playwright and its browser

For a new Python environment, install the Python package and then install Chromium for Playwright:

python -m pip install playwright
python -m playwright install chromium

Run these commands in the same environment that will run the script. The first installs Playwright’s Python API; the second installs the browser runtime it launches. If your environment already has the package and browser, you do not need to repeat the installation.

Save a viewport screenshot

By default, page.screenshot(path="viewport.png") captures the visible browser viewport. The viewport dimensions supplied to new_page therefore affect the resulting image. Choose dimensions that fit the layout you need to inspect or publish.

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

Save the full page

Use full_page=True to capture the full scrollable page rather than only what is visible in the viewport:

page.screenshot(path="full.png", full_page=True)

Full-page output can be extremely tall on long documents. If the image will be difficult to view, share, or process, capture a relevant section or element instead of producing one document-sized PNG.

Capture local HTML instead of a website

For an HTML file on disk, navigate to its file URL. Resolving the path first ensures it is absolute, which avoids ambiguity about the script’s current working directory:

from pathlib import Path
from playwright.sync_api import sync_playwright

html_file = Path("page.html").resolve()
file_url = html_file.as_uri()

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

Keep any local images, stylesheets, and other files the HTML depends on accessible at the paths referenced by the document. A screenshot can only show resources the browser can load. If the page depends on remote resources, those resources must also be reachable from the machine running the browser.

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

Capture a particular HTML element

When the whole page is not the desired output, use a locator to screenshot one element. For example, this captures an element with the CSS class invoice:

invoice = page.locator(".invoice")
invoice.screenshot(path="invoice.png", animations="disabled")

The locator screenshot is useful for cards, charts, receipts, and other bounded components. The element must exist and be visible when the capture runs. Disabling animations can make output more repeatable when an animation would otherwise change the element during capture.

Choose when the page is ready to capture

Waiting is part of screenshot correctness. A capture taken before the content appears can produce a blank or incomplete image even when the browser loaded the URL successfully.

Wait for network activity to settle

The example uses wait_until="networkidle" with page.goto. This is a practical choice for pages that settle after loading, but some sites keep network connections active or continually fetch data. In those cases, waiting for a specific visible element is more targeted.

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

Wait for a selector or known page state

If the important content appears in a particular element, wait for it before capture:

page.goto("https://example.com", wait_until="domcontentloaded")
page.locator(".report-ready").wait_for(state="visible")
page.screenshot(path="report.png", full_page=True)

Replace .report-ready with a selector that represents the content you need. You can also wait for a page state your application controls. Prefer a meaningful condition over an arbitrary sleep: a fixed delay may be too short on a slow run and unnecessarily long on a fast one.

Make rendering conditions repeatable

  • Set the viewport explicitly so responsive layout does not vary with the machine’s default window size.
  • Make sure fonts and network resources have loaded when their appearance matters.
  • Use a readiness condition tied to the content, rather than assuming the page is ready immediately after navigation.
  • Disable animations for an element screenshot when motion makes the result inconsistent.

Save the screenshot as bytes instead of a file

If you omit the path, page.screenshot() returns PNG bytes. You can write them to a file yourself or pass them to another image-processing step:

png_bytes = page.screenshot(full_page=True)
with open("page.png", "wb") as image_file:
    image_file.write(png_bytes)

This is useful when a pipeline needs image data in memory rather than a screenshot saved directly by Playwright. Choose either the path-based form or the bytes form according to what the next step in your program expects.

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

Use Selenium if it is already your project standard

Selenium’s Python WebDriver can save the current browser window as a PNG, either to a file or as bytes:

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    driver.save_screenshot("page.png")
finally:
    driver.quit()

driver.save_screenshot("page.png") and driver.get_screenshot_as_file("page.png") save the current window to a PNG file. To work with raw data, use driver.get_screenshot_as_png(). Selenium’s documented core screenshot methods focus on the current window; they do not offer the same direct full_page=True option described for Playwright. Full-page capture with Selenium may require browser-specific methods or stitching.

Choose Selenium when it is already the project’s browser-automation standard and a current-window capture meets the need. For a direct full-page or locator screenshot, Playwright exposes those options in its page and locator screenshot APIs.

Troubleshoot missing, blank, or incorrect output

Symptom Likely cause What to try
The script cannot launch Chromium The browser runtime is missing from the Python environment or machine. Install Playwright’s browser with python -m playwright install chromium in the environment used to run the script.
The PNG is blank or missing page content The screenshot ran before client-rendered or delayed content appeared. Wait for a relevant selector or known page state before capturing.
The layout differs between runs or machines The viewport, fonts, resources, or animation state differs. Set the viewport explicitly, ensure required resources are available, and disable animations for locator screenshots when appropriate.
A local image or stylesheet is absent The browser cannot resolve the resource path or reach its source. Check that local dependencies are present at the paths referenced by the HTML and that required remote resources are reachable.
The full-page PNG is unwieldy The document is much taller than the viewport. Capture a specific element or divide the page into sections instead.
Selenium saves only the visible window The core Selenium screenshot methods capture the current window. Use a browser-specific full-page technique or stitching, or use Playwright’s documented full-page capture option.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you need a screenshot without installing and managing a browser runtime in your Python project, ScreenshotNeo provides a website screenshot API. Its API accepts a URL in one GET request and can return PNG, JPEG, WebP, or PDF. The Python example below saves the response body as a PNG; see the ScreenshotNeo API documentation for request options and response details.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.png", "wb").write(r.content)

ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

Performance, reliability, and cost considerations

With a local Playwright or Selenium workflow, the capture runs on the machine or environment where your script executes. The output depends on the page reaching the state you chose to wait for, and on its browser being able to load the fonts, styles, scripts, and images that shape the rendering. There is no relevant published performance figure in the sources for these screenshot APIs, so treat capture time as dependent on the page and runtime rather than relying on an assumed fixed duration.

For long pages, full-page images consume more storage and can be cumbersome to process than viewport or element captures. If you only need a component, narrowing the capture can produce a more useful artifact. For a service-based workflow, check the API response headers and plan allowance; ScreenshotNeo identifies whether a capture was billed in its X-Billed response header.

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

Frequently Asked Questions

Can I save an HTML string directly as a PNG without opening a browser?

A browser-rendering engine is needed if the output should reflect browser layout, CSS, and JavaScript. Load the HTML in a browser page, then capture the rendered page or element.

Does a PNG screenshot preserve selectable text?

No. A PNG is a raster image, not an HTML document or text-bearing PDF. Keep the source HTML separately if you need searchable or editable content.

Can I use the screenshot bytes without writing a temporary file?

Yes. Playwright returns bytes from page.screenshot() when no path is supplied; those bytes can be passed directly to another part of your Python pipeline.

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.

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.