ScreenshotNeo

BlogHow-to

Take a Screenshot of a WebElement in Selenium Python and Save It

Capture one Selenium WebElement as a PNG, handle save failures, use in-memory bytes, and troubleshoot the most common issues.

By the ScreenshotNeo team30 September 20263 min read

Take a Screenshot of a WebElement in Selenium Python and Save It

Use Selenium Python’s WebElement.screenshot() method after locating the element:

element.screenshot("/absolute/path/element.png")

The method writes a PNG file and returns True when the save succeeds. It returns False when writing raises an OSError. Use a full, writable path and a filename ending in .png. The official Selenium Python WebElement API documents this behavior.

Complete runnable example

from selenium import webdriver
from selenium.webdriver.common.by import By

url = "https://example.com"
output_path = "/tmp/example-heading.png"

driver = webdriver.Chrome()
try:
    driver.get(url)
    element = driver.find_element(By.CSS_SELECTOR, "h1")
    saved = element.screenshot(output_path)
    if not saved:
        raise OSError(f"Could not save element screenshot to {output_path}")
    print(f"Saved screenshot to {output_path}")
finally:
    driver.quit()

Install Selenium first if it is not already available:

python -m pip install selenium

The browser and WebDriver must also be available to your Selenium setup. The example uses Chrome, but the Python API call is the same when your configured driver is another supported browser.

How the capture works

  1. Create a WebDriver instance.
  2. Navigate with driver.get().
  3. Locate the target with find_element().
  4. Call element.screenshot(path).
  5. Check the Boolean result.
  6. Quit the driver in a finally block.

The screenshot covers the selected element, rather than the entire browser window. The element must exist in the current page and be located with a selector that matches the rendered DOM.

Selenium locates one element and writes its rendered bounds as a PNG.
Selenium locates one element and writes its rendered bounds as a PNG.

Choosing a reliable selector

Prefer stable attributes that are intended for automation:

# ID
By.ID, "pricing-card"

# Data attribute
By.CSS_SELECTOR, "[data-testid='hero-title']"

# Semantic selector
By.CSS_SELECTOR, "article h1"

# XPath when CSS is insufficient
By.XPATH, "//section[@aria-label='Results']//h2"

Avoid selectors based on generated class names or positions such as div:nth-child(3) when the page can change. If more than one element matches, use find_elements() and select deliberately, or narrow the selector.

Wait until the element is ready

Pages that render content with JavaScript may expose the element before its final content or size is ready. Use an explicit wait:

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

 driver = webdriver.Chrome()
try:
    driver.get("https://example.com")
    element = WebDriverWait(driver, 20).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, "h1"))
    )
    if not element.screenshot("/tmp/heading.png"):
        raise OSError("Screenshot save failed")
finally:
    driver.quit()

Remove the accidental leading space before driver if copying this into a Python file; top-level indentation is invalid. For a page that updates after becoming visible, wait for a specific text, attribute, or application state that represents the final version.

Save PNG data without writing immediately

Use screenshot_as_png when you need bytes for an upload, image processor, object store, or test assertion:

png_bytes = element.screenshot_as_png
with open("/tmp/element.png", "wb") as image_file:
    image_file.write(png_bytes)

For a base64 representation, use:

png_base64 = element.screenshot_as_base64

These properties capture the same element but let your code control storage and transport.

Element screenshot versus browser screenshot

Need API Result
One WebElement element.screenshot(path) Writes that element as PNG and returns a Boolean
One element in memory element.screenshot_as_png PNG bytes
One element as text-safe data element.screenshot_as_base64 Base64 string
Current browser window driver.save_screenshot(path) Window screenshot, not an element crop
Current browser window (alternative) driver.get_screenshot_as_file(path) Window screenshot saved to a file

Selenium’s Python WebDriver API documents the window-level methods. Choose the narrowest scope that matches the output you need.

Handling save paths and failures

  • Create the parent directory before saving.
  • Use a path your process can write.
  • Use a .png extension because the output is PNG.
  • Check the returned Boolean instead of assuming success.
  • Catch filesystem errors around your own directory and permission checks.
