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.
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.
#1 Best Overall
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.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallimport 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:
Rank #2
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:
Recommended Free Tools
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:
Rank #3
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.
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.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #4
Common failures and precise fixes
- Height is only the viewport. You read
clientHeight. Usedocument.scrollingElement.scrollHeight. document.body.scrollHeightis unexpectedly small. The page may scroll the root element, or it may be in standards mode. Usedocument.scrollingElementinstead of hard-codingbody.- 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. ClassCastExceptionon the result. Do not cast directly toLong; cast toNumberand calllongValue().- 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.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.
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.
Best Value
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.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsWhy 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.
Quick Recap
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.

