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.

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 rendered document’s scrollable height inside page.evaluate(). The usual starting point is document.documentElement.scrollHeight; compare it with document.body.scrollHeight when a page uses different scrolling conventions. This returns the document height in CSS pixels, not merely the visible viewport.

Minimal working script

page.evaluate() runs JavaScript in the loaded page’s context, where document and the DOM exist. PhantomJS returns simple JSON-serializable values across that boundary, so a number such as scrollHeight can be assigned directly in your PhantomJS script.

var page = require('webpage').create();

page.open('https://example.com/', function (status) {
    if (status !== 'success') {
        console.log('Unable to load the page');
        phantom.exit(1);
        return;
    }

    var height = page.evaluate(function () {
        return document.documentElement.scrollHeight;
    });

    console.log(height);
    phantom.exit();
});

Save the file as height.js and run it with your PhantomJS executable, for example phantomjs height.js. A successful run prints the document’s scrollable height. If the page fails to open, the script exits with status 1 instead of reporting a misleading measurement.

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

Which DOM height should you read?

HTML and CSS allow the document element and the body element to participate differently in scrolling. Measure both when you are diagnosing an unexpected result.

Property What it represents How to use it
document.documentElement.scrollHeight The full scrollable height reported by the root document element. Use as the first measurement for a complete page.
document.body.scrollHeight The body element’s scrollable height. Compare with the root value when layouts or older browser conventions disagree.
document.body.offsetHeight The body’s layout height, including its border box. Diagnostic comparison; it is not always the page’s scrollable height.
document.documentElement.clientHeight The root element’s visible client area. Use to understand the viewport, not as the full-page height.
document.documentElement.scrollHeight versus clientHeight Scrollable extent versus currently visible extent. A page taller than the viewport normally has a larger scrollHeight.

The duplicate root entry in the last row is intentional: comparing scrollHeight with clientHeight is the quickest way to see whether content extends beyond the visible area.

Return a complete diagnostic snapshot

When one number looks too small, return several related values in one evaluation. This avoids guessing which element PhantomJS considers the scrolling element.

var measurements = page.evaluate(function () {
    return {
        bodyScrollHeight: document.body.scrollHeight,
        bodyOffsetHeight: document.body.offsetHeight,
        documentClientHeight: document.documentElement.clientHeight,
        documentScrollHeight: document.documentElement.scrollHeight
    };
});

console.log(JSON.stringify(measurements));

Compare the two scroll heights first. If both are close to the viewport, check loading and viewport size before changing the measurement expression. A large difference between the body and root values indicates that the page’s layout conventions need page-specific handling; keep the value that matches the element actually owning document scrolling.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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

Measure after the content exists

page.open() calls its callback after the navigation result is known, but pages can still add content later through JavaScript. Measuring immediately can therefore capture only the initial layout.

Use a page callback for navigation failures

Always check status. Only evaluate the DOM when it is 'success'; otherwise report the failure and exit nonzero, as in the minimal script.

Allow client-side content to settle

If the page inserts articles, images or other elements after navigation, schedule the measurement after an application-appropriate delay or after a page condition becomes true. The condition and delay are site-specific; the important point is that scrollHeight reflects the layout at the instant you read it.

var page = require('webpage').create();

page.open('https://example.com/', function (status) {
    if (status !== 'success') {
        console.log('Unable to load the page');
        phantom.exit(1);
        return;
    }

    window.setTimeout(function () {
        var height = page.evaluate(function () {
            return document.documentElement.scrollHeight;
        });
        console.log(height);
        phantom.exit();
    }, 1000);
});

The one-second delay is only an example. Replace it with a delay long enough for the target page or use a page-specific readiness signal when you control the application.

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

Set a representative viewport before opening

Responsive CSS can produce a different document height at different browser dimensions. PhantomJS’s viewportSize property sets those dimensions; assign it before page.open().

var page = require('webpage').create();
page.viewportSize = { width: 1280, height: 800 };

page.open('https://example.com/', function (status) {
    if (status !== 'success') {
        console.log('Unable to load the page');
        phantom.exit(1);
        return;
    }

    var height = page.evaluate(function () {
        return document.documentElement.scrollHeight;
    });

    console.log(height);
    phantom.exit();
});

Choose dimensions that represent the audience or screenshot you are automating. The matching technical discussion notes a possible default viewport of 400×300; treat that as a build-sensitive diagnostic detail, not a universal PhantomJS guarantee. A narrow default can trigger mobile or tablet breakpoints and change wrapping, visibility and therefore height.

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

When the document is not the scroller

