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 Selenium’s WebElement.screenshot() when the area you need is one DOM element. For a free-form rectangle that crosses several elements, take a current-window PNG with driver.get_screenshot_as_png() and crop it with Pillow. The first approach is more reliable because Selenium finds and renders the element for you; the second is more flexible but requires screenshot-space coordinates that match your browser’s scale and scroll state.

Choose the capture method first

What you need Recommended method Trade-off
One card, article, chart, or other DOM element element.screenshot("region.png") or element.screenshot_as_png Direct and avoids manual crop coordinates, but limited to that element’s rendered bounds.
A rectangle spanning multiple elements or not represented by one node driver.get_screenshot_as_png(), then Pillow crop() Flexible, but you must calculate and verify coordinates in the returned bitmap.
A PNG file of the current browser window driver.save_screenshot(path) or get_screenshot_as_file(path) Simple file output; it captures the current window rather than promising a universal full-document image.
Image bytes for later processing or upload driver.get_screenshot_as_png() or element.screenshot_as_png Keeps the image in memory so your code can crop, inspect, or store it yourself.

The Python API pages for Selenium 4.49.0 document these current-window and element methods. The examples below use Selenium 4-style Python code and PNG output.

Prepare a stable Selenium session

Install Selenium and a browser driver that matches your chosen browser, then wait for the page state you actually need. A screenshot taken while a cookie dialog, lazy image, animation, or late network request is still changing can be technically successful but visually wrong.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
python -m pip install selenium pillow

The following setup uses Chrome. Replace the driver creation with Firefox or another supported browser if required by your environment.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
# options.add_argument("--headless=new")  # enable on a server without a display
options.add_argument("--window-size=1440,1000")
driver = webdriver.Chrome(options=options)

try:
    driver.get("https://example.com")
    # capture code goes here
finally:
    driver.quit()

Set the window size before measuring coordinates. If the page has a responsive layout, changing it later can move the target. For dynamic pages, add an explicit wait for a target element or a meaningful state instead of relying only on a fixed sleep.

Capture one DOM element directly

When the requested part corresponds to one element, locate that element and call its screenshot method. This is the shortest and usually the least error-prone solution.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--window-size=1440,1000")
driver = webdriver.Chrome(options=options)

try:
    driver.get("https://example.com/news")
    region = driver.find_element(By.CSS_SELECTOR, "article .target")
    region.screenshot("region.png")
finally:
    driver.quit()

WebElement.screenshot(path) writes a PNG file. If you need to send the image to another service, inspect it, or crop it again, use the bytes property instead:

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.
from pathlib import Path

png_bytes = region.screenshot_as_png
Path("region.png").write_bytes(png_bytes)

Use a precise, stable locator

Prefer a semantic identifier or a stable class over a long chain of positional selectors. For example, #pricing-card is less fragile than a selector depending on several nested div elements. If multiple nodes match, find_element returns the first one; verify that this is intentional or use a more specific locator.

Handle elements below the fold

Scroll the target into view before capturing it when it is not visible. Selenium’s element location helper documents this behavior, but scrolling can trigger lazy loading, sticky headers, or layout changes. Capture only after the page settles:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 20)
region = wait.until(EC.visibility_of_element_located(
    (By.CSS_SELECTOR, "article .target")
))
driver.execute_script(
    "arguments[0].scrollIntoView({block: 'center', inline: 'nearest'});",
    region,
)
region.screenshot("region.png")

Measure or locate after scrolling, not before. A sticky banner, image decode, responsive reflow, or browser zoom can change the element’s position between those operations.

Capture an arbitrary rectangle and crop it

Selenium does not provide a documented, cross-browser method for “take pixels from this arbitrary rectangle.” Instead, capture the current window as PNG bytes and let an image library crop the bitmap.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from io import BytesIO
from PIL import Image

png = driver.get_screenshot_as_png()
image = Image.open(BytesIO(png))

# Coordinates are (left, upper, right, lower) in screenshot pixels.
left, top, right, bottom = 120, 180, 1120, 760
if not (0 <= left < right <= image.width and 0 <= top < bottom <= image.height):
    raise ValueError(f"Crop box is outside {image.size}: {(left, top, right, bottom)}")

region = image.crop((left, top, right, bottom))
region.save("region.png")

driver.get_screenshot_as_png() returns bytes for the current window. Pillow’s crop operation is post-processing, not a Selenium capture API. Use driver.save_screenshot("window.png") instead when you only need the un-cropped current-window file.

Build a crop from an element’s rectangle

For a rectangle aligned to an element, Selenium exposes geometry through element.rect. Scroll first, obtain the rectangle afterward, and compare the resulting crop against the saved screenshot in the browser and driver combination you deploy.

from io import BytesIO
from PIL import Image

region = driver.find_element(By.CSS_SELECTOR, "article .target")
driver.execute_script(
    "arguments[0].scrollIntoView({block: 'center', inline: 'nearest'});",
    region,
)

png = driver.get_screenshot_as_png()
image = Image.open(BytesIO(png))
rect = region.rect

# This is a starting conversion for a viewport-relative layout.
# Verify alignment locally for your browser, zoom, and device scale.
box = (int(rect["x"]), int(rect["y"]),
       int(rect["x"] + rect["width"]),
       int(rect["y"] + rect["height"]))
