October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Browser Testing

How to Scroll a Website With PhantomJS and Selenium (and the Modern Selenium Alternative)

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

Use Selenium’s JavaScript execution to scroll: run window.scrollTo, window.scrollBy, or scrollIntoView in the currently selected window and frame. PhantomJS can run old Selenium scripts, but it is a legacy, unmaintained browser integration. For new work, run the same Selenium code with headless Chrome or Firefox.

Choose the right scrolling method

Your choice depends on what the test must prove:

Goal Preferred technique Why
Jump to an exact page position execute_script with window.scrollTo Direct, deterministic positioning.
Move a known distance window.scrollBy Useful for incremental lazy-loading or pagination checks.
Reveal a specific element scrollIntoView on a located element Targets the element instead of guessing document coordinates.
Model wheel input Selenium wheel actions Represents wheel movement and supports an element or scroll origin; Selenium’s documentation qualifies these scenarios as Chromium Only, so verify your browser and binding.
Scroll a nested panel Target the panel element or an appropriate wheel origin The document may not be the container that actually scrolls.

Selenium JavaScript execution runs in the active browsing context—the selected window and frame—and can receive a located WebElement as an argument. That context rule explains many “the page did not scroll” failures.

Set up maintained Selenium first

Install Selenium for Python and use a current browser driver managed by your environment. A minimal example opens a page, scrolls to the bottom, and then quits cleanly:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

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

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
finally:
    driver.quit()

Remove --headless while developing if you need to watch the viewport. A larger window can change responsive layouts and therefore change which element is scrollable.

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

Scroll down a page with JavaScript

Jump to the bottom

driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")

scrollTo sets an absolute position. To go to a known coordinate, use two arguments:

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

Coordinates are pixels in the document’s vertical direction. They are not a guarantee that a particular target is visible after responsive reflow, sticky headers, or content inserted above the target.

Move by a relative amount

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

Positive vertical values move down; negative values move up. For a loop that progressively exposes content, keep the increment modest and check a condition after each move rather than assuming a fixed number of iterations is enough.

Scroll to an element

from selenium.webdriver.common.by import By

element = driver.find_element(By.CSS_SELECTOR, "footer")
driver.execute_script("arguments[0].scrollIntoView(true)", element)

The WebElement is passed as a JavaScript argument, where it becomes arguments[0]. The true alignment places the element’s top edge near the top of the viewport. If a fixed navigation bar covers it, use a small follow-up offset:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
driver.execute_script("arguments[0].scrollIntoView(true); window.scrollBy(0, -80)", element)

Choose a stable selector. A data attribute intended for testing is usually less fragile than a generated class name.

Scroll with Selenium wheel actions

Wheel actions are useful when the behavior under test is wheel input rather than merely the final position. Selenium documents scrolling by a delta, to an element, and from an element or other origin. Negative horizontal or vertical deltas move left or up.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Because the official wheel documentation labels these scenarios Chromium Only, confirm support for the exact browser and language binding in your test matrix before depending on them. A JavaScript scroll is generally the safer cross-browser positioning primitive when you only need an element visible.

Conceptually, a wheel action looks like this in Selenium bindings that expose wheel input:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
# API names vary by Selenium language binding and version.
# Verify the wheel-action syntax for your binding before using it.
ActionChains(driver).scroll_by_amount(0, 600).perform()

For an element-origin scroll, use the binding’s documented “scroll from element” operation and pass the scrollable element. An origin offset outside the viewport can raise an exception. Do not assume a wheel event aimed at the document will move a modal, sidebar, or other nested container.

Scrolling nested containers correctly

Many pages have a fixed body with an independently scrolling feed. In that case, window.scrollTo changes the document, not the feed. Locate the container and scroll it directly:

panel = driver.find_element(By.CSS_SELECTOR, ".results-panel")
driver.execute_script("arguments[0].scrollTop = arguments[0].scrollHeight", panel)

To move a container by a fixed amount:

driver.execute_script("arguments[0].scrollBy(0, 500)", panel)

Alternatively, locate a child inside the panel and call scrollIntoView on that child. If the child is in an iframe, switch into that frame first; JavaScript executes in whichever frame is selected.

Frames, windows, and the active browsing context

When scrolling appears to do nothing, verify context before changing the script:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Switch to the intended window or tab with Selenium’s window-handle API.
  2. Switch into the iframe containing the target with driver.switch_to.frame(...). Use driver.switch_to.default_content() to return to the top document.
  3. Locate the element after switching; WebElements belong to the document in which they were found.
  4. Run the scroll script, then verify visibility or position in that same context.

An iframe’s document can scroll independently from its parent page. Scrolling the parent cannot reveal content that is below the viewport inside the child frame.

Dynamic content and lazy loading

