How to Scroll Down a Page With Selenium
Use Selenium wheel actions to scroll by distance or bring a target into view. See Java, Python, JavaScript, and cURL examples, plus fixes for common issues.
To scroll down with Selenium, use a wheel action for a user-like scroll, or run the browser’s JavaScript scrolling methods when you need to move the document or a specific element. In Java, a fixed downward scroll is new Actions(driver).scrollByAmount(0, 500).perform(); a positive vertical delta scrolls down. To reach a known destination, prefer scrolling the target element into view instead of guessing a pixel distance.
1. Choose the right scrolling method
| Need | Method |
|---|---|
| Move down by a known amount | Wheel action with a vertical delta |
| Reach a known element | Wheel action to the element, or JavaScript scrollIntoView() |
| Scroll a nested region or from a particular coordinate | Wheel action with an element or viewport origin |
| Scroll to the document bottom | JavaScript using the document height, then wait for page behavior as needed |
Selenium’s official wheel-actions guide describes scrolling to an element, by an amount, from an element, from an element with an offset, and from a viewport offset. The page marks these wheel actions Chromium-only. The wheel input device was introduced in Selenium 4.2, so check your binding and installed version if a method is missing. Selenium wheel actions · Actions API
2. Scroll down by a fixed amount in Java
Use this when incremental movement is what you want. The delta is in pixels; positive Y means down and negative Y means up.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
public class ScrollPage {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com");
new Actions(driver)
.scrollByAmount(0, 500)
.perform();
} finally {
driver.quit();
}
}
}
Change 500 to suit the page. A large delta can move past content you intended to inspect; smaller repeated deltas may be easier to coordinate with waits and assertions.
3. Scroll a known element into view in Java
When the destination is known, target it directly. Selenium documents that scrollToElement brings the element’s bottom to the bottom of the screen, including when the target is above the current viewport.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
public class ScrollToTarget {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com");
WebElement target = driver.findElement(By.cssSelector("#target"));
new Actions(driver).scrollToElement(target).perform();
// Continue with an explicit wait or assertion for the next step.
} finally {
driver.quit();
}
}
}
The selector must match an element that exists. On a page that renders content later, wait for the target before locating it.
4. Scroll from an element or viewport origin
An origin is useful when the scroll should start in a nested scrollable area, such as a panel, or at a viewport coordinate. Java exposes this through scrollFromOrigin and WheelInput.ScrollOrigin.
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.WheelInput;
WebElement panel = driver.findElement(By.cssSelector(".scroll-panel"));
WheelInput.ScrollOrigin origin = WheelInput.ScrollOrigin.fromElement(panel);
new Actions(driver).scrollFromOrigin(origin, 0, 400).perform();
For a viewport coordinate, create an origin from a viewport point using the overload available in your Java Selenium version, then call scrollFromOrigin(origin, 0, 400). Element origins can also take offsets. Keep offsets within the viewport; Selenium warns that an offset outside it can raise an exception. See the official examples and API details for the signatures in your binding.
5. Python: use a wheel action or JavaScript
In Python, Selenium 4 provides wheel input through the Actions API. The exact convenience methods available can depend on the installed binding version; upgrade or consult the API reference if your version does not expose the method you need. The official Python reference documents WheelInput.
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
try:
driver.get("https://example.com")
ActionChains(driver).scroll_by_amount(0, 500).perform()
finally:
driver.quit()
Remove the leading space before driver = if copying into a Python file; it is shown here at the block’s indentation level only in editors that preserve surrounding indentation. A direct JavaScript option works when the selected document is the one that should scroll:
driver.execute_script("window.scrollTo(0, 500)")
6. JavaScript: Selenium WebDriver and browser scrolling
Selenium’s JavaScript WebDriver can execute a script in the currently selected frame or window. This runnable Node.js example uses a DOM script to move down a fixed amount:
const { Builder } = require('selenium-webdriver');
(async function scrollPage() {
const driver = await new Builder().forBrowser('chrome').build();
try {
await driver.get('https://example.com');
await driver.executeScript('window.scrollTo(0, 500)');
} finally {
await driver.quit();
}
})();
To bring a known element into view, pass the located element as a script argument:
const target = await driver.findElement({ css: '#target' });
await driver.executeScript('arguments[0].scrollIntoView()', target);
JavaScript execution runs in the current frame or window context. Switch to the correct frame first if the content is inside an iframe. Browser methods such as window.scrollTo and Element.scrollIntoView are DOM APIs, not Selenium-specific APIs. Selenium JavaScript WebDriver
7. Scroll to the bottom and handle dynamic content
For a document that scrolls with the window, a one-shot script can move to its current bottom:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
This moves to the height available at that moment; it does not guarantee that lazy-loaded or infinite-scroll content has finished loading. If the page adds content after scrolling, repeat the scroll and wait for a page-specific condition, such as a target element appearing or the document height changing. Stop when the content or condition you need is reached, and use a maximum iteration or time limit so an endless feed cannot hang the run.
For an element with its own scroll bar, scroll that container rather than assuming the document body is the scrolling surface. You can use an element-origin wheel action, or run JavaScript against the container, for example arguments[0].scrollTop = arguments[0].scrollHeight.
8. Waits, frames, and reliable interactions
- Navigate to the page and wait for the relevant content or target element using an explicit wait.
- Choose a fixed delta for incremental movement, or a target-based method when you know what must become visible.
- After scrolling, wait for the next expected state. Scrolling itself does not prove that an image, request, animation, or newly loaded section has completed.
- If the page uses an iframe, switch into it before locating or scrolling its content; switch back when finished.
- For nested scrolling, verify which ancestor has the scroll bar and start the wheel action at an origin inside that region.
Keep scroll steps and waits tied to observable page state rather than relying on a single arbitrary pause. Page behavior varies: a scroll can trigger lazy loading, but Selenium does not guarantee that the page will load additional content.
9. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
scrollByAmount or another wheel method is missing |
Older Selenium version or a binding API mismatch | Check the installed Selenium version and that binding’s current API. Wheel input was introduced in Selenium 4.2. |
| Wheel action runs but the page does not move | Wrong frame, scroll origin, or scrollable container | Select the intended frame and scroll region; verify the document or element actually has overflow to scroll. |
| Target cannot be found | Wrong selector, late rendering, or target is inside a frame | Check the selector, wait for presence, and switch to the correct frame before locating it. |
| Origin offset throws an exception | Offset falls outside the viewport | Use an in-viewport coordinate or an origin based on the scrollable element. |
| Scrolling to the bottom misses later content | Content is appended only after the first movement | Scroll in a bounded loop and wait for a page-specific change or completion condition. |
| JavaScript executes without visible movement | Script ran in another selected frame/window, or a nested container scrolls | Switch context and target the actual scrolling element rather than assuming window is responsible. |
10. Performance, reliability, and cost
A direct wheel action or script call adds little work compared with loading and rendering the page; total runtime is usually shaped by navigation, page scripts, waits, and any content loaded after scrolling. Avoid unnecessary repeated scrolls and fixed delays. For reliability, prefer target-based scrolling plus an explicit condition when the destination is known, and bound loops for infinite content. Selenium’s wheel documentation is marked Chromium-only, so check browser and binding support before relying on wheel actions elsewhere. Browser automation also requires maintaining a browser and driver setup.
For a one-off screenshot rather than an interactive browser workflow, ScreenshotNeo offers a hosted screenshot API and MCP server. Its API returns a screenshot or PDF from one GET request; pricing starts with 1,000 free shots per month without a card, and paid plans start at $5 for 3,000 shots. See ScreenshotNeo.
Or skip the browser setup
Use ScreenshotNeo when the goal is a clean page capture rather than interacting with the page in Selenium. Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use 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.
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)
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}`);
See the ScreenshotNeo API documentation for options and setup, then get 1,000 free screenshots a month with no card.
FAQ
Should I use a wheel action or JavaScript?
Use wheel actions when the automation should scroll through user-like input or use an origin. Use JavaScript for direct DOM movement, such as setting the window position or calling scrollIntoView().
How do I scroll up?
Use a negative vertical delta with a wheel action, or call window.scrollTo with a smaller Y position.
Does one scroll load every lazy image?
No. Loading depends on page behavior and how far the element is from the viewport. Scroll as needed and wait for the specific images or content your task requires.


