How to Capture a Selenium Screenshot After Scrolling to an Element
Scroll a Selenium element into view, then capture either the element itself or the surrounding browser viewport. Includes Python examples and fixes for sticky headers and dynamic pages.
To capture an element after scrolling to it in Selenium, locate the element, scroll it into view, then call element.screenshot("target.png"). This saves a PNG crop of the element. If you want the surrounding browser viewport instead, scroll first and take a driver-level screenshot.
1. Capture the element after scrolling
This runnable Selenium Python example opens a page, waits for a target element, centers it in view, and saves the element as target.png. Replace the URL and CSS selector with values for your page.
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"
selector = "#target"
driver = webdriver.Chrome()
try:
driver.get(url)
element = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, selector))
)
driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'nearest', behavior: 'instant'});",
element,
)
element.screenshot("target.png")
finally:
driver.quit()
Selenium documents WebElement.screenshot(filename) as saving the current element to PNG. Use screenshot_as_png or screenshot_as_base64 when you need the bytes or encoded value instead of writing a file. See the Selenium Python WebElement API.
Choose a locator that identifies the intended element
The example uses a CSS selector, but Selenium supports other locators. Prefer a stable ID, test attribute, or other selector that identifies one element. If your locator matches multiple elements, make it specific enough to select the intended one.
from selenium.webdriver.common.by import By
element = driver.find_element(By.ID, "target")
# Or:
element = driver.find_element(By.CSS_SELECTOR, "[data-testid='result-card']")
# Or:
element = driver.find_element(By.XPATH, "//section[@aria-label='Results']")
2. Set the scroll position deliberately
scrollIntoView() scrolls ancestor containers to bring the element into view. The options let you choose vertical and horizontal alignment and scrolling behavior. A centered, instant scroll is a useful default when a fixed header might cover the top of the page.
driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'nearest', behavior: 'instant'});",
element,
)
| Option | Effect | Useful when |
|---|---|---|
block: "start" |
Aligns the element’s top edge with the top of its scrollable area. | You want top alignment and no fixed header covers the target. |
block: "center" |
Centers the element vertically in the scrollable area. | A sticky header could overlap a top-aligned element. |
block: "end" |
Aligns the element’s bottom edge with the bottom of the scrollable area. | The bottom edge is the important part of the composition. |
block: "nearest" |
Moves the least amount needed to bring the element into view. | You want to preserve the current scroll position where possible. |
inline: "nearest" |
Moves horizontally only as needed. | Horizontal scrolling is possible and you want minimal movement. |
behavior: "instant" |
Requests an immediate jump. | The screenshot should follow the scroll without waiting for a smooth animation. |
behavior: "smooth" |
Animates the scroll. | You specifically need the animated behavior; wait for it to finish before capture. |
behavior: "auto" |
Follows the computed CSS scroll behavior. | You want the page’s configured behavior to apply. |
The shorter scrollIntoView(true) form aligns the element to the top; false aligns it to the bottom. These correspond to {block: "start", inline: "nearest"} and {block: "end", inline: "nearest"}. For a fixed header, center alignment or CSS scroll-margin-top can leave space above the target. The page layout and nested scroll containers still affect the result. See MDN’s scrollIntoView reference.
3. Choose element, viewport, or full-page output
Pick the screenshot method based on what the image needs to show:
| Output | Selenium method | What it captures |
|---|---|---|
| Element crop | element.screenshot("target.png") |
The located element itself, without surrounding page context. |
| Viewport | driver.save_screenshot("viewport.png") |
The visible browser page after scrolling, including surrounding context. |
| Full document | Not established by the basic methods above | A driver viewport screenshot should not be assumed to capture a long page in full. |
For a viewport screenshot after scrolling, use:
driver.execute_script(
"arguments[0].scrollIntoView({block: 'center', inline: 'nearest', behavior: 'instant'});",
element,
)
driver.save_screenshot("viewport.png")
Selenium’s Python quick reference lists both driver-level screenshot methods and element-level screenshot methods. See the Selenium documentation and Python API reference.
4. Handle lazy loading and dynamic pages
Scrolling can trigger lazy-loaded images or application updates. Do not assume that the page is ready for capture immediately after a scroll if the content changes as it comes into view. Wait for an application-specific condition, such as the image becoming complete or a loading marker disappearing.
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
# Wait for an application-specific state after the scroll.
WebDriverWait(driver, 10).until(
lambda d: d.execute_script(
"return arguments[0].complete && arguments[0].naturalWidth > 0;",
element.find_element(By.CSS_SELECTOR, "img"),
)
)
element.screenshot("target.png")
Adapt the condition to the page. For example, wait for a loading indicator to disappear, a result count to update, or an image to finish loading. A fixed sleep is not a reliable universal solution because animation, network, and lazy-loading times vary.
If the page rerenders after scrolling, Selenium can report that the original element reference is stale. Reacquire the element after the update, scroll the fresh reference, then capture it. Selenium checks element freshness when methods run; a detached element reference remains unusable. See the WebElement API.
5. Other Selenium language bindings
The direct answer above is for Python. In other Selenium bindings, execute the same browser JavaScript to scroll and then use that binding’s element or driver screenshot API. Method names and screenshot return types differ by language and version; check the official API reference for the binding you use.
// JavaScript example using Selenium WebDriver for Node.js
const { Builder, By } = require('selenium-webdriver');
(async function captureElement() {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com');
const element = await driver.findElement(By.css('#target'));
await driver.executeScript(
"arguments[0].scrollIntoView({block: 'center', inline: 'nearest', behavior: 'instant'});",
element
);
// Use the Node binding's screenshot API for the desired output.
const image = await element.takeScreenshot(true);
require('node:fs').writeFileSync('target.png', Buffer.from(image, 'base64'));
} finally {
await driver.quit();
}
})();
This Node.js example uses Selenium WebDriver’s element screenshot API, which returns encoded screenshot data in the binding. Confirm the method signature against the Selenium JavaScript API version installed in your project.
6. Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
NoSuchElementException |
The selector does not match yet, is wrong, or the content is inside a frame. | Check the selector, wait for the element, and switch to the correct frame when needed. |
StaleElementReferenceException |
The page detached or replaced the element after it was located. | Wait for the page update, locate the element again, then scroll and capture the fresh reference. |
| The target is hidden behind a sticky header | Top alignment placed it underneath fixed content. | Use block: "center" or add a suitable scroll-margin-top to the target. |
| The screenshot shows an intermediate scroll position | Smooth scrolling is still running or application content is changing. | Request behavior: "instant" where supported, or wait for a meaningful application condition before capture. |
| The image misses content that appears on scroll | A lazy-loaded image or other content has not finished loading. | Wait for that content’s loaded or visible state before taking the screenshot. |
| The output contains only the target when context was expected | An element screenshot crops to the element. | Use driver.save_screenshot() after scrolling to capture the viewport. |
| The output does not contain the whole long page | A basic driver screenshot captures the visible viewport, not a guaranteed full document. | Use a full-page method supported by your chosen tooling, and verify its behavior for your browser and driver. |
7. Reliability, performance, and cost
For reliable results, wait for the target, use immediate scrolling when animation is unwanted, and wait for the page state that matters before capture. Reacquire elements after rerenders. The final pixels can vary with viewport size, browser, driver, fonts, and page state, so keep those conditions consistent when screenshots are part of a regression check.
Element capture focuses the output on the target; viewport capture includes more pixels and page context. Keep the chosen output type and viewport consistent when comparing images. Browser setup and page loading are part of a Selenium workflow, so the main costs are the compute and time needed to run the browser and load the page. No benchmark or universal runtime applies across sites and environments.
8. Or skip the browser setup
For a URL-based screenshot without setting up Selenium and a browser, ScreenshotNeo provides a website screenshot API and MCP server. Its API can return PNG, JPEG, WebP, or PDF; the one-call example below saves the response body to a file. 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,
)
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 accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card required.
9. FAQ
Does Selenium scroll the element automatically when I take its screenshot?
Use an explicit scroll first when the scroll position matters. Then call the element screenshot method or the driver screenshot method, depending on the output you need.
What does location_once_scrolled_into_view do?
It scrolls the element into view while obtaining its location. Selenium documents it as a location helper, and its implementation uses scrollIntoView(true). Prefer it when you need the location; use explicit JavaScript scrolling when you need to choose alignment or behavior.
Can I get the screenshot as data instead of a file?
In Python, use element.screenshot_as_png for PNG bytes or element.screenshot_as_base64 for base64 data. The file method is convenient when you want Selenium to write the PNG directly.