image.crop(box).save("region.png")

Do not treat that conversion as universal. CSS coordinates and screenshot bitmap pixels can differ with device-pixel ratio, browser zoom, window chrome, scroll offsets, and driver behavior. The official references document geometry and scrolling, but do not establish one cross-browser coordinate formula. If the crop is shifted, inspect the actual PNG dimensions, keep the viewport unchanged, and calibrate the conversion in the same environment used in production.

Wait for the right page state

Use explicit waits for visibility, presence, or a custom condition. A visible element may still contain a loading placeholder, so wait for an image, class, or text that proves the state you want.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from selenium.webdriver.support.ui import WebDriverWait

wait = WebDriverWait(driver, 20)
wait.until(lambda d: d.find_element(By.CSS_SELECTOR, "article .target img").get_attribute("complete") == "true")

Disable animations when deterministic output matters by injecting a temporary style before capture:

driver.execute_script("""
const style = document.createElement('style');
style.id = 'screenshot-stability';
style.textContent = `*, *::before, *::after {
  animation: none !important;
  transition: none !important;
  caret-color: transparent !important;
}`;
document.head.appendChild(style);
""")

This changes the page only in the capture session. Remove or avoid it when the animation itself is what you need to document.

Diagnose common failures

“No such element”

The selector may be wrong, the page may not have finished navigating, or the content may be inside an iframe or shadow root. Wait for the element, switch to the correct iframe before locating it, and confirm the selector in browser developer tools.

The image is blank or old

Capture occurred before content loaded, or a lazy image has not entered the viewport. Wait for the target state, scroll it into view, and check the element’s rendered dimensions before saving.

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

The crop is shifted or has the wrong size

Common causes are device scale, browser zoom, a changed scroll position, sticky content, window resizing, or page reflow. Take the screenshot and read rect in the same state, compare CSS dimensions with image.size, and calibrate rather than assuming a fixed multiplier.

Only part of the element appears

An element screenshot reflects the element’s rendered region. Overflow clipped by CSS, a collapsed container, or content outside the element’s box will not automatically be included. Capture a containing element or use a larger window crop when that is the intended visual area.

Headless and headed results differ

Headless mode can use different defaults for viewport, fonts, and device scale. Set an explicit window size, install the same fonts, and compare PNG dimensions in both modes.

Does this capture the entire page?

The cited current-window API establishes a screenshot of the current window, not a browser-independent guarantee of a full document across drivers. For a full-page result, verify the behavior of the specific browser and driver version you run instead of assuming that a viewport screenshot includes every scrolled section.

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 output choices

  • Capture only what you need: element screenshots and small crops use less memory and storage than repeatedly saving large windows.
  • Reuse a driver: starting a browser for every image is slower and more failure-prone than keeping one session for a batch, while navigating to a fresh URL between captures.
  • Keep capture state deterministic: fix viewport size, timezone-related page settings where relevant, zoom, fonts, and wait conditions.
  • Validate files: check that the PNG exists, has non-zero dimensions, and represents the expected state before uploading it.
  • Record environment details: browser, driver, Selenium version, viewport, and device scale make coordinate bugs reproducible.

For a direct element image, prefer screenshot_as_png when the next operation is in memory. For a rectangle, retain the original window PNG during debugging so you can distinguish a bad crop box from a bad page render.

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

Or skip the browser setup

ScreenshotNeo provides a one-request screenshot API when you do not want to maintain Selenium, browser binaries, waits, and coordinate calibration. It can capture full pages or one CSS-selected element, and supports custom CSS and JavaScript, click actions, wait conditions, device presets, retina scale, headers, cookies, user agents, geolocation, caching, PDFs, bulk capture, and asynchronous jobs.

Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

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)
r.raise_for_status()
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(`${res.status} ${res.statusText}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo documentation for all parameters and response headers. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account to try it.

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

FAQ

Can I return an element screenshot without writing a file?

Yes. Use element.screenshot_as_png; it returns PNG bytes that you can pass to Pillow, an HTTP client, or object storage.

Can one Selenium call select several unrelated elements?

Not as one documented WebElement screenshot. Capture a common container if one exists, or take a window screenshot and crop a rectangle that encloses the required areas.

Why does a screenshot differ between machines?

Fonts, viewport dimensions, browser versions, device scale, zoom, and page timing all affect rendered pixels. Pin the important environment settings and wait for a defined page state.

Is Pillow required for Selenium screenshots?

No for direct element or window file output. Pillow is needed only when you want to manipulate PNG bytes, such as cropping an arbitrary rectangle.

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

Frequently Asked Questions

Can I return an element screenshot without writing a file?

Yes. Use element.screenshot_as_png to obtain PNG bytes.

Can one Selenium call select several unrelated elements?

No single documented WebElement screenshot combines unrelated nodes; capture a shared container or crop a window screenshot.

Why does a screenshot differ between machines?

Fonts, viewport, browser version, device scale, zoom, and timing can change rendered pixels.

Is Pillow required for Selenium screenshots?

Only for image processing such as cropping; direct Selenium file and bytes methods do not require it.

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

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.