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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Read the document’s scrolling element and return its scrollHeight with Selenium’s JavascriptExecutor. That gives the total DOM content height in CSS pixels, including content below the viewport. Measure only after the page reaches the state you care about, and switch into the correct iframe first when the content is framed.

The direct Selenium Java solution

The following snippet measures the current document without manually scrolling:

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;

// driver is initialized and is already on the target page.
long pageHeight = ((Number) ((JavascriptExecutor) driver)
    .executeScript("return document.scrollingElement.scrollHeight;"))
    .longValue();

System.out.println("Document content height: " + pageHeight + " CSS pixels");

JavascriptExecutor.executeScript runs JavaScript in Selenium’s currently selected window and frame. The Java API can return a whole number as Long or a decimal as Double; converting through Number keeps this code safe for either wrapper. See the Selenium JavascriptExecutor API.

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

In this context, “page length” means the document’s content extent, not the height of the visible browser window and not the size of one particular element. The result is an integer number of CSS pixels.

Why scrollingElement.scrollHeight is the right property

A browser exposes several height values. They answer different questions, so substituting one for another can produce a plausible but wrong result.

Property or API What it measures Overflow below the viewport Box details Best use
document.scrollingElement.scrollHeight Content extent of the document’s scrolling element Included Includes padding; excludes border and margin; integer pixels Total document content height
clientHeight Displayed content area of an element Not included Includes padding; excludes border, margin and scrollbar Visible content area
offsetHeight Occupied layout height of an element Only what belongs to that box Includes padding, border and a scrollbar when present; excludes margin Rendered box dimensions
WebElement.getSize().getHeight() Rendered height of one located element Not a document measurement Element geometry, not page overflow A component, panel or article element

MDN documents scrollHeight as the extent of an element’s content, including content not visible because of overflow. document.scrollingElement selects the element that actually scrolls the document. In standards mode that is normally document.documentElement; under the specified quirks-mode condition it can be body.

A complete runnable example

This example uses Selenium Manager (available in current Selenium 4 releases) to create a Chrome driver, opens a page, waits for the document to finish loading, and prints the height and viewport height. The dependency version is intentionally left to the version you have approved in your build; consult Selenium’s getting-started documentation for installation and browser setup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import java.time.Duration;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

public class PageHeight {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(60));
            driver.get("https://example.com");

            new WebDriverWait(driver, Duration.ofSeconds(30)).until(d ->
                "complete".equals(((JavascriptExecutor) d).executeScript(
                    "return document.readyState;")));

            JavascriptExecutor js = (JavascriptExecutor) driver;
            Object raw = js.executeScript(
                "var root = document.scrollingElement;" +
                "return root ? root.scrollHeight : null;");

            if (raw == null) {
                throw new IllegalStateException("This document has no scrolling element");
            }

            long totalHeight = ((Number) raw).longValue();
            long viewportHeight = ((Number) js.executeScript(
                "return document.scrollingElement.clientHeight;")).longValue();

            System.out.printf("Total content: %d CSS px; viewport: %d CSS px%n",
                totalHeight, viewportHeight);
        } finally {
            driver.quit();
        }
    }
}

readyState reaching complete means the browser’s load event has finished; it does not guarantee that a single-page application, images, advertisements or API-rendered components have finished changing the DOM. Add an application-specific wait when those elements matter.

Measure the correct page state

Wait for a known element

For an article, dashboard or report, wait for a selector that proves the useful content is present:

new WebDriverWait(driver, Duration.ofSeconds(30)).until(
    org.openqa.selenium.support.ui.ExpectedConditions
        .visibilityOfElementLocated(org.openqa.selenium.By.cssSelector("main article")));

long height = ((Number) ((JavascriptExecutor) driver).executeScript(
    "return document.scrollingElement.scrollHeight;")).longValue();

Prefer a meaningful state signal over an arbitrary sleep. A fixed delay can be useful only when the application offers no observable condition; keep it as short as the page’s measured behavior allows.

Lazy-loaded images

An image with loading="lazy" may not contribute its final layout until it approaches the viewport. If your definition of “full length” includes all lazy content, scroll in increments, wait for layout to settle, then measure:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
JavascriptExecutor js = (JavascriptExecutor) driver;
long previous = -1;
for (int pass = 0; pass < 20; pass++) {
    long current = ((Number) js.executeScript(
        "return document.scrollingElement.scrollHeight;")).longValue();
    js.executeScript("window.scrollTo(0, document.scrollingElement.scrollHeight);");
    Thread.sleep(500); // replace with an explicit image/content wait when possible
    long after = ((Number) js.executeScript(
        "return document.scrollingElement.scrollHeight;")).longValue();
    if (after == current && current == previous) break;
    previous = current;
}
long finalHeight = ((Number) js.executeScript(
    "return document.scrollingElement.scrollHeight;")).longValue();

This loop is a stabilization strategy, not proof that an infinite feed is complete. An infinite-scroll site can keep adding content forever. Define a maximum number of passes, a target item count or an application completion marker.

