HTML to Image Conversion in Python with Selenium
Render HTML in a real browser and save it as a PNG with Selenium. Learn setup, viewport and element capture, full-page options, troubleshooting, and an API alternative.
Use Selenium to open HTML in a real browser, wait until the content you need has rendered, then save a screenshot. The basic Python workflow is: install Selenium, create a WebDriver, navigate to a local HTML file or URL, and call save_screenshot(). That method captures the current browser window as a PNG. For full-document screenshots, use a browser-specific API such as Firefox’s documented full-page methods.
1. Install Selenium and prepare a browser
The Selenium Python bindings support Python 3.10 and newer. Install or update the package:
python -m pip install -U selenium
Selenium needs a browser and a matching driver. In modern supported environments, Selenium Manager can handle browser driver setup when you instantiate a WebDriver. If your machine or deployment environment cannot use Selenium Manager, install and configure the browser and driver yourself. Check the current Selenium documentation for supported browsers and setup details, since those can change.
A local script does not need Selenium Server. Remote WebDriver sessions use Selenium Grid. The examples below use Chrome locally and rely on Selenium Manager where available.
2. Convert a local HTML file to PNG
Save the markup to a file, navigate Chrome to its absolute file: URL, and save the browser window screenshot:
from pathlib import Path
from selenium import webdriver
html_path = Path("page.html").resolve()
output_path = Path("output.png").resolve()
if not html_path.is_file():
raise FileNotFoundError(html_path)
driver = webdriver.Chrome()
try:
driver.set_window_size(1440, 1000)
driver.get(html_path.as_uri())
saved = driver.save_screenshot(str(output_path))
if not saved:
raise OSError(f"Could not save screenshot: {output_path}")
finally:
driver.quit()
print(f"Saved {output_path}")
Put this code in capture.py beside page.html, then run python capture.py. The result is written to output.png. Setting the window size controls the browser viewport, not the page’s total document height.
The HTML page can refer to local CSS, images, fonts, and scripts. Keep those assets in locations the page can load. Relative asset URLs resolve from the HTML file’s location; remote assets still require network access.
3. Capture a remote HTML page
For a page already served at a URL, navigate directly to it. Here is a runnable version that checks for the page title before saving:
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
url = "https://example.com"
output_path = Path("remote-page.png").resolve()
driver = webdriver.Chrome()
try:
driver.set_window_size(1440, 1000)
driver.get(url)
WebDriverWait(driver, 15).until(
lambda browser: browser.execute_script("return document.readyState") == "complete"
)
saved = driver.save_screenshot(str(output_path))
if not saved:
raise OSError(f"Could not save screenshot: {output_path}")
finally:
driver.quit()
print(f"Saved {output_path}")
document.readyState == "complete" is a useful baseline, but it does not guarantee that a single-page application, delayed font, image, animation, or API request has finished. Wait for a page-specific ready signal or a meaningful element when the output depends on dynamic content.
4. Choose the capture area
Viewport screenshot
save_screenshot(path) saves what is currently visible in the browser window. Set the window size explicitly before capture to make the viewport predictable. This does not make the image full-page.
Element screenshot
To save a component rather than the whole viewport, locate it and call the element screenshot method:
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
driver = webdriver.Chrome()
try:
driver.set_window_size(1440, 1000)
driver.get("https://example.com")
card = WebDriverWait(driver, 15).until(
lambda browser: browser.find_element(By.CSS_SELECTOR, "main")
)
if not card.screenshot(str(Path("element.png").resolve())):
raise OSError("Could not save element screenshot")
finally:
driver.quit()
Element capture is useful for a chart, card, or preview. The selector must match an element that exists and is visible. The Selenium documentation describes element screenshots in its WebDriver interactions guide.
Full-document screenshot
Full-page support depends on the browser driver. Selenium’s Firefox Python API documents get_full_page_screenshot_as_file(path) and save_full_page_screenshot(path). This example uses the first method:
from pathlib import Path
from selenium import webdriver
output_path = Path("full-page.png").resolve()
driver = webdriver.Firefox()
try:
driver.set_window_size(1440, 1000)
driver.get("https://example.com")
saved = driver.get_full_page_screenshot_as_file(str(output_path))
if not saved:
raise OSError(f"Could not save screenshot: {output_path}")
finally:
driver.quit()
This Firefox-specific method is not a cross-driver guarantee. Check the API for your selected browser and verify the result against pages with long content, sticky headers, or lazy-loaded sections. The Selenium Python API reference documents screenshot and window sizing methods.
5. Make captures consistent
- Set the viewport: choose a fixed width and height with
set_window_size(). Different dimensions can change responsive layouts and line wrapping. - Wait for meaningful content: use an explicit wait for a selector or application-ready condition instead of relying on an arbitrary sleep.
- Account for assets: fonts, images, CSS, and JavaScript must load successfully. Network access, cache state, and local asset paths can affect the render.
- Control the runtime: browser version, operating system fonts, device scale, zoom, and scrollbars can affect dimensions or appearance. Verify these in the environment where captures run.
- Check the save result: Selenium’s file screenshot methods return a boolean. Use an absolute output path and treat
Falseas a failed capture. - Always close the session: put
driver.quit()in afinallyblock so browser processes are cleaned up if navigation or capture fails.
Selenium also exposes screenshot bytes through get_screenshot_as_png(), and base64 screenshot methods for embedding. Use these when the next step needs bytes in memory instead of a saved file; consult the API reference for the exact method signatures.
6. cURL, Python, and Node.js alternatives
Selenium is the Python method for rendering HTML in a browser session. If you need an HTTP call that returns an image without managing a local browser, an image API is another approach. ScreenshotNeo accepts a URL and returns a screenshot; its parameter names used by other screenshot APIs also work. See the ScreenshotNeo API documentation for configuration and response details.
cURL
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
The Python and cURL examples save the returned response body; check the status and response headers in production before treating a response as an image. The supplied Node.js request works in Node versions with built-in fetch; writing its response body to disk depends on your runtime. For standard Node.js, use Buffer.from(await res.arrayBuffer()) with node:fs/promises writeFile.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One request can return PNG, JPEG, WebP, or PDF, with options including full-page capture with lazy images loaded, CSS selector element capture, custom CSS and JavaScript, waits, viewport and device presets, retina scale, and HTML/CSS-to-image. Cookie banners, newsletter popups, and chat widgets are removed before the shot, and each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing; response headers report the page verdict and billing status. AI agents can use its MCP server tools: take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Read the API docs for setup and options. Sign up for 1,000 free screenshots a month, with no card.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| WebDriver cannot start or reports a driver error | Browser installation, driver setup, or Selenium Manager access is unavailable. | Confirm a supported browser is installed and the environment can use Selenium Manager. If not, configure the browser driver manually and check the current Selenium setup guide. |
| The screenshot is blank or missing content | Navigation completed before the app rendered, or assets/API requests failed. | Wait for a page-specific element or ready condition; inspect network access and asset URLs. Do not assume document readiness means app readiness. |
| Output dimensions are wrong | Window size was not set, the page is responsive, or viewport capture was mistaken for full-page capture. | Set an explicit size before capture and use the browser’s documented full-document method when the entire page is needed. |
| File is not created | Relative output path points elsewhere, the directory is missing, or the save method returned false. | Use an absolute path, create the parent directory if needed, and check the boolean return value. |
| Element screenshot fails | The selector matched nothing, the element is hidden, or it has not rendered yet. | Use an explicit wait for the element, verify the selector, and ensure the target is visible. |
| Browser process remains after an exception | The driver was not quit on an error path. | Put capture code inside try and call driver.quit() in finally. |
| Repeated captures vary visually | Fonts, device scale, animations, remote assets, or browser versions differ. | Keep the browser environment and viewport consistent, wait for fonts and content your page depends on, and verify output in the deployment runtime. |
8. Performance, reliability, and cost
A Selenium capture starts or uses a browser session, loads the page and assets, waits for the relevant state, and encodes an image. Keep a session alive when capturing several pages in one controlled job if your application design allows it, and always close it at the end. Avoid fixed long sleeps: they waste time on fast pages and may still be too short on slow ones.
For reliable jobs, set explicit timeouts and waits appropriate to the page, check navigation and save outcomes, and record the URL and failure stage when a capture fails. Full-document images can be large; use viewport or element capture when that is the actual output needed. No universal Selenium-versus-API speed comparison is established by the cited documentation, so measure with your own pages and runtime.
Selenium itself is open-source software; operational cost depends on the machine, browser runtime, and any remote Grid or hosted infrastructure you choose. ScreenshotNeo’s listed plans are Free: 1,000 per month; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan.
9. FAQ
Does Selenium convert raw HTML strings directly to PNG?
The basic workflow captures a rendered browser page. Save the markup as an HTML file and navigate to its file URL, or serve it at a URL, then capture the rendered result.
Can I use Selenium without installing Java?
Yes. A local Selenium Python script does not require the Java Selenium Server. Remote sessions use Selenium Grid.
Does Selenium support full-page screenshots in every browser?
Do not assume so. The Python API documents full-document methods for Firefox; verify support and behavior for the browser driver you use.
Is Playwright another option?
Yes. Playwright’s Python guides document browser automation and saving screenshots, and browsers run headless by default. Choose based on your project’s existing dependencies, browser requirements, and capture needs; the documentation does not establish a general performance winner. See the Playwright Python guide and screenshot guide.


