ScreenshotNeo

BlogHow-to

How to Scroll a Webpage Before Taking a Screenshot with Selenium

Scroll to the bottom or a target element in Selenium, wait for lazy content, and capture the correct viewport or full page.

By the ScreenshotNeo team30 September 20267 min read

How to Scroll a Webpage Before Taking a Screenshot with Selenium

Use Selenium’s JavaScript executor to scroll, then capture the current viewport. In Python, scroll to the document bottom with driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") and save it with driver.save_screenshot("screenshot.png"). To bring a known element into view, call element.scrollIntoView(true) before saving.

execute_script runs JavaScript synchronously in the current window or frame, so Selenium runs the screenshot command after the scroll script returns. A normal WebDriver screenshot contains only the current viewport. Scrolling does not automatically create one tall, full-document image.

1. Scroll to the bottom, then capture the viewport

This complete Python example opens a page, scrolls to its bottom, waits for a small application-specific rendering interval, saves a PNG, and closes the browser.

A Selenium workflow scrolls first, then captures the current viewport.
A Selenium workflow scrolls first, then captures the current viewport.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time

options = Options()
options.add_argument("--headless=new")
options.add_argument("--window-size=1440,1000")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
    time.sleep(1)  # Replace with a condition tied to your application when possible.
    driver.save_screenshot("bottom-of-page.png")
finally:
    driver.quit()

The screenshot shows the viewport after the scroll. If the page is taller than the viewport, it will not include the entire document in one image.

2. Scroll to a specific element

Find the element first, then align it with the viewport. The true argument places the element’s top edge near the top of the viewport.

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

options = Options()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    element = driver.find_element(By.CSS_SELECTOR, "footer")
    driver.execute_script("arguments[0].scrollIntoView(true);", element)
    driver.save_screenshot("footer.png")
finally:
    driver.quit()

Use a stable selector such as an ID, data attribute, or semantic element. A selector that matches a hidden or duplicated node can produce an unexpected capture.

Center the element instead

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

Centering helps when a sticky header would cover the top of the target. You can also apply an offset after scrolling:

driver.execute_script("window.scrollBy(0, -80);")

3. Wait for content that loads during scrolling

The Selenium scroll call is synchronous, but the page may start asynchronous work afterward. Lazy images, infinite lists, advertisements, and client-rendered sections can still be incomplete when the screenshot runs. Selenium’s documentation does not define one universal delay; wait for a condition that represents your application’s ready state.

Wait for a target element

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

wait = WebDriverWait(driver, 15)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "footer")))
driver.save_screenshot("ready.png")

Wait for an image to finish loading

image = driver.find_element(By.CSS_SELECTOR, "img.hero")
wait.until(lambda d: d.execute_script(
    "return arguments[0].complete && arguments[0].naturalWidth > 0;", image
))
driver.save_screenshot("loaded-image.png")

Scroll an infinite page in increments

For an infinite feed, one jump to document.body.scrollHeight may trigger only the first batch of requests. Repeatedly measure the document height, scroll down, and stop when the height no longer grows or a page-specific end marker appears.

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

last_height = 0
for _ in range(20):
    height = driver.execute_script("return document.body.scrollHeight")
    driver.execute_script("window.scrollTo(0, arguments[0]);", height)
    time.sleep(0.5)
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

driver.save_screenshot("feed-end.png")

Prefer an explicit “end of results” element or network-ready signal when the site provides one. A fixed loop can stop too early on slow pages or waste time on pages that never end.

4. Viewport screenshots versus full-page screenshots

Goal Method Result
Capture what the user sees after scrolling save_screenshot or get_screenshot_as_file Current browser viewport as PNG
Capture a particular section scrollIntoView, then save Viewport positioned on the element
Capture the whole document in one image Firefox full-page screenshot API Full-document image, where supported

Firefox WebDriver documents save_full_page_screenshot and related full-page methods. A normal screenshot remains viewport-sized even if you first scroll to the bottom.

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.add_argument("-headless")
driver = webdriver.Firefox(options=options)
try:
    driver.get("https://example.com")
    driver.save_full_page_screenshot("full-page.png")
finally:
    driver.quit()

Full-page support and rendering details vary by browser and driver. If you need identical output across browsers, capture predictable viewport regions or use a dedicated screenshot service.

5. Java Selenium equivalent

Java uses JavascriptExecutor for scrolling and TakesScreenshot for the PNG.

import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.WebElement;

