Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Short answer: create a PhantomJS WebPage, size its viewport, open the visualization, wait for a page-specific ready signal (or, less reliably, a delay), render the page, and exit. This works for pages rendered with HTML/CSS, SVG, images, and Canvas, but PhantomJS is no longer developed. The project says, “Important: PhantomJS development is suspended until further notice,” and its GitHub repository has been archived read-only since May 30, 2023. Treat the procedure below as a legacy technique for an existing PhantomJS environment, not a recommendation for new browser automation.
What PhantomJS can—and cannot—capture
PhantomJS uses a WebKit-based headless browser. Its documented screen-capture scope includes HTML styled with CSS, SVG, raster images, and Canvas, which covers many chart implementations. The render() API writes the current rendered page to a file. Supported documented output formats are PDF, PNG, JPEG, BMP, and PPM; GIF availability depends on the Qt build. The filename extension normally selects the format, while PNG and JPEG quality options can be configured through the API.
Those capabilities do not prove compatibility with every current chart library, JavaScript bundle, font, cross-origin request, or website. Modern frameworks may depend on browser features absent from PhantomJS’s older WebKit. Validate the exact page in your own runtime, and keep a maintained browser automation tool as the safer choice for new projects.
Prerequisites and a minimal script
- A PhantomJS executable available on your PATH (or an absolute path to it).
- A URL that can be loaded by the runtime without interactive authentication, unless you add the required page settings and credentials.
- A writable output directory.
Save this as capture.js. Replace the URL and readiness selector with values from the visualization page.
#1 Best Overall
var webpage = require('webpage');
var page = webpage.create();
page.viewportSize = { width: 1440, height: 900 };
var url = 'https://example.com/dashboard';
page.open(url, function (status) {
if (status !== 'success') {
console.error('Page open failed: ' + status);
phantom.exit(1);
return;
}
// Prefer a page-specific readiness check; see the next section.
var deadline = Date.now() + 30000;
function waitForChart() {
var ready = page.evaluate(function () {
return !!document.querySelector('[data-chart-ready="true"]');
});
if (ready) {
page.render('chart.png');
phantom.exit();
return;
}
if (Date.now() >= deadline) {
console.error('Chart readiness timeout');
phantom.exit(2);
return;
}
setTimeout(waitForChart, 250);
}
waitForChart();
});
Run it with phantomjs capture.js. A successful page.open() callback means the page load was reported as successful; it does not mean asynchronous data, chart construction, fonts, or animations have finished.
Wait for the visualization, not merely the document
Best option: expose a readiness condition
If you control the page, set an attribute or element after the final data has been drawn:
// Application code, after data and rendering complete
chartContainer.setAttribute('data-chart-ready', 'true');
The capture script can then poll that condition with page.evaluate(). Evaluation runs inside the page context, so values and functions are not automatically shared with the PhantomJS script. Return serializable values, and keep browser-only DOM work inside the callback.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Check a chart-specific DOM or SVG state
When no explicit flag exists, inspect a stable element: an SVG with a known number of paths, a canvas whose dimensions are non-zero, a “loaded” class, or a data label that appears only after the request completes. Avoid selecting a transient spinner or an element that exists before data arrives.
var ready = page.evaluate(function () {
var svg = document.querySelector('#sales-chart svg');
var canvas = document.querySelector('#sales-chart canvas');
return !!(svg && svg.querySelectorAll('path').length > 0) ||
!!(canvas && canvas.width > 0 && canvas.height > 0);
});
Fallback: a fixed delay
PhantomJS’s Quick Start demonstrates waiting with setTimeout before rendering. A delay is easy, but it is a heuristic: on a slow network it may capture an empty chart, while on a fast network it wastes time. Use a deadline and report a timeout rather than silently producing a misleading image.
Rank #2
setTimeout(function () {
page.render('chart.png');
phantom.exit();
}, 5000);
Control dimensions and the capture region
Viewport size
Set page.viewportSize before opening the page when responsive layout affects the chart. The page may choose different labels, legends, or breakpoints at different widths.
page.viewportSize = { width: 1920, height: 1080 };
Viewport height controls the visible browser area. It does not automatically make a long page a full-page image.
Recommended Free Tools
Clip one region
Use page.clipRect when you need only the chart or a dashboard panel. Coordinates are page pixels relative to the viewport.
page.clipRect = { top: 120, left: 80, width: 1100, height: 650 };
page.render('sales-panel.png');
Calculate the rectangle from the element’s bounding box when layout is stable:
var rect = page.evaluate(function () {
var el = document.querySelector('#sales-chart');
if (!el) return null;
var r = el.getBoundingClientRect();
return { top: r.top, left: r.left, width: r.width, height: r.height };
});
if (!rect) { console.error('Chart element not found'); phantom.exit(3); }
else {
page.clipRect = rect;
page.render('chart-only.png');
phantom.exit();
}
Output formats and quality
Choose the extension that matches your downstream use: PNG for lossless labels and transparent-looking edges where supported by the page, JPEG for smaller photographic output, PDF for document workflows, and BMP or PPM when your pipeline requires them. The documented API exposes JPEG and PNG quality settings. Keep the extension and quality setting consistent with the consumer that will open the file, and remember that GIF support is build-dependent.
Rank #3
Complete workflow with status, readiness, and errors
- Create the page with
require('webpage').create(). - Set
viewportSize; setclipRectonly if a region is required. - Call
page.open(url, callback). - Stop immediately when the callback status is not
success. - Poll a real chart-ready condition with
page.evaluate(). Use a bounded delay only when the page offers no observable condition. - Call
page.render(filename)after the visualization is ready. - Call
phantom.exit()after rendering and any logging are complete.
Troubleshooting
Status is fail
Check the URL, DNS, TLS compatibility, redirects, and whether the page requires authentication. Log the URL and status, then exit with a non-zero code so scheduled jobs detect the failure. A successful status cannot compensate for a page that later fails its API request.
Free tools Windows power users keep installed
One-click scans. No signup required.
The image is blank or shows a spinner
The capture ran before asynchronous data arrived. Replace a fixed delay with a selector, attribute, SVG node count, or other state that proves rendering completed. Increase the deadline only after confirming the page is simply slow; otherwise investigate JavaScript errors and blocked requests.
The chart is cropped or uses the wrong layout
Set the viewport before page.open(). Check responsive breakpoints and verify clipRect coordinates against the viewport. For a full dashboard, omit clipping and use a viewport that matches the intended composition.
Text or fonts differ
Fonts may load after the chart appears or may not be available to the legacy WebKit engine. Wait for a page signal that includes font readiness when possible, bundle a dependable fallback, and compare output from the exact PhantomJS/Qt build used in production.
Modern JavaScript fails
PhantomJS’s old WebKit may not implement syntax or APIs required by a current application. Transpiling the application can help only when the underlying browser APIs are also available. If the page depends on unsupported features, use a maintained browser automation runtime instead of trying to patch the capture script.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Animations produce inconsistent frames
Wait for an application-level “animation complete” signal, disable animation in the page’s test configuration, or capture after a deterministic state transition. A timer alone can land between frames.
Reliability, scheduling, and cost considerations
Make captures deterministic: pin the PhantomJS version and Qt build, set an explicit viewport, use a bounded readiness timeout, and return non-zero exit codes for load or readiness failures. Store logs alongside output so a missing chart is distinguishable from an empty but valid visualization. If the page changes frequently, maintain a small canary URL and review it after application or browser updates.
PhantomJS itself does not provide a hosted queue, retry service, usage accounting, or a guarantee that a third-party site will remain compatible. Any retries, concurrency limits, storage, and alerting must be implemented by your job runner. Do not treat the Quick Start’s illustrative delay or page-load example as a performance benchmark.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step 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. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Use the API documentation at https://screenshotneo.com/docs/. The same request can return PNG, JPEG, WebP, or PDF:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Other options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page ranges, custom CSS or JavaScript, pre-capture clicks, selector hiding, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.
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, and every feature is available on every plan. Create a free ScreenshotNeo account and start with the monthly allowance.
Frequently Asked Questions
Does page.open() wait for chart data?
No. Its callback reports page-load status; asynchronous data and visualization readiness require a separate condition or bounded wait.
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 reinstallCan PhantomJS capture an SVG chart?
The documented capture scope includes SVG, along with CSS, images, and Canvas, but individual modern sites and libraries may still be incompatible with its legacy WebKit.
How do I capture only the chart instead of the whole page?
Set page.clipRect to the chart’s page-pixel rectangle, optionally deriving coordinates with getBoundingClientRect() inside page.evaluate().
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.

