How to Screenshot a Selenium Element Without a Collapsible Division
Capture one Selenium element cleanly, hide a page-specific expandable division, crop residual controls, and troubleshoot viewport and driver issues.
Direct answer: locate the target WebElement and call its element screenshot method. In Python, element.screenshot('element.png') writes a PNG containing the element’s visible rendered region. This is the correct first approach when you need one element, rather than taking a full browser screenshot and cropping it later.
If an expandable division, dock, banner or chat panel appears in the result, determine whether it is inside the target element or is page furniture overlapping it. If it belongs to the page, hide that specific DOM node before the capture, then restore it if the same browser session continues. A selector and style that work on one site are not universal Selenium options.
1. Capture one element in Python
Selenium’s Python API documents WebElement.screenshot(filename) as saving the current element to a PNG. The official Selenium screenshot guide also shows element-level capture: Selenium screenshot documentation.
from pathlib import Path
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
URL = "https://example.com/page-with-a-map"
OUTPUT = Path("map.png")
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1440,1200")
driver = webdriver.Chrome(options=options)
try:
driver.get(URL)
wait = WebDriverWait(driver, 30)
map_element = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "#map"))
)
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
map_element.screenshot(str(OUTPUT))
print(f"Saved {OUTPUT}")
finally:
driver.quit()
Replace #map with a stable selector from the page. Prefer an ID, data attribute, or semantic class over a generated CSS class. Wait for visibility so Selenium does not capture an element before it has dimensions.
2. Diagnose the unwanted collapsible division
- Open the page at the same viewport used by automation.
- Inspect the screenshot and identify whether the division is a child of the target element.
- If it is a child, select a narrower element or hide the child before capture.
- If it is outside the target but overlaps it, inspect its position,
z-index, and containing block. Hide the page-specific node or change the target and scroll position. - Capture again and verify the PNG dimensions and visible content.
An expandable division may change height after a click, during a resize, or after asynchronous content loads. Capture only after the page reaches the state you intend to publish.
3. Hide a page-specific dock before capture
Changing page styles is a workaround for that page, not a built-in Selenium screenshot setting. The selector, property, and timing must match the site. The following pattern hides an expanded dock and removes its occupied height, then captures the map.
from selenium.webdriver.common.by import By
# Use DevTools to replace these selectors with the page's real selectors.
dock_selector = ".expanded-dock"
map_selector = "#map"
# Confirm the node exists before changing it.
dock = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, dock_selector))
)
driver.execute_script("""
const dock = arguments[0];
dock.dataset.seleniumOriginalVisibility = dock.style.visibility;
dock.dataset.seleniumOriginalHeight = dock.style.height;
dock.style.visibility = 'hidden';
dock.style.height = '0px';
dock.style.overflow = 'hidden';
""", dock)
# Allow layout to settle, then locate the map again.
map_element = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, map_selector))
)
driver.execute_script("""
return new Promise(resolve => requestAnimationFrame(() => resolve()));
""")
map_element.screenshot("map-without-dock.png")
For a dock whose open state is controlled by a button, clicking the page’s own collapse control is usually safer than forcing CSS. If clicking causes navigation or animation, wait for the dock’s closed state before taking the screenshot.
collapse = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "[aria-label='Collapse panel']"))
)
driver.execute_script("arguments[0].click();", collapse)
wait.until(
EC.invisibility_of_element_located((By.CSS_SELECTOR, ".expanded-dock"))
)
map_element.screenshot("map-collapsed.png")
4. Handle margins, controls, and clipping after capture
Element screenshots describe the element’s visible region. If the output still contains margins, attribution, zoom controls, or branding, crop or mask the saved PNG. Fixed pixel coordinates depend on viewport size, device scale factor, responsive breakpoints, and the page layout, so calculate them from the actual image or element rectangle.
from PIL import Image
with Image.open("map-without-dock.png") as source:
# Example only: measure these values for your page and viewport.
left, top, right, bottom = 12, 8, source.width - 12, source.height - 8
cropped = source.crop((left, top, right, bottom))
cropped.save("map-cropped.png")
Mask controls only when they are outside the content you need. Do not copy coordinates from a different page or viewport. A CSS selector and a measured bounding rectangle are more robust than a hard-coded crop.
5. Wait for the content that belongs in the image
Maps, charts, and lazy images can render after the element first becomes visible. Wait for a page-specific readiness signal, such as a loaded class, a nonzero canvas size, or an image’s complete property.
wait.until(lambda d: d.execute_script("""
const el = document.querySelector(arguments[0]);
return el && el.getBoundingClientRect().width > 0 &&
el.getBoundingClientRect().height > 0;
""", map_selector))
wait.until(lambda d: d.execute_script("""
return [...document.querySelectorAll(arguments[0] + ' img')]
.every(img => img.complete);
""", map_selector))
map_element.screenshot("ready-map.png")
6. JavaScript Selenium equivalent
The Selenium JavaScript WebElement API describes the result as the visible region inside the element’s bounding rectangle. This example writes the returned base64 PNG to disk.
const { Builder, By, until } = require('selenium-webdriver');
const fs = require('node:fs/promises');
(async function () {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.manage().window().setRect({ width: 1440, height: 1200 });
await driver.get('https://example.com/page-with-a-map');
const map = await driver.wait(
until.elementIsVisible(await driver.findElement(By.css('#map'))),
30000
);
const png = await map.takeScreenshot();
await fs.writeFile('map.png', png, 'base64');
} finally {
await driver.quit();
}
})();
7. Java Selenium equivalent
WebDriver driver = new ChromeDriver();
try {
driver.manage().window().setSize(new Dimension(1440, 1200));
driver.get("https://example.com/page-with-a-map");
WebElement map = new WebDriverWait(driver, Duration.ofSeconds(30))
.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#map")));
File png = map.getScreenshotAs(OutputType.FILE);
Files.copy(png.toPath(), Path.of("map.png"), StandardCopyOption.REPLACE_EXISTING);
} finally {
driver.quit();
}
Driver implementations can differ. Selenium’s Java API documents best-effort behavior for non-W3C-conformant implementations, including preferring the entire element content and then the visible portion. Inspect the output with the exact browser and driver versions used in production.
8. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
ElementNotInteractableException or an empty image |
The element is hidden, has zero dimensions, or is still loading. | Wait for visibility and a nonzero bounding rectangle; scroll it into view if needed. |
StaleElementReferenceException |
The page re-rendered after you located the element. | Wait for the render to finish, then locate the element immediately before capture. |
| The dock remains in the PNG | The selector matched the wrong node, or the dock is inside the target. | Inspect the DOM, verify the matched node, and narrow the target selector or hide the child. |
| The map is clipped | Only the visible element region was captured, or the viewport is too small. | Set a known window size, scroll the element into view, or use a page-specific full-content strategy before capture. |
| Controls move between runs | Responsive layout, fonts, device scale, or asynchronous content changed. | Pin viewport and scale, wait for fonts/assets, and derive crop coordinates from the current rectangle. |
| Screenshot differs by browser | Driver and browser implementations may render element bounds differently. | Use a pinned browser/driver pair and compare output in that target environment. |
| PNG contains a blank chart | Canvas or data request was not ready. | Wait for a page-specific loaded signal or canvas dimensions, then capture. |
9. Performance, reliability, and cost
- Element capture avoids transferring and post-processing a full-window image when one element is all you need.
- Use one browser session for related captures, but re-find elements after DOM updates.
- Keep viewport, browser version, device scale, timezone, and fonts consistent for reproducible pixels.
- Wait for meaningful readiness signals instead of a long arbitrary sleep; this reduces both premature captures and wasted time.
- Retry navigation and screenshot steps only when the failure is transient. Do not hide deterministic selector or layout bugs with unlimited retries.
- Selenium itself does not charge per screenshot. Your cost is the browser infrastructure, execution time, storage, and any third-party services used by the page.
10. Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. It can capture a CSS-selected element, wait for a selector, delay, or network idle, apply custom JavaScript and CSS, click an element, hide selectors, set viewport and device options, and block ads, trackers, requests, or resource types.
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}`);
See the ScreenshotNeo API documentation for the full option set. Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
FAQ
Does Selenium capture the entire element, including content below the viewport?
Element screenshot behavior is based on the visible region and driver implementation. If content is clipped, make it visible or use a page-specific full-content technique before capture.
Can Selenium automatically remove every expandable division?
No. Selenium exposes screenshot operations; identifying and hiding a page’s dock or banner requires that page’s selector and state.
Should I crop a full browser screenshot instead?
Start with the element API. Crop afterward only for measured margins, controls, or branding that remain in an otherwise correct element image.
Why does the same selector produce different dimensions?
Responsive CSS, fonts, device scale, browser versions, and late-loading content can change the element rectangle. Pin those inputs and wait for readiness.
Can I capture an element as JPEG or WebP with Selenium?
The documented Selenium element methods write or return PNG data. Convert the PNG afterward if another format is required.