WebDriver driver = new ChromeDriver();
try {
    driver.get("https://example.com");
    JavascriptExecutor js = (JavascriptExecutor) driver;
    WebElement footer = driver.findElement(By.cssSelector("footer"));
    js.executeScript("arguments[0].scrollIntoView(true);", footer);
    File image = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
    // Copy image to your destination with your preferred file utility.
} finally {
    driver.quit();
}

6. Useful scroll and capture options

  • Bottom of document: window.scrollTo(0, document.body.scrollHeight).
  • Absolute position: window.scrollTo({top: 1200, left: 0, behavior: 'instant'}).
  • Relative movement: window.scrollBy(0, 600).
  • Element alignment: arguments[0].scrollIntoView(true).
  • Horizontal scrolling: use scrollTo(x, y) or scrollIntoView({inline: 'center'}).
  • Viewport size: set the WebDriver window size before navigation so responsive breakpoints are deterministic.
  • PNG output: save_screenshot and get_screenshot_as_file save the current window as PNG.

Disable smooth scrolling for deterministic automation if the site’s CSS animates movement:

driver.execute_script("document.documentElement.style.scrollBehavior = 'auto';")

Fixed headers can hide the target. Scroll it into view, then subtract the header height:

driver.execute_script("arguments[0].scrollIntoView(true); window.scrollBy(0, -72);", element)

7. Common errors and fixes

Symptom Cause Fix
Screenshot still shows the top Scroll ran in the wrong tab, frame, or before navigation completed Switch to the correct window/frame, wait for the page, then execute the script.
Target is covered by a header Sticky navigation overlays the element Use centered scrollIntoView or scroll upward by the header height.
Lazy images are blank Image requests are asynchronous Wait for complete and naturalWidth, or wait for the page’s loaded marker.
Infinite page is incomplete One bottom jump did not trigger every batch Scroll in increments and stop on an end marker or stable document height.
ElementNotInteractableException or stale element The DOM changed after locating the element Wait for visibility and locate the element again immediately before scrolling.
Only one viewport appears in the output save_screenshot is a viewport capture Use Firefox’s full-page API or capture and stitch sections deliberately.
Different screenshots in headless and headed mode Different window size, fonts, or timing Set an explicit viewport, install required fonts, and wait on application state.
Script works on the main page but not an iframe JavaScript runs in the current browsing context Switch with driver.switch_to.frame(...), scroll, then switch back.

8. Reliability, performance, and cost considerations

  • Reliability: Replace arbitrary sleeps with explicit waits tied to visible elements, loaded images, or an application-ready marker. Keep selectors stable and set page-load and script timeouts.
  • Performance: One JavaScript scroll is inexpensive. Incremental scrolling on a long infinite feed is slower because it triggers layout, rendering, and network work at every step.
  • Memory: Very long pages and large device-scale factors increase browser memory and image size. Use a realistic viewport and capture only the required region.
  • Repeatability: Fix the browser version, viewport, timezone, locale, fonts, and test data when comparing screenshots.
  • Cost: Running Selenium means maintaining browser binaries, drivers, compute, and page-loading time. A hosted capture API can remove that operational work; compare its billing rules with your workload.

9. Or skip the browser setup

ScreenshotNeo provides a single-request website screenshot API when you do not need to manage Selenium, Chrome, drivers, or waits yourself. See the ScreenshotNeo API documentation for all options.

Automated cleanup can remove overlays before a screenshot is taken.
Automated cleanup can remove overlays before a screenshot is taken.
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}`);

Before capture, ScreenshotNeo can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server lets Claude, Cursor, and other MCP clients use take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.

10. FAQ

Does Selenium wait for scrolling to finish?

The JavaScript execution itself is synchronous, so Selenium continues after the script returns. It does not guarantee that lazy content triggered by scrolling has finished loading; wait for that content separately.

Can I scroll an element without clicking it?

Yes. Locate the element and call scrollIntoView; no click is required.

Why is my full-page screenshot not full height?

save_screenshot captures the current viewport. Use a browser-specific full-page method, such as Firefox’s documented API, or capture sections and combine them.

Which Selenium API saves a screenshot?

Python provides save_screenshot and get_screenshot_as_file; Java exposes screenshot output through TakesScreenshot.

How do I capture a page after scrolling horizontally?

Use window.scrollTo(x, y) or scrollIntoView with an inline option, set a viewport wide enough for the layout, and then save the current viewport.

Sources