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.

Use PhantomJS to screenshot one DOM element by measuring that element in page.evaluate(), assigning the returned rectangle to page.clipRect, and then calling page.render(). PhantomJS does not provide a selector-based screenshot method; you derive the selector’s coordinates and clip the render to them.

What the workflow does

PhantomJS renders a page with its WebKit layout engine. With no clipping rectangle, page.render() processes the page’s normal render area. Setting page.clipRect limits the rasterized output to a rectangle with top, left, width, and height properties.

The reliable sequence is:

  1. Create a webpage object.
  2. Set page.viewportSize before loading the page so responsive layout is deterministic.
  3. Open the URL and stop if page.open() does not report success.
  4. Run document.querySelector() inside page.evaluate().
  5. Read the selected element’s getBoundingClientRect().
  6. Return only plain geometry data across the PhantomJS page boundary.
  7. Assign that object to page.clipRect.
  8. Render an image after the target is present and its layout is final.

The rectangle is measured in the page context, while clipping is performed by the renderer. That makes viewport size, scroll position, transforms, and late layout changes important implementation details.

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

Complete PhantomJS example

Save this as capture-element.js. Replace the URL and selector with your own values.

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

page.viewportSize = { width: 1024, height: 768 };

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

  var rect = page.evaluate(function (selector) {
    var element = document.querySelector(selector);
    if (!element) {
      return null;
    }

    var bounds = element.getBoundingClientRect();
    return {
      top: bounds.top,
      left: bounds.left,
      width: bounds.width,
      height: bounds.height
    };
  }, '#target');

  if (!rect) {
    console.error('Target element not found');
    phantom.exit(1);
    return;
  }

  page.clipRect = rect;
  page.render('element.png');
  phantom.exit();
});

Run it with the PhantomJS executable:

phantomjs capture-element.js

A successful run writes element.png. PhantomJS capture documentation also describes JPEG, GIF, and PDF output; for a clipped DOM element, PNG is generally the least surprising choice because it preserves sharp edges and transparency where the page supplies it.

How each part works

Set the viewport before opening

page.viewportSize controls the layout width and height used while the page is loaded. A navigation menu, card width, or responsive breakpoint can change the element’s dimensions, so use the same viewport for every capture you need to compare.

Check the navigation status

Do not measure after a failed navigation. The callback’s status should be checked before any DOM query. Exiting with a non-zero code makes failures visible to a shell script or CI job.

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

Pass a selector as a serializable argument

page.evaluate() runs JavaScript in the page context and accepts serializable arguments. Passing '#target' keeps the selector explicit and lets you reuse the same function for other selectors.

Return geometry, not the DOM node

A DOM element is a browser-side object and cannot be returned as a useful value to PhantomJS’s outer script. Return a plain object containing numbers instead. The example deliberately copies the four rectangle properties rather than returning element or the complete DOMRect.

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

Clip and render only after measurement

Assigning page.clipRect does not select an element by itself. It tells the renderer which coordinate rectangle to rasterize. Calling page.render() afterward produces the image for that region.

Choosing and validating the selector

Prefer stable selectors

  • Use an ID when it is unique and intended to identify the component.
  • Use a semantic class or an attribute such as [data-testid="receipt"] when IDs are generated.
  • Use a descendant selector when the same class appears in several components, for example article[data-id="42"] .invoice-total.

document.querySelector() returns the first match. If several elements can match, either make the selector more specific or use querySelectorAll() and choose an index deliberately. A missing match must be handled before assigning clipRect.

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

Reject unusable rectangles

An element can exist but have zero width or height, for example while hidden in a tab. Add a validation check when that matters:

if (rect.width <= 0 || rect.height <= 0) {
  console.error('Target has no visible size');
  phantom.exit(1);
  return;
}

Fractional values are normal when CSS uses percentages or transforms. PhantomJS can rasterize them, but rounding to integer coordinates can make an automation pipeline easier to compare. If you round, round consistently and ensure the resulting width and height remain positive.

Dynamic pages: measure only when the target is ready

page.open() reports navigation status; it does not guarantee that every application-rendered component has finished. A page may fetch the target after the initial load event, replace its contents, or change its size when fonts and images arrive. The official PhantomJS material does not define one universal wait rule for all dynamic sites, so use a condition specific to your page.

Rank #3
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

Wait for a selector

Poll until the element exists, then measure it:

var deadline = Date.now() + 10000;
var timer = setInterval(function () {
  var ready = page.evaluate(function (selector) {
    var element = document.querySelector(selector);
    return !!element && element.getBoundingClientRect().width > 0;
  }, '#target');

  if (ready) {
    clearInterval(timer);
    capture();
  } else if (Date.now() > deadline) {
    clearInterval(timer);
    console.error('Timed out waiting for target');
    phantom.exit(1);
  }
}, 100);

In this pattern, put the rectangle query, clipRect assignment, and render() call in a capture() function. A fixed delay can be useful for a known animation, but a condition is usually less slow and less fragile.

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

