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

Use Selenium’s JavaScript execution to scroll the current page or a specific element: call window.scrollTo for an absolute position, window.scrollBy for a relative movement, or scrollIntoView for a located element. The same calls work in the selected window and frame. PhantomJS can run similar scripts only in legacy setups; Selenium’s JavaScript binding removed native PhantomJS support because its WebDriver implementation is no longer actively developed. For maintained automation, use headless Chrome or Firefox.

Choose the scrolling method first

Your choice depends on what the test must prove. Direct JavaScript positioning is deterministic and useful when you need a particular element visible. Wheel actions model user-like scrolling and can use an element as the scroll origin, but Selenium’s wheel-action documentation labels the scenarios Chromium Only, so verify support for your browser and language binding.

Need Recommended approach Important qualification
Jump to the bottom or an exact document position window.scrollTo Acts in the selected window and frame.
Move a fixed distance window.scrollBy Positive vertical values move down; negative values move up.
Reveal a known element scrollIntoView with a WebElement argument Useful when the element is outside the viewport.
Test wheel input or a nested scroll origin Selenium wheel actions Confirm compatibility; the documentation describes these scenarios as Chromium Only.
Run an old PhantomJS test Keep scrolling logic separate and migrate the browser PhantomJS integration is legacy, not a current Selenium recommendation.

Prerequisites for a maintained Selenium test

  • Install Selenium for your chosen language and have a compatible browser and driver available.
  • Use a current Chrome or Firefox installation for new work. Headless mode removes the need for a visible desktop window but does not change the scrolling API.
  • Know whether the target is in the top-level document or inside an iframe. JavaScript executes in the currently selected browsing context.
  • Identify whether the page itself scrolls or whether a nested element such as a feed, modal, or sidebar has its own overflow scrollbar.

Scroll a page with Selenium and Python

This complete example opens a page, scrolls to the document bottom, moves back up by 600 pixels, then scrolls a footer into view. Replace the URL and selector with values from your test.

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")

    # Absolute position: the bottom of the document.
    driver.execute_script(
        "window.scrollTo(0, document.body.scrollHeight);"
    )

    # Relative movement: 600 CSS pixels upward.
    driver.execute_script("window.scrollBy(0, -600);")

    # Element-targeted scrolling.
    footer = driver.find_element(By.CSS_SELECTOR, "footer")
    driver.execute_script(
        "arguments[0].scrollIntoView(true);", footer
    )
finally:
    driver.quit()

execute_script runs the supplied JavaScript in the currently selected frame or window. Selenium can pass a located WebElement as an argument, which is why arguments[0] refers to footer in the final call.

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

Scroll by a known amount

For incremental pagination or a tour through a page, use a positive delta to move down:

driver.execute_script("window.scrollBy(0, 600);")

Use several calls when the site loads content only after an intermediate position. A single jump to the bottom does not prove that lazy-loaded content has finished rendering.

Scroll to a precise document coordinate

driver.execute_script("window.scrollTo(0, 1200);")

The first argument is the horizontal coordinate and the second is the vertical coordinate. Coordinates are relative to the document, not to a particular nested panel.

Scroll an element into view

target = driver.find_element(By.CSS_SELECTOR, "#pricing")
driver.execute_script("arguments[0].scrollIntoView(true);", target)

The Boolean argument requests alignment at the top edge. If a sticky header covers the result, scroll by a small negative offset afterward or use a page-specific script that accounts for the header height.

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.

Use Selenium’s JavaScript binding

In the JavaScript binding, the equivalent operation is driver.executeScript. The method receives a script and optional arguments, including WebElements:

const { Builder, By } = require('selenium-webdriver');

(async function scrollExample() {
  const driver = await new Builder().forBrowser('chrome').build();
  try {
    await driver.get('https://example.com');
    await driver.executeScript(
      'window.scrollTo(0, document.body.scrollHeight);'
    );
    await driver.executeScript('window.scrollBy(0, -600);');
    const footer = await driver.findElement(By.css('footer'));
    await driver.executeScript(
      'arguments[0].scrollIntoView(true);', footer
    );
  } finally {
    await driver.quit();
  }
}());

Switch to the required window or frame before calling executeScript. Otherwise, the script can execute successfully while affecting a different document than the one containing your target.

Scroll inside an iframe

Find the iframe, switch into it, and then locate and scroll the content. Selenium’s script execution is context-sensitive:

frame = driver.find_element(By.CSS_SELECTOR, "iframe.payment")
driver.switch_to.frame(frame)
inside = driver.find_element(By.CSS_SELECTOR, ".receipt")
driver.execute_script("arguments[0].scrollIntoView(true);", inside)
driver.switch_to.default_content()

If the iframe itself is visible but its internal document does not move, this switch is the usual missing step. Return to the top-level document before interacting with elements outside the frame.

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

Scroll a nested container instead of the document

A page can have an unchanging document viewport and a separately scrollable feed. In that case, window.scrollTo targets the wrong scroll surface. Locate the container and either scroll it directly or bring a child into view:

