What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use PhantomJS’s page.evaluate() after the page finishes loading, and read document.documentElement.scrollHeight. That value represents the document’s complete scrollable height rather than only the visible viewport. Compare it with document.body.scrollHeight when diagnosing unusual layouts, and measure a nested scrolling element if the document itself is not the element that scrolls.
Measure the document after it loads
This complete PhantomJS script opens a URL, evaluates JavaScript inside the page, prints the full document height, and exits with an error when loading fails:
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();
});
The important expression is document.documentElement.scrollHeight. scrollHeight is a DOM measurement of all content in the scrolling document, including content below the currently visible area. The result is a number in CSS pixels.
Why page.evaluate() is required
PhantomJS code outside the page cannot directly use the page’s DOM. page.evaluate() runs a function in the web page’s JavaScript context, where document and its elements exist. PhantomJS transfers back only simple JSON-serializable values, such as numbers, strings, booleans, arrays, and plain objects. DOM nodes, functions, and closures do not cross that boundary.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →#1 Best Overall
Use the callback timing correctly
Measure from the page.open callback after a successful load. Measuring before that callback can return a partial or nearly empty document. If the site inserts content later with JavaScript, waits, or asynchronous requests, add a suitable readiness check before evaluating the height.
Diagnose surprising values with all four measurements
If the reported height looks like the viewport height, return several related values in one evaluation:
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));
Interpret the values as follows:
document.documentElement.scrollHeight: the primary full-document height to try first.document.body.scrollHeight: an alternative document height used by some page structures.document.body.offsetHeight: the body’s border-box layout height, which can expose differences between body layout and scrolling.document.documentElement.clientHeight: the visible client area, generally close to the viewport height. It is not the complete page height.
Compare the two scroll heights and the body offset height. If all values are close to the viewport, first verify that the intended content has loaded. A page can also place its actual content inside a child element with overflow: auto or overflow: scroll; in that case, the child owns the scrollable height.
Measure a nested scrolling container
When the page has an internal scrolling panel, select that element and read its scrollHeight instead of assuming the root document scrolls:
var panelHeight = page.evaluate(function () {
var panel = document.querySelector('.results-panel');
return panel ? panel.scrollHeight : null;
});
console.log(panelHeight);
Replace .results-panel with the site’s selector. A returned null means the selector did not match. This distinction matters for dashboards, modal bodies, chat panes, code editors, and other layouts where the window remains short while an inner element contains the long content.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Set a representative PhantomJS viewport
Responsive pages can produce different DOM structures and heights at different browser dimensions. PhantomJS’s default viewport is commonly described as 400 by 300 pixels; treat that as a build-sensitive diagnostic detail rather than a universal guarantee. Set the viewport before opening the page when you need desktop, tablet, or another specific layout:
var page = require('webpage').create();
page.viewportSize = { width: 1280, height: 800 };
page.open('https://example.com/', function (status) {
if (status !== 'success') {
phantom.exit(1);
return;
}
var height = page.evaluate(function () {
return document.documentElement.scrollHeight;
});
console.log(height);
phantom.exit();
});
The viewport height affects what is visible, while the page’s layout rules determine how content wraps and which responsive components appear. Therefore, record the viewport dimensions alongside a measurement if you need reproducible results.
Wait for content that is loaded after navigation
page.open confirms that navigation completed; it does not guarantee that every lazy image, client-rendered list, or delayed request has finished. A simple fixed delay can help with known page behavior:
Free tools Windows power users keep installed
One-click scans. No signup required.
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;
}
window.setTimeout(function () {
var height = page.evaluate(function () {
return document.documentElement.scrollHeight;
});
console.log(height);
phantom.exit();
}, 1000);
});
Use a delay appropriate to the application, or poll for a selector that indicates the content is ready. A delay is only a timing workaround: it cannot guarantee that a slow or failed request has produced the expected content, so inspect the DOM when accuracy matters.
Height measurement is separate from screenshots and PDFs
Reading scrollHeight answers “how tall is the rendered document?” It does not itself create an image or PDF. PhantomJS’s page.render() renders a page to an image buffer, while clipRect specifies the screen region to capture. Those rendering settings control output, not the DOM value returned by evaluate().
Rank #3
If you need a full-page image, use the measured value as diagnostic information and configure rendering for the target format separately. A screenshot can still be wrong if content was not loaded, if a fixed element overlaps the page, or if the desired content is in a nested scroller.
Common failure modes and fixes
The result equals roughly 300 pixels
This usually indicates the page was measured at PhantomJS’s small default viewport, the document has not populated yet, or the real scrolling element is nested. Set page.viewportSize, wait for the page’s content, and inspect child elements with their own scrollHeight.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →document is undefined
That error occurs when DOM code is executed outside page.evaluate(). Move the DOM-reading function into evaluate and return a serializable value.
document.documentElement.scrollHeight is too small
Compare it with document.body.scrollHeight and document.body.offsetHeight. Then check whether scripts add content after navigation, whether images or fonts change layout later, and whether a child container owns scrolling.
The height changes between runs
Responsive breakpoints, asynchronous content, rotating ads, and delayed layout changes can all affect the result. Fix the viewport, use a deterministic wait condition, and measure at a known point in the page lifecycle.
Rank #4
- 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
The page fails to open
Check the status passed to the page.open callback. Do not evaluate the DOM after a failed navigation. Log the URL and exit nonzero so an automation job can detect the failure.
The value is correct but the image is clipped
A correct DOM height does not automatically change a render’s clipping rectangle or output configuration. Configure the rendering operation independently, and remember that clipRect captures a specified screen region rather than changing document layout.
A reusable diagnostic script
This version combines a controlled viewport, load-status handling, a short wait, and the four-value diagnostic object:
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: ' + status);
phantom.exit(1);
return;
}
window.setTimeout(function () {
var result = page.evaluate(function () {
return {
bodyScrollHeight: document.body.scrollHeight,
bodyOffsetHeight: document.body.offsetHeight,
documentClientHeight: document.documentElement.clientHeight,
documentScrollHeight: document.documentElement.scrollHeight
};
});
console.log(JSON.stringify(result));
phantom.exit();
}, 1000);
});
Use documentScrollHeight as the normal answer, then use the other fields to explain discrepancies. Keep the JSON output in logs when comparing builds or debugging a page that changes over time.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server when you need an image or PDF rather than a PhantomJS DOM measurement. A single request can return PNG, JPEG, WebP, or PDF output. Before capture, it accepts cookie and consent banners like a visitor 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 reports the result in X-Page-Verdict and X-Billed headers.
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 minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11See the ScreenshotNeo documentation for all request options. A basic cURL call is:
Best Value
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 supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or custom viewports, retina scale, PDF paper settings and page ranges, custom HTML/CSS and JavaScript, pre-capture clicks, selector hiding, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agents, Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, an OpenAPI specification, and familiar parameter names for easier migration.
An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Other plans are Starter ($5/3,000), Growth ($15/15,000), Pro ($39/60,000), Scale ($99/250,000), and Business ($249/1,000,000); yearly billing provides two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to start.
Practical checklist
- Set
page.viewportSizebefore navigation when responsive layout matters. - Wait for successful navigation and for client-rendered content that affects height.
- Read
document.documentElement.scrollHeightinsidepage.evaluate(). - Compare body scroll and offset heights when the value looks wrong.
- Inspect nested scrolling elements instead of assuming the root document owns all content.
- Keep DOM measurement separate from screenshot clipping and rendering configuration.
Frequently Asked Questions
What unit does PhantomJS return for scrollHeight?
It returns a numeric CSS-pixel measurement.
Should I use body.scrollHeight or documentElement.scrollHeight?
Start with document.documentElement.scrollHeight, then compare document.body.scrollHeight when diagnosing a page-specific layout.
Can scrollHeight include content in an iframe?
The top document’s measurement does not automatically become the iframe document’s measurement; evaluate inside the relevant frame context and measure that document separately.
Does changing the viewport change the full page height?
It can. Responsive breakpoints and line wrapping may change the rendered layout, so use the viewport that represents the result you need.
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.