Allow layout to settle

If the element resizes after appearing, wait for the page’s own readiness signal or sample its rectangle until it remains stable for the interval your application needs. Images without dimensions, web fonts, transitions, and expanding accordions are common causes of a correct selector with an incorrect final rectangle.

Scroll and transforms

getBoundingClientRect() reports coordinates relative to the viewport. Scroll state and CSS transforms therefore affect the values. Keep the page at a known scroll position before measuring, and verify the output when the target is inside a scrolled container or transformed element. The clipping API defines the rectangle consumed by rendering, but the documentation does not settle every coordinate-space interaction for arbitrary pages.

Element clipping versus manual coordinates

Approach How it works Best fit Main risk
Selector-derived rectangle Select the element, read its bounds, then assign page.clipRect. Pages whose layout changes between viewports or content states. The selector may match the wrong node or the node may move after measurement.
Manual rectangle Set fixed top, left, width, and height values. Static pages with a known, fixed layout. Responsive changes or scroll offsets can capture the wrong region.

Both approaches use the same clipRect renderer feature. Deriving the rectangle from the DOM usually avoids hard-coding coordinates, but it does not remove the need for readiness and coordinate checks.

Output formats and file handling

Use a filename ending in .png, .jpg, or another format supported by your PhantomJS build. PNG is appropriate for UI components, text, and transparent backgrounds. JPEG can be smaller for photographic content but introduces compression artifacts around text. Keep output paths writable and use unique names when several captures run concurrently.

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

For a PDF, PhantomJS’s rendering options differ from an element image workflow; a clipped image is the natural result when the requirement is one DOM component rather than a printable document.

Troubleshooting

“Target element not found”

  • Confirm the selector in the page’s actual DOM, including case and escaping.
  • Check whether the content is inside an iframe; the top-level document cannot query an iframe’s internal DOM without switching context.
  • Wait for client-side rendering instead of measuring immediately after navigation.

The image is blank or incomplete

  • Verify that page.open() returned success.
  • Move the capture after the target’s data, images, and fonts are ready.
  • Check that the rectangle has positive dimensions.

The wrong area is captured

  • Log the returned rectangle and compare it with the selected element in the chosen viewport.
  • Normalize scroll position before measuring.
  • Investigate CSS transforms and nested scrolling containers.
  • Make sure the layout did not change between the query and page.render().

The script exits before the file is written

Call phantom.exit() only after page.render() and after any asynchronous readiness logic. Use phantom.exit(1) for errors so automation can distinguish failure from a successful image.

The selector matches several nodes

querySelector() captures the first match. Narrow the selector, or explicitly select the desired item from querySelectorAll() and return that item’s rectangle.

Reliability checklist

  • Set a fixed viewport for reproducible responsive layout.
  • Check navigation status.
  • Wait for a page-specific readiness condition.
  • Use a stable selector and verify that it matches one intended element.
  • Return only serializable rectangle data from page.evaluate().
  • Reject missing, zero-size, or obviously out-of-range rectangles.
  • Confirm scroll position and inspect transformed or nested content.
  • Render only after the final measurement.
  • Use process exit codes and writable, unique output paths.

PhantomJS’s official references are legacy documentation. The material available for this technique establishes the API behavior described here, but does not establish the project’s current maintenance or security-support status. Assess that separately before introducing PhantomJS into a new production system.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides element capture through a hosted screenshot API, so you do not need to install PhantomJS, manage a browser process, or derive clip coordinates yourself. It can select one element by CSS selector and also supports full-page capture, custom viewports, retina scale, dark mode, waits, custom JavaScript and CSS, headers, cookies, user agents, geolocation, blocking rules, caching, PDFs, bulk capture, and asynchronous jobs.

One GET request returns the image. The API accepts PNG, JPEG, or WebP output; the example below keeps the target URL and selector explicit:

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

In Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://example.com/",
        "selector": "#target",
    },
    timeout=90,
)
r.raise_for_status()
open("element.webp", "wb").write(r.content)

In Node.js:

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com/',
  selector: '#target'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
require('fs').writeFileSync('element.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo documentation for the complete parameter list. Before capture it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and response headers identify the page verdict and billing state. Its 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 with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free. Sign up for the free plan.

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

Frequently Asked Questions

Can PhantomJS capture an element by CSS selector directly?

No. PhantomJS documents clipping a render rectangle, not a selector-specific screenshot API. Select the element in page.evaluate(), return its bounds, and assign those bounds to page.clipRect.

Why should I return top, left, width, and height instead of the element?

The evaluate boundary requires a simple serializable return value. A DOM node is page-context state; numeric geometry is the data the outer PhantomJS script needs.

Will this capture an element taller than the viewport?

The rectangle can describe the element’s measured height, but the result depends on the page layout, scroll state, and PhantomJS renderer behavior. Test tall or dynamically expanding elements rather than assuming full-page behavior.

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.