Wait for fonts and layout changes

Web fonts, responsive components and late network responses can change line wrapping and therefore page height. If the page exposes a “loaded” flag, wait for it. Otherwise, take two measurements separated by a short, bounded wait and accept the value only when they remain equal; do not use an unbounded polling loop in a test suite.

Frames, windows and shadow DOM

Content inside an iframe

JavaScript runs in Selenium’s currently selected frame. Switch before measuring, then switch back if later steps target the top document:

WebDriver driver = ...;
var frame = driver.findElement(org.openqa.selenium.By.cssSelector("iframe.report"));
driver.switchTo().frame(frame);
long frameHeight = ((Number) ((JavascriptExecutor) driver).executeScript(
    "return document.scrollingElement.scrollHeight;")).longValue();
driver.switchTo().defaultContent();

The value is the height of the iframe document, not the outer page. The outer document’s height and the iframe’s internal height are separate measurements.

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

Multiple windows or tabs

After opening a new tab, use driver.switchTo().window(handle) before executing the script. Selenium always evaluates JavaScript in the selected window.

Shadow DOM

A component’s shadow root is not automatically the document’s scrolling element. Locate the host, retrieve its shadow root with Selenium’s shadow-DOM APIs, and measure the specific scroll container inside it when that is the content you need.

Measure an element instead of the whole document

If the requirement is the height of an article, modal or grid, locate that element and choose the property that matches the question:

var article = driver.findElement(org.openqa.selenium.By.cssSelector("article"));
long renderedHeight = article.getSize().getHeight();
long contentHeight = ((Number) ((JavascriptExecutor) driver).executeScript(
    "return arguments[0].scrollHeight;", article)).longValue();

getSize() reports rendered element geometry. The element’s scrollHeight reports its content overflow, which can be larger when the element has an internal scrollbar.

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

Common failures and precise fixes

  • Height is only the viewport. You read clientHeight. Use document.scrollingElement.scrollHeight.
  • document.body.scrollHeight is unexpectedly small. The page may scroll the root element, or it may be in standards mode. Use document.scrollingElement instead of hard-coding body.
  • NullPointerException from the script. A document without a scrolling element is possible. Return the element conditionally, check for null, and decide how your test should handle that case.
  • The number changes after printing. Content is still loading, a lazy section was not triggered, or a font changed wrapping. Wait for the relevant selector or application state, then measure again.
  • The iframe height is wrong. You measured the parent context. Locate the frame, call switchTo().frame(...), and measure inside it.
  • ClassCastException on the result. Do not cast directly to Long; cast to Number and call longValue().
  • Height grows without end. The site uses infinite scrolling or inserts content on every scroll. Set a pass limit and a business-defined completion condition.
  • Headless and headed values differ. Viewport width changes responsive breakpoints and line wrapping. Set the same window size and device scale assumptions in both runs.

Performance, precision and test design

Reading scrollHeight is a small, synchronous JavaScript operation. The expensive parts are navigation, rendering and any scrolling needed to trigger lazy content. Avoid measuring in a tight loop while the page is mutating; wait for a state transition, then read once.

The value is in CSS pixels, not physical monitor pixels. Browser zoom, device pixel ratio and retina settings do not change the CSS-pixel definition, although responsive layout can change the underlying content. Margins outside the scrolling element are not included, so a visual gap around the page should not be added unless your specification explicitly calls for it.

For a regression test, assert a meaningful range or relationship rather than one universal number. A responsive page can legitimately have different heights at different viewport widths, fonts, locales and logged-in states. Record the URL, viewport, frame context and page-state marker alongside the measurement so a failure can be reproduced.

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 you only need a rendered capture or PDF rather than an in-process Selenium measurement, ScreenshotNeo provides a single HTTP request. Its clean-shot workflow accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.

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.

See the ScreenshotNeo API documentation for all options. A direct call is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The equivalent Python request is:

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)

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

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. Every feature is on every plan: 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

Can I get the page height without scrolling?

Yes. Reading scrollHeight does not require moving the viewport. Scrolling is needed only when interaction triggers additional content such as lazy loading or infinite scrolling.

Does scrollHeight include the browser’s address bar?

No. It measures the web document in CSS pixels, not browser chrome or the operating-system window.

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

Why is the number an integer?

The DOM property is exposed as an integer pixel extent. Selenium’s JavaScript result may still be wrapped as a different Number subtype, which is why the example converts through Number.

Frequently Asked Questions

Can I get the page height without scrolling?

Yes. Reading scrollHeight does not require moving the viewport. Scrolling is needed only when interaction triggers additional content such as lazy loading or infinite scrolling.

Does scrollHeight include the browser’s address bar?

No. It measures the web document in CSS pixels, not browser chrome or the operating-system window.

Why is the number an integer?

The DOM property is exposed as an integer pixel extent. Selenium’s JavaScript result may still be wrapped as a different Number subtype, which is why the example converts through Number.

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

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.