from pathlib import Path

output = Path("artifacts/element.png")
output.parent.mkdir(parents=True, exist_ok=True)

saved = element.screenshot(str(output))
if not saved:
    raise OSError(f"Selenium could not write {output}")
if not output.is_file() or output.stat().st_size == 0:
    raise OSError(f"Screenshot file is missing or empty: {output}")

The API warns when the filename does not end in .png. Do not rename the file to a different image format without converting the bytes with an image library.

Common errors and fixes

NoSuchElementException

Cause: the selector does not match the current DOM, the page has not loaded the element, or the element is inside a frame.

Fix: verify the selector, wait for visibility, and switch into the correct iframe before locating it:

driver.switch_to.frame(driver.find_element(By.CSS_SELECTOR, "iframe"))
element = WebDriverWait(driver, 20).until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "h1"))
)

StaleElementReferenceException

Cause: JavaScript replaced the node after you located it.

Fix: wait for the update to finish, then locate the element again immediately before taking the screenshot.

ElementNotInteractableException or an empty-looking image

Cause: the element is hidden, has no rendered size, is covered by a state change, or its content has not finished rendering.

Fix: wait for visibility and, when appropriate, scroll it into view:

driver.execute_script(
    "arguments[0].scrollIntoView({block: 'center', inline: 'nearest'});",
    element,
)

False returned from screenshot()

Cause: Selenium caught an OSError while writing.

Fix: check that the parent directory exists, the process has write permission, the path is valid for the operating system, and the destination is not a directory.

Permission denied or read-only filesystem

Cause: the execution environment blocks writes to the chosen location.

Fix: write to an application-owned temporary or artifacts directory and pass its absolute path.

Only part of a component appears

Cause: the selected WebElement is smaller than the visual component, or the component uses overflow clipping.

Fix: select the outer container that defines the desired bounds. If you need the whole page, use the WebDriver window screenshot API or a full-page capture tool.

Capturing multiple elements

from pathlib import Path
from selenium.webdriver.common.by import By

output_dir = Path("artifacts/cards")
output_dir.mkdir(parents=True, exist_ok=True)

cards = driver.find_elements(By.CSS_SELECTOR, "article.card")
for index, card in enumerate(cards, start=1):
    path = output_dir / f"card-{index}.png"
    if not card.screenshot(str(path)):
        raise OSError(f"Could not save {path}")

Re-locate elements when the page rerenders between captures. For long lists, process items in batches so browser memory and disk usage remain predictable.

Performance and reliability notes

  • Element screenshots are usually cheaper than stitching a full-page image because the captured region is smaller, but page load and rendering still dominate total time.
  • Use explicit waits targeted to the required state instead of a large fixed sleep.
  • Keep the browser session alive when capturing several elements from one page; start a new session only when isolation is required.
  • Use deterministic viewport, zoom, fonts, timezone, and test data when comparing screenshots.
  • Write to local storage first, then upload or process the file. This makes a filesystem failure distinct from a browser failure.
  • Always call quit() in finally so failed captures do not leave browser processes running.

Selenium’s API documentation does not establish a browser-by-browser support matrix for element screenshots. Validate the exact browser and driver versions used by your deployment.

Or skip the browser setup

ScreenshotNeo provides a website screenshot API when you want a rendered page image without managing Selenium, browsers, drivers, waits, and file paths. See the ScreenshotNeo documentation for all 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)
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}`);

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing state. It also offers an MCP server for AI agents, including Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf tools. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Does element.screenshot() save JPEG or WebP?

No. Selenium’s WebElement screenshot API writes PNG data. Convert the bytes separately if another format is required.

A capture service can remove common overlays before rendering the final image.
A capture service can remove common overlays before rendering the final image.

Can I return the image from an API endpoint?

Yes. Read element.screenshot_as_png and return those bytes with an image/png content type.

Should I use a full path?

Yes. A full, writable path avoids ambiguity about the process working directory and follows the API guidance.

What if I need the whole page?

Use a full-page capture approach or a service designed for full-page screenshots. element.screenshot() is scoped to one WebElement.