ScreenshotNeo

BlogHow-to

Capture Webpage Screenshots in Python with Selenium

Use Python Selenium to capture a rendered webpage, wait for dynamic content, save element screenshots, and understand full-page and PDF options.

By the ScreenshotNeo team4 October 20269 min read

Use Selenium WebDriver’s save_screenshot() method to save the current browser view as a PNG. Start a browser, navigate to the page, wait for the content you need, save the screenshot, then close the browser session. For an element, use its screenshot method. Full-page capture support depends on your installed Selenium version and browser.

Save a webpage screenshot with Python Selenium

Install Selenium, then save this as screenshot.py and run it with Python. Selenium Manager can manage a compatible driver in supported setups; if it cannot find or launch a browser, see the troubleshooting section.

python -m pip install selenium
from selenium import webdriver

url = "https://example.com"
driver = webdriver.Chrome()

try:
    driver.get(url)
    driver.save_screenshot("page.png")
finally:
    driver.quit()

save_screenshot() returns a success value and writes the screenshot to the specified path. Check the return value and confirm that the destination directory exists and is writable if your program needs to handle save failures explicitly. The WebDriver command returns image data encoded in Base64 at the WebDriver endpoint; the Python binding’s save method writes it to the file.

from pathlib import Path
from selenium import webdriver

output = Path("screenshots/page.png")
output.parent.mkdir(parents=True, exist_ok=True)

driver = webdriver.Chrome()
try:
    driver.get("https://example.com")
    saved = driver.save_screenshot(str(output))
    if not saved:
        raise RuntimeError(f"Screenshot was not saved: {output}")
finally:
    driver.quit()

For repeatable results, set the viewport before navigating or capturing. The ordinary screenshot captures the current browsing context at its current viewport; it does not automatically stitch the full document into one image.

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--window-size=1440,1000")

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

Wait for the content you need

Navigation completing does not guarantee that a JavaScript application has finished fetching and rendering the part you want. Prefer an explicit wait for a meaningful element or state over a fixed sleep.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

url = "https://example.com"
driver = webdriver.Chrome()

try:
    driver.get(url)
    WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "main h1"))
    )
    driver.save_screenshot("page.png")
finally:
    driver.quit()

Choose a condition that represents screenshot readiness: a heading becoming visible, a loading indicator disappearing, a chart appearing, or a particular element reaching its expected text. A wait for an element to exist in the DOM is not always enough if it is hidden or still changing.

Choose a page-load strategy

Selenium 4 browser options support three page-load strategies. The default is usually right for ordinary pages; adjust it when the page’s loading behavior or your automation needs call for it. Even with the default, add an explicit wait for application-specific content when needed.

Strategy When WebDriver proceeds Use it when
normal After resources load and the load event fires. You want the usual navigation wait.
eager After DOM access is ready and DOMContentLoaded fires; other resources may still load. You plan to wait explicitly for the content that matters.
none Without waiting for page readiness during navigation. You will manage readiness entirely with explicit waits.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.page_load_strategy = "eager"

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    WebDriverWait(driver, 20).until(
        lambda d: d.execute_script("return document.readyState") == "complete"
    )
    # For a single-page application, also wait for a page-specific condition.
    driver.save_screenshot("page.png")
finally:
    driver.quit()

document.readyState == "complete" is not proof that a single-page application has finished later network requests or rendering. The Selenium documentation calls out this limitation. Wait for the specific content your screenshot requires. See the Selenium documentation on driver options and page-load strategies.

Capture an element instead of the viewport

Use an element screenshot when you only need one card, chart, table, or other located component. Selenium captures the element itself, avoiding unrelated viewport content.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

url = "https://example.com"
driver = webdriver.Chrome()

try:
    driver.get(url)
    chart = WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "#chart"))
    )
    chart.screenshot("chart.png")
finally:
    driver.quit()

Make sure the target is visible and in the expected state before capturing it. If the element is outside the viewport, Selenium’s element screenshot behavior can involve scrolling it into view; sticky headers, animations, overlays, or clipping can affect the result. If the element is covered, wait for or dismiss the overlay using an authorized site interaction before taking the screenshot.

How to capture the full page

Full-page screenshot methods vary by Selenium binding, browser, driver, and version. The Python API index lists save_full_page_screenshot(), but do not assume it is available or behaves identically in every environment. Check the method in your installed Python binding and consult browser-specific documentation before relying on it.

from selenium import webdriver

url = "https://example.com"
driver = webdriver.Firefox()

try:
    driver.get(url)
    full_page_method = getattr(driver, "save_full_page_screenshot", None)
    if full_page_method is None:
        raise RuntimeError(
            "This Selenium driver does not expose save_full_page_screenshot()"
        )
    full_page_method("full-page.png")
finally:
    driver.quit()