Some interfaces keep the document itself short and put the long content inside a panel with overflow scrolling. In that case, document-level measurements correctly report the outer page, but not the panel’s content.

var panelHeight = page.evaluate(function () {
    var panel = document.querySelector('.results-panel');
    return panel ? panel.scrollHeight : null;
});

console.log(panelHeight);

Replace .results-panel with the selector for the element that owns the scrollbar. If the selector is absent, return null and handle that case in the PhantomJS script rather than treating it as zero. For a page with several independent scrolling regions, measure each region separately and document which one your downstream process needs.

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

Height measurement is separate from screenshots and PDFs

A DOM measurement answers “how tall is the rendered content?” Rendering answers “which pixels should be output?” PhantomJS’s page.render produces an image buffer, while clipRect selects a screen region for rendering. Those settings do not replace reading scrollHeight. Obtain the height with page.evaluate(); configure rendering or clipping only when you also need an image or PDF.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common failure modes and fixes

  • Only the viewport height is returned. You may be reading clientHeight, or the page may not have finished inserting content. Read document.documentElement.scrollHeight and measure after the relevant content is present.
  • Root and body values differ. Print the diagnostic object and identify which element owns document scrolling. Use the value that matches that layout, rather than assuming one property works for every page.
  • Both values are near 300 pixels. Verify that the intended page loaded, then inspect the viewport. A possible 400×300 PhantomJS default can activate a responsive layout or expose only initial content; set page.viewportSize before navigation.
  • Lazy or asynchronous content is missing. The measurement ran before the page populated it. Wait for a known application condition or use a delay suited to that page, then evaluate again.
  • The page visibly scrolls but the document height is short. Look for a nested scrolling container and read that element’s scrollHeight.
  • page.evaluate() returns an unusable object. Return a number, string, boolean, null, or a plain object containing those values. DOM nodes and JavaScript closures do not cross the page/script boundary as ordinary return values.
  • Navigation reports failure. Keep the status check, log the failure, and do not use a stale or partial measurement. Retry according to your job’s policy only after determining why the page did not load.
  • Different runs produce different heights. Check responsive dimensions, delayed content, advertisements or other injected elements, and whether the page’s data changed between loads. Record the viewport and measurement time with the result.

A production-oriented measurement pattern

This version combines a chosen viewport, navigation validation and a structured result that can be consumed by another process.

var system = require('system');
var page = require('webpage').create();

var target = system.args[1] || 'https://example.com/';
page.viewportSize = { width: 1280, height: 800 };

page.open(target, function (status) {
    if (status !== 'success') {
        console.log(JSON.stringify({
            ok: false,
            url: target,
            error: 'Unable to load the page'
        }));
        phantom.exit(1);
        return;
    }

    window.setTimeout(function () {
        var result = page.evaluate(function () {
            var root = document.documentElement;
            var body = document.body;
            return {
                documentScrollHeight: root ? root.scrollHeight : null,
                bodyScrollHeight: body ? body.scrollHeight : null,
                bodyOffsetHeight: body ? body.offsetHeight : null,
                documentClientHeight: root ? root.clientHeight : null
            };
        });

        console.log(JSON.stringify({ ok: true, url: target, measurements: result }));
        phantom.exit();
    }, 1000);
});

Invoke it as phantomjs measure.js https://example.com/. Keep the viewport, wait policy and selected height field with your stored result so later consumers can reproduce the measurement conditions.

Or skip the browser setup

If your goal is a clean capture rather than maintaining PhantomJS code, ScreenshotNeo provides a GET-based screenshot API. It 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 or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the outcome with X-Page-Verdict and X-Billed headers. It also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.

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

One GET request

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

See the ScreenshotNeo API documentation for authentication, output and options. You can also call the same endpoint from Python or Node.js:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, custom CSS and JavaScript, waits for selectors, delays or network idle, device presets and arbitrary viewports, retina scale, PDF controls, request and resource blocking, headers, cookies, user agents, authorization, timezone and geolocation. It supports caching with a chosen TTL, signed links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage reporting, an OpenAPI specification and familiar parameter names for easier migration.

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

Practical checklist

  1. Set page.viewportSize before navigation when responsive layout matters.
  2. Open the URL and verify a successful status.
  3. Wait for the page’s asynchronous content when necessary.
  4. Evaluate document.documentElement.scrollHeight.
  5. Compare document.body.scrollHeight and body.offsetHeight if the result is surprising.
  6. Measure the nested scrolling element when the document is not the scroller.
  7. Keep DOM measurement separate from page.render and clipRect decisions.

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.