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

The usual fix is to set both properties that PhantomJS uses for different jobs: assign page.viewportSize before loading the page, then assign a matching page.clipRect immediately before page.render(). The viewport controls browser layout; the clip rectangle controls the pixels written to the image. Setting only the viewport does not guarantee a viewport-sized file.

Why the screenshot is taller than the visible page

PhantomJS has two separate dimensions in this workflow. page.viewportSize defines the headless browser’s viewport—the width and height used while the page lays itself out. page.clipRect defines the rectangle that page.render() copies into the output image. They are related, but one does not replace the other.

If you set a viewport but leave the capture bounds unrestricted, the rendered image can include content below the fold. That produces a tall screenshot even though the browser viewport itself has the expected height. A tall result is therefore not automatically a page-layout error: it may simply be a capture rectangle that extends farther than the visible browser area.

There are two legitimate goals:

Goal Configuration Expected height
Viewport-only image Set the desired viewport, then set clipRect to top: 0, left: 0, and the same width and height. Exactly the clip rectangle’s height, subject to the image format and renderer.
Full-page image Use the intended viewport for layout, but do not constrain the capture to a viewport-sized rectangle. Tall enough to include content below the fold.

Decide which output you need before changing the script. Cropping the rectangle is correct for a browser-window mock-up, above-the-fold preview, or fixed-size visual test. It is wrong when the purpose is to preserve the entire document in one image.

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

Fix a viewport-sized PhantomJS screenshot

Set the viewport before page.open(), so responsive layout is calculated at the intended dimensions. After the page reports a successful load, set a clip rectangle with the same dimensions and render.

var page = require('webpage').create();
var width = 1024;
var height = 768;

// Controls browser layout and the visible viewport.
page.viewportSize = {
  width: width,
  height: height
};

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

  // Controls the pixels included in the screenshot.
  page.clipRect = {
    top: 0,
    left: 0,
    width: width,
    height: height
  };

  page.render('screenshot.png');
  phantom.exit();
});

The 1024 × 768 values are example dimensions. Replace both pairs with the output size you actually require. Keeping the values in variables prevents a silent mismatch in which the browser lays out at one size while the capture rectangle uses another.

Why the order matters

  1. Create the page. The webpage module supplies the page object.
  2. Assign viewportSize. Do this before opening the URL so the page’s responsive rules see the desired viewport during loading.
  3. Check the load status. Do not render an error page or incomplete navigation as if it were a successful capture.
  4. Assign clipRect. Use zero for top and left when you want the rectangle to begin at the viewport’s upper-left corner.
  5. Render and exit. The rectangle must be assigned before page.render(); changing it afterward cannot alter the already-written file.

When a tall image is the correct result

A full-page capture intentionally includes material below the fold. In that case, a viewport-sized clipRect defeats the goal by cutting off the document. Keep the viewport assignment for layout consistency, but omit the bounded rectangle used for viewport-only output and render the page according to your full-page capture design.

Do not judge a full-page image by the height of the browser viewport. The viewport is the window through which the page is viewed; a full-page capture is a larger canvas containing content that the window does not show at once.

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

Diagnose a result that still has the wrong dimensions

If the image remains too tall after you add a matching rectangle, verify the capture itself rather than assuming a universal PhantomJS defect. The available API behavior does not establish one secondary cause for every page, so check these concrete points in order.

Print the values used for capture

Log width, height, and every page.clipRect field immediately before page.render(). A stale variable, a later assignment, or a typo in a property name can leave the renderer using different bounds from the ones you intended.

Confirm the assignment occurs before render

PhantomJS renders the current page state at the moment page.render() runs. If asynchronous code sets the rectangle after that call, it has no effect on the file already created. Put the assignment in the successful page.open callback or in the later callback you use for your own readiness check.

Check which page or frame is being rendered

Complex scripts can navigate, create frames, or retain more than one page object. Make sure the object receiving clipRect is the same object on which you call render(), and that it contains the document you inspected. A correct rectangle on a different page object cannot fix the output.

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

Separate capture size from page content