This example checks for method availability and fails clearly rather than silently substituting a viewport capture. The Java API documentation describes its full-page interface as beta and identifies FirefoxDriver as an implementation; that is not a promise of matching support in Python. Verify the Python API index and your actual browser and driver versions. If full-page capture is a hard requirement, validate the output on representative pages, including pages with lazy-loaded images, sticky elements, and long content.

Save a PDF when you need a document

If the deliverable should be a printable document rather than a raster image, Selenium’s print_page() method produces PDF output. The Selenium documentation says this feature currently requires Chromium in headless mode. A PDF uses print rendering, so it may not look exactly like a browser screenshot.

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    pdf_data = driver.print_page()
    with open("page.pdf", "wb") as pdf_file:
        pdf_file.write(pdf_data.encode("ascii"))
finally:
    driver.quit()

See Selenium’s print page documentation for current requirements and API details. Use save_screenshot() for an image; use print_page() when you need PDF output.

Run headless or set a predictable browser size

Headless mode runs the browser without a visible window, which is useful on servers and in automation jobs. Specify a viewport so screenshots have consistent dimensions. Headless rendering can still vary with browser version, installed fonts, device scale, and operating system.

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--window-size=1440,1000")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "main"))
    )
    driver.save_screenshot("headless-page.png")
finally:
    driver.quit()

For reproducibility, keep the browser version, viewport, page state, locale, and fonts consistent between runs. If pixel-level comparison matters, also control animations and dynamic content at the application or test level.

Or skip the browser setup

ScreenshotNeo provides a screenshot API: one GET request returns an image or PDF. It can be useful when you do not want to manage a browser and driver for a capture job. See the ScreenshotNeo API documentation for request options.

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

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
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);

In Node.js environments without Bun, write the response bytes with the runtime’s file API, for example await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()))) inside an async function.

  • Cookie banners are accepted and removed before capture; newsletter popups and chat widgets are removed too, and each cleanup step can be turned off.
  • Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.

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

Troubleshooting

Symptom Likely cause What to do
Chrome or ChromeDriver will not start Browser and driver versions are incompatible, or a browser is unavailable. Keep Chrome and ChromeDriver major versions aligned. Selenium Manager can download a browser version when none is found locally in supported setups. Review the Selenium Chrome setup guide.
Screenshot is blank or missing dynamic content Capture happened before the application rendered the relevant content. Add an explicit wait for a visible page-specific element or expected state. Navigation completion alone may not be enough.
Wait times out The locator is wrong, the element never appears, or the page did not reach the expected state. Inspect the live DOM and locator, check whether the element is inside a frame, and confirm the page can load from the automation environment. Set a realistic timeout and report the current URL and page state on failure.
Cannot find save_full_page_screenshot The installed binding or driver does not provide that method. Check your Selenium Python API and browser-specific support. Do not treat a normal screenshot as full-page output.
Output file is missing or unreadable The destination directory may not exist or be writable, or saving returned failure. Create the parent directory, use an absolute path when debugging, check the method’s return value, and verify the process has write permission.
Screenshot differs between runs Viewport, browser version, fonts, animation, ads, or page data changed. Pin the browser environment where possible, set a fixed viewport, wait for stable content, and disable or account for animation and other dynamic page elements.
PDF printing fails The browser is not Chromium or is not running headless. Use Chromium in headless mode and consult Selenium’s current print-page requirements.

Performance, reliability, and cost

A Selenium screenshot requires starting and maintaining a browser session. Reusing one session for multiple pages can avoid repeated browser startup, but isolate page state when captures must be independent and always close the driver in a finally block. Browser startup, navigation, application-specific waits, and large full-page images are common contributors to elapsed time and resource use.

Use explicit waits with bounded timeouts so a broken page does not stall a job indefinitely. For batch work, record the URL, browser and driver versions, viewport, wait condition, output path, and exception for each capture. Retry transient navigation failures selectively; repeated retries cannot fix a persistent locator or compatibility error.

Selenium itself is browser automation software; the cost of running it depends on where you run the browser and the infrastructure you choose. ScreenshotNeo offers a managed API alternative with 1,000 free screenshots monthly and paid tiers from $5 for 3,000. Its listed plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is on every plan. For either approach, account for retries, output storage, and the operational effort of maintaining consistent browser environments.

Frequently asked questions

Does Selenium save screenshots as PNG?

save_screenshot() writes a PNG screenshot to the path you provide. Use a PNG filename for clarity.

Does a successful screenshot call mean the page finished rendering?

No. It means the screenshot command ran; dynamic application content may still be loading. Wait for the content that matters to your capture.

Can I capture just one element?

Yes. Locate the element, wait until it is visible, then call its screenshot() method with an output path.

Can Selenium take a full-page screenshot?

Some binding and browser combinations expose full-page support. Check your installed Python API and browser-specific implementation rather than assuming it is universal.

Should I use a screenshot or print to PDF?

Use a screenshot for a raster image of the rendered browser view. Use print_page() for a PDF document, keeping in mind that print layout can differ from screen rendering.