feed = driver.find_element(By.CSS_SELECTOR, ".message-list")
driver.execute_script(
    "arguments[0].scrollTop = arguments[0].scrollHeight;", feed
)

last_row = driver.find_element(By.CSS_SELECTOR, ".message-list .row:last-child")
driver.execute_script("arguments[0].scrollIntoView(true);", last_row)

Wheel actions can also use an element as a scroll origin. Selenium documents element-origin and delta-based scenarios, but notes Chromium-only coverage; check the binding and browser combination used by your test suite. An origin offset outside the viewport can raise an exception, so keep the origin element on-screen or use direct JavaScript positioning.

Wait for content after scrolling

Scrolling and loading are separate events. Infinite feeds, images, and advertisements may update after the scroll call returns. Synchronize with a condition that represents your application’s state, such as the presence of a new row, a changed item count, or a loading indicator disappearing.

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

before = len(driver.find_elements(By.CSS_SELECTOR, ".card"))
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

WebDriverWait(driver, 15).until(
    lambda d: len(d.find_elements(By.CSS_SELECTOR, ".card")) > before
)

Do not replace an application-specific condition with an arbitrary sleep unless the test genuinely needs a fixed pause. Selenium supports asynchronous script execution with callback completion, but there is no site-independent waiting recipe that guarantees lazy-load completion.

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

Legacy PhantomJS: what still works and what does not

Older PhantomJS examples commonly use Selenium’s JavaScript execution to call window.scrollTo, window.scrollBy, or scrollIntoView. Those JavaScript calls describe browser behavior, not a current PhantomJS support promise.

Selenium’s JavaScript binding change history states that native support for PhantomJS was removed because its WebDriver implementation was no longer under active development, and recommends using Chrome or Firefox in headless mode instead. Treat PhantomJS capability snippets found in old projects as migration material, not as a supported setup for a new test.

Migrate without rewriting scrolling logic

  1. Keep calls such as executeScript and the selectors that identify targets.
  2. Replace the PhantomJS driver construction with a maintained Chrome or Firefox driver.
  3. Run the test in headless mode if the original job was server-side and had no display.
  4. Recheck frame selection, nested containers, timing, and screenshot output because modern browsers may expose different layout or loading behavior.
  5. Remove PhantomJS-specific capabilities after the replacement passes in the environments you support.

Common failures and fixes

The wrong window or frame moves

Cause: script execution affects the selected browsing context. Fix: switch to the intended window handle and iframe before locating the target and executing JavaScript.

The document moves but the target is still hidden

Cause: the target is inside a nested scroll container, or a sticky header covers it. Fix: scroll the container or call scrollIntoView on the target, then adjust for the header and verify its displayed state.

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

Scrolling reaches the bottom but no new items appear

Cause: the application has not finished its network or rendering work. Fix: wait for a meaningful DOM condition, changed item count, or loading-state transition; do not assume the scroll command itself waits.

A wheel action throws an unsupported-command error

Cause: browser or binding support does not match the documented Chromium-only scenarios. Fix: confirm compatibility for that exact combination or use JavaScript execution for deterministic positioning.

An old PhantomJS test cannot start

Cause: current Selenium no longer provides native PhantomJS support. Fix: migrate the driver to headless Chrome or Firefox while preserving the scrolling operations.

The script runs but the page appears unchanged

Cause: the page may have a fixed viewport with a scrollable element, or the selected element may already be visible. Fix: inspect which element’s scrollTop changes and target that element explicitly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a clean screenshot rather than an interaction test, ScreenshotNeo returns an image or PDF from one request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. 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 provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo documentation for parameters and response details. A direct request looks like this:

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}`);

The Free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account to get started.

Performance, reliability, and cost considerations

  • JavaScript jumps are usually cheaper than many small wheel events, but they may not exercise the same event handlers as a real wheel gesture.
  • Element-targeted scrolling is less brittle than hard-coded coordinates when responsive layouts change.
  • For long pages, capture or inspect only the region needed by the test where possible; full-page work can trigger substantial lazy loading.
  • Use explicit waits tied to application state to reduce both flaky failures and unnecessary delays.
  • When replacing PhantomJS, compare browser version, viewport, fonts, and headless settings so visual differences are not mistaken for scrolling defects.

Practical decision checklist

  1. Is the target in the current window and frame?
  2. Does the document scroll, or does a nested element own the scrollbar?
  3. Do you need an exact position, element visibility, or simulated wheel input?
  4. What observable condition proves that lazy content finished loading?
  5. Are you maintaining PhantomJS only because of an old test? If so, migrate the driver before adding more browser-specific code.

Frequently Asked Questions

Can Selenium scroll to an element without knowing its coordinates?

Yes. Locate the element and pass it to JavaScript as an argument to arguments[0].scrollIntoView(true).

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

Why does scrolling the window not move my sidebar or feed?

That region is likely a nested scroll container. Target the container or a child element inside it instead of using window.scrollTo.

Is PhantomJS still supported by Selenium?

Selenium’s JavaScript binding history removed native PhantomJS support and recommends headless Chrome or Firefox.

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.