Inspect the output dimensions independently of how much content is visible in the image. If the file has the rectangle’s dimensions but appears to contain unexpected content, the sizing problem is solved and the remaining issue is page state, navigation, or layout. If the file dimensions themselves are wrong, return to the rectangle values and call order.

Common mistakes and their fixes

Symptom Likely configuration mistake Fix
Image is taller than the visible browser area. Viewport set, but no bounded clipRect. Set a rectangle whose width and height match the intended viewport.
Top or left edge is offset. Rectangle starts at a nonzero coordinate. Use top: 0 and left: 0 for a viewport-origin capture.
Dimensions change between runs. Different variables or late assignments are used on different paths. Define one width and height pair and assign the rectangle immediately before rendering.
Image shows an error or incomplete page. Rendering occurs without checking status. Handle a non-success status and exit with an error instead of saving the result.
Rectangle appears correct, but content is from another document. A different page object or frame is rendered. Trace the object receiving clipRect through to the render() call.
Below-the-fold content is missing. A viewport-sized rectangle was used for a full-page requirement. Remove that bounded rectangle and use a full-page capture approach instead.

Choosing dimensions for repeatable captures

  • Use explicit integers. Keep width and height in variables and reuse them for both properties.
  • Set layout dimensions before navigation. Responsive breakpoints are evaluated while the document loads.
  • Set capture dimensions after navigation succeeds. This keeps the rectangle tied to the page object you actually intend to save.
  • Keep the objective stable. A viewport preview and a full-page archive are different products; use separate scripts or clearly named modes rather than changing one rectangle ad hoc.
  • Validate the output file. Check its pixel dimensions after each configuration change so visual appearance does not substitute for a size check.

Performance and reliability considerations

A bounded rectangle limits the number of pixels written for a viewport screenshot, while a full-page image necessarily grows with the document. That difference affects file size and the time required to encode and transfer the result. It does not change the distinction between layout and capture bounds: both modes still need an intentionally chosen viewport.

Load status is a minimum reliability check, not a guarantee that every page element has finished its own asynchronous work. If your page has additional readiness logic, place the clipRect assignment and render call after that logic, while retaining the same object and dimensions. The sources establish the viewport/rectangle behavior, but they do not provide a universal wait recipe for every application.

Or skip the browser setup

If you only need an image or PDF from a URL, ScreenshotNeo provides a single-request screenshot API and an MCP server for AI clients. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps 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.

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

For a direct image request, see the ScreenshotNeo documentation for the current parameters and response details.

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

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

ScreenshotNeo also supports full-page captures with lazy images loaded, CSS-selector element captures, dark mode, device presets and custom viewports, retina scale, PDF paper and margin controls, custom CSS or JavaScript, pre-capture clicks, selector hiding, selector/delay/network-idle waits, request and resource blocking, custom headers and cookies, user-agent and authorization values, timezone and geolocation, transparent backgrounds, resizing, TTL-based caching, signed 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. Every plan includes every feature. The Free plan includes 1,000 shots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

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

FAQ

Does viewportSize automatically crop the output?

No. It sets the browser viewport. The capture bounds are controlled separately by clipRect.

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

Should I use clipRect for every screenshot?

Use it when you need a fixed, viewport-sized result. Do not use a viewport-sized rectangle when the requirement is a full-page image.

What do the example 1024 × 768 values represent?

They are documentation-style example dimensions, not a required PhantomJS size or a measured limit.

What if the page loads successfully but the screenshot is still incomplete?

Keep the same viewport and rectangle logic, then place rendering after the page-specific readiness condition you require. A successful navigation status alone does not describe every page’s asynchronous content.

Frequently Asked Questions

Can a CSS rule make the PNG file itself taller?

CSS can change the document’s layout, but the output dimensions still come from the capture rectangle used at render time. Verify that rectangle first.

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

Is a full-page screenshot the same as increasing the viewport height?

No. Increasing the viewport changes layout and the visible browser area; a full-page capture preserves content below the fold without treating the entire document as the viewport.

The Bottom Line

For a screenshot that matches the visible PhantomJS viewport, set page.viewportSize before navigation and a zero-origin page.clipRect of the same dimensions before page.render(). A tall image is expected only when the capture is allowed to include content below the fold.

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.