Scrolling is an action, not proof that new content has finished loading. Infinite feeds may request data after the scroll event; images may be lazy-loaded only when an intersection threshold is reached. Synchronize with a relevant observable condition:

  • Wait for a new item that was not present before the scroll.
  • Wait for a loading indicator to disappear.
  • Wait for a network-driven status or page-specific “end of results” marker.
  • Use an explicit short delay only when the application provides no better condition, and keep the delay as a last resort.

Do not write a site-independent recipe that assumes “scroll, sleep, done.” The correct wait depends on the page’s DOM and loading contract. Selenium also provides asynchronous script execution for JavaScript that completes through a callback; use it when your page-side operation itself is asynchronous, then combine it with an application-level wait.

JavaScript Selenium binding example

The same operations are available in Selenium’s JavaScript binding through executeScript. This complete example uses headless Chrome:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
const { Builder, By } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

(async function scrollPage() {
  const options = new chrome.Options().addArguments('--headless=new');
  const driver = await new Builder()
    .forBrowser('chrome')
    .setChromeOptions(options)
    .build();

  try {
    await driver.get('https://example.com');
    await driver.executeScript(
      'window.scrollTo(0, document.body.scrollHeight);'
    );
    const footer = await driver.findElement(By.css('footer'));
    await driver.executeScript('arguments[0].scrollIntoView(true)', footer);
  } finally {
    await driver.quit();
  }
})();

In this binding, the supplied script runs in the currently selected frame or window, and WebElements can be included as arguments.

PhantomJS: legacy migration guidance

Older tutorials often combine Selenium with PhantomJS capabilities. Treat those examples as migration material, not as a recommendation for a new test suite. Selenium’s JavaScript binding change history states that native PhantomJS support was removed because its WebDriver implementation was no longer under active development. The project advises PhantomJS users to use Chrome or Firefox in headless mode instead.

The scrolling logic itself usually needs little or no change: keep your window.scrollTo, window.scrollBy, and scrollIntoView calls, replace the PhantomJS driver initialization, and then re-check selectors, user-agent-dependent behavior, and rendering differences in the maintained browser.

If you must keep an old PhantomJS job

  • Pin the legacy environment so an unrelated driver update does not silently change behavior.
  • Separate browser startup from scrolling helpers; this makes migration straightforward.
  • Expect differences in modern JavaScript, CSS, TLS, and bot-detection behavior.
  • Plan a move to headless Chrome or Firefox rather than adding new PhantomJS-specific capabilities.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting scroll failures

The wrong page or frame moves

Check the active window handle and frame. executeScript operates only in the selected browsing context.

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

The document moves, but the target is still hidden

The target may be inside a nested scroll container. Scroll that container or use an element-origin wheel action. Also check whether a sticky header covers the element after alignment.

The script throws a stale-element error

The page replaced the node after you located it. Find the element again immediately before scrolling, and wait for the page’s update to finish before interacting with it.

Scrolling reaches the bottom but no items appear

Confirm that the feed is the scrollable element, then wait for a new item or loading-state change. A fixed delay does not prove that the request completed.

Wheel actions fail in a non-Chromium browser

The documented wheel scenarios carry a Chromium Only qualification. Use JavaScript positioning or verify that your selected binding and browser implement the required action.

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

PhantomJS will not start

Do not treat startup errors as a scrolling bug. PhantomJS is an obsolete Selenium integration; migrate the driver to headless Chrome or Firefox and retain the page-level scrolling helper.

Performance, reliability, and test design

  • Prefer one targeted operation. Scrolling directly to a known element is usually less work than many small increments.
  • Use incremental movement deliberately. It is appropriate when the application loads content based on repeated scroll thresholds.
  • Make viewport size explicit. Responsive breakpoints can change both document height and which element owns scrolling.
  • Assert an outcome. Verify visibility, a changed scroll position, a new item, or an end marker rather than asserting that a command returned.
  • Keep browser migration separate. A helper that accepts a driver and selector can be reused with Chrome, Firefox, and a temporary legacy setup.

Or skip the browser setup

If your actual goal is a clean screenshot rather than an interactive browser test, ScreenshotNeo provides a single HTTP request. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, 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 includes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo documentation for parameters and response details. cURL:

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 per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

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

Frequently Asked Questions

Can Selenium scroll an iframe’s document?

Yes, after switching into the iframe. The script runs in the selected frame; switch back to the top document when finished.

Should new projects still use PhantomJS?

No. Keep PhantomJS only as legacy migration context and use headless Chrome or Firefox for maintained Selenium automation.

Why does window.scrollTo not move my feed?

The feed is likely a nested scroll container. Locate that container and change its scroll position or target a child with scrollIntoView.

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.

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

Leave a Reply

Your email address will not be published. Required fields are marked *

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.

Read next

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.