html2canvas vs. PhantomJS vs. Urlbox: A Comparison
Compare html2canvas, PhantomJS, and Urlbox by rendering model, browser support, cross-origin limits, automation, outputs, and cost—and find the right fit for your screenshot workflow.

Short answer: Use html2canvas for an in-browser export when a DOM-based reconstruction is good enough. Keep PhantomJS only for legacy automation that depends on its QtWebKit behavior: its maintainers say development is suspended. For server-side URL or HTML rendering, automation, batch work, or PDFs, use a hosted screenshot service such as Urlbox. If you are choosing a screenshot API today, try ScreenshotNeo first: it removes consent banners, popups, and chat widgets before capture, bills only clean shots, and its paid plans start at $5 for 3,000 shots.
These tools are not three versions of the same thing. html2canvas rebuilds a page from the DOM inside a browser tab. PhantomJS drives an older browser engine. Urlbox runs rendering on a hosted service. The right choice depends chiefly on where the capture happens, how closely it must match the rendered page, and whether you need an API or scheduled automation.
1. At a glance
| Tool | Rendering model | Where it runs | Good fit | Main constraint |
|---|---|---|---|---|
| html2canvas | Recreates an image from DOM and styles | User’s browser | Export button, previews, annotations | Not a literal browser screenshot; CSS and origin limits apply |
| PhantomJS | Headless QtWebKit browser render | Your legacy environment | Existing jobs built around its behavior | Development is suspended |
| Urlbox | Hosted URL/HTML rendering API | Vendor infrastructure | Server-side capture, automation, PDFs, batch work | Hosted-service cost, privacy, and vendor dependency |
| ScreenshotNeo | Hosted screenshot API and MCP server | ScreenshotNeo infrastructure | One-call screenshots, clean captures, AI-agent workflows | Requires an API key for API use |
2. How html2canvas works
html2canvas traverses the loaded page’s DOM, reads available styles and content, then draws a representation into a canvas. It does not ask the browser to photograph the final pixels. Its documentation warns that the result may not be 100% accurate because it reconstructs the page from information available in the DOM.

That makes it useful when the page is already open and the user wants to export a component, dashboard, or same-origin view. It can avoid sending page content to a screenshot vendor. In return, every CSS feature needs library support, and differences from the live browser rendering are possible.
Install and capture an element
For a browser project, install the package with npm and import it into your application:
npm install html2canvas
import html2canvas from 'html2canvas';
const element = document.querySelector('#report');
if (!element) throw new Error('Could not find #report');
const canvas = await html2canvas(element, {
backgroundColor: '#ffffff',
scale: window.devicePixelRatio || 1,
logging: false
});
const link = document.createElement('a');
link.download = 'report.png';
link.href = canvas.toDataURL('image/png');
link.click();
Call the capture after the content is in the DOM and any required data has loaded. The output is a canvas, so you can also pass it to your own upload or preview flow instead of triggering a download. A canvas may be exported as PNG or JPEG with toDataURL; respect browser canvas security rules and size limits.
Relevant options
| Option | What it controls | When it helps |
|---|---|---|
scale |
Canvas pixel density | Raise for sharper output; lower to limit memory and dimensions |
windowWidth, windowHeight |
Viewport dimensions used for rendering calculations | Reproduce a responsive layout at a chosen viewport |
x, y, width, height |
Capture region | Limit output to a specific area |
useCORS |
Attempts CORS-enabled image loading | Use when remote image hosts explicitly permit cross-origin access |
proxy |
Routes image loading through a proxy | Handle remote assets where direct browser access is blocked, if you operate a suitable proxy |
foreignObjectRendering |
Uses an alternate rendering path where supported | Evaluate for pages with content the normal renderer does not represent well |
The data-html2canvas-ignore attribute can exclude an element from capture. For example, put it on a floating toolbar or button that should remain interactive on screen but should not appear in the exported image.
Cross-origin pages and images
html2canvas is client-side and operates under the browser’s same-origin security model. It cannot freely read arbitrary cross-origin page contents. Images from another origin generally need that image server to send appropriate CORS headers and the capture to use useCORS, or they need to be served through a proxy. Setting useCORS: true does not grant permission that the remote server has not granted.
Same-origin iframes can be processed recursively. Cross-origin frames are blocked; sandboxed frames without allow-same-origin also prevent access. If the target is an entire URL outside the current page, html2canvas is the wrong mechanism: it does not run in Node.js because it depends on browser globals such as window and document. Browser extensions should consider the browser’s native screenshot APIs, as the html2canvas FAQ recommends.
3. PhantomJS: a legacy browser renderer
PhantomJS is a scriptable headless browser based on QtWebKit. Unlike html2canvas, it loads and renders a page using a browser engine, so it can capture content outside the current tab and its capture guide describes output including PNG, JPEG, GIF, and PDF. You can set a viewport and a clip rectangle.
The decisive concern for new projects is maintenance: the official PhantomJS homepage says development is suspended until further notice. Its engine and lifecycle make it a poor default when a project needs modern web-platform compatibility, security updates, or ongoing ecosystem support. That recommendation follows from the suspension notice and its QtWebKit architecture.
Legacy capture example
For an existing PhantomJS installation, a minimal script using its documented page API looks like this:
// capture.js — run with an existing phantomjs installation
var page = require('webpage').create();
page.viewportSize = { width: 1280, height: 900 };
page.open('https://example.com', function (status) {
if (status !== 'success') {
console.error('Page load failed');
phantom.exit(1);
return;
}
page.render('page.png');
phantom.exit();
});
phantomjs capture.js
This is a legacy illustration, not a recommendation to add PhantomJS to a new service. A production job also needs explicit handling for page readiness, timeouts, output paths, errors, and process cleanup. Rendering behavior can differ from current browsers because QtWebKit is the engine.
When to keep it
- An established job has known output that depends on PhantomJS-specific rendering.
- You can isolate the binary and its dependencies from public, untrusted input.
- You have representative regression captures and a migration plan.
If those conditions no longer hold, evaluate maintained headless Chromium tooling or a hosted service. Compare output on your own pages: replacing a rendering engine can change fonts, CSS layout, timing, and image behavior.
4. Urlbox: hosted rendering and automation
Urlbox describes its product as an API for converting URLs and HTML into screenshots, PDFs, videos, and extracted text, HTML, and metadata. Its documentation describes embeddable render links as well as synchronous and asynchronous POST requests to a JSON API. The hosted model avoids operating browser processes in your own application and supports use cases such as galleries, archives, thumbnails, responsive checks, Open Graph images, PDF exports, video previews, metadata extraction, and scheduled comparisons.
For exact request fields, authentication, output settings, and response handling, use the Urlbox documentation. The dossier does not specify an endpoint or signing format, so this comparison does not invent a request that may be wrong for your account or API version. The practical integration pattern is:
- Choose the URL or HTML input and output format.
- Configure the render options and authentication exactly as documented for your account.
- Send the request from a backend when credentials or private page data are involved.
- Handle synchronous results or persist the asynchronous job identifier and retrieve its result as documented.
- Record failures and retry only transient errors with bounded backoff.
Urlbox pricing in the research snapshot
The pricing page accessed on 2026-09-29 listed Lo-Fi at $19/month for up to 2,000 renders, Hi-Fi at $49/month for up to 5,000, Ultra at $99/month for up to 15,000, Business at $498/month, and Enterprise from $3,000/month. It also advertised a seven-day free trial for several tiers. Pricing changes; check the current page before budgeting or purchase.
Hosted rendering trades infrastructure work for a recurring service cost and a dependency on a vendor. Consider whether the pages contain credentials, personal data, or content you cannot send to a third party, and verify the service’s current security and retention terms before using it for sensitive URLs.
5. Which tool should you choose?
| Requirement | Recommended direction | Reason |
|---|---|---|
| A user clicks “Export PNG” on a page already open | html2canvas | Runs in the browser without a screenshot backend; accept reconstruction and CORS limits |
| Capture an external URL on a server | Hosted screenshot API | html2canvas cannot fetch and inspect arbitrary pages from Node.js |
| Keep an old job stable while planning a migration | Contain PhantomJS temporarily | Its QtWebKit behavior may be part of the existing output contract; development is suspended |
| Automate PDFs, batch jobs, or scheduled captures | Hosted screenshot API | These workflows require server-side rendering and job orchestration |
| Browser extension capture | Native browser screenshot API | html2canvas’s FAQ points extensions toward native capture APIs |
| AI agent needs screenshots through MCP | ScreenshotNeo | Its MCP server exposes screenshot, page-info, and PDF tools |
For server-side capture, ScreenshotNeo is the first service to try: its clean-capture flow accepts 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, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses identify the page verdict and billing status. It offers a screenshot API and an MCP server for Claude, Cursor, and other MCP clients.
6. Or skip the browser setup
For a server-side screenshot, ScreenshotNeo accepts a URL in one GET request and returns PNG, JPEG, WebP, or PDF. See the API documentation for the available parameters.

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.
7. Reliability, performance, and cost
Performance and output size
With html2canvas, increasing scale multiplies canvas dimensions and memory use. A page with a large full-height dashboard can consume substantial memory even when the visible viewport is modest. The research FAQ gives rough dimension guidance around 32,767 pixels per side for current Chrome/Chromium, Firefox, and desktop Safari; iOS Safari is lower and memory-dependent. Oversized canvases may be blank or partially rendered without throwing an exception. Capture a bounded region, lower scale, or split long content into sections when necessary.
For PhantomJS or a hosted service, the work includes page loading, scripts, fonts, images, and rendering. Reduce unnecessary waits and resources when your output requirements allow it. A hosted service saves you from managing browser processes, but network and page complexity still affect latency; set realistic client timeouts and handle slow pages explicitly.
Reliability practices
- Wait for the content you need, not an arbitrary long delay. For html2canvas, ensure the relevant DOM and images are ready before calling it.
- Use a timeout and a bounded retry policy for remote captures. Retrying a permanently blocked or invalid page will not fix it.
- For legacy PhantomJS, supervise the process and ensure it exits on both success and failure.
- For hosted asynchronous jobs, persist job state and make result retrieval safe to repeat.
- Keep a small set of representative URLs for visual regression checks after changing libraries, browser engines, or capture settings.
Cost and ownership
html2canvas has no per-render vendor charge, but your team owns browser compatibility, CORS workarounds, output quality, and memory limits. PhantomJS similarly shifts ownership to you, with the added maintenance risk of suspended development. A hosted API adds a usage bill but reduces browser infrastructure work. Compare total cost using expected monthly volume, failure and retry rates, operational time, output formats, and the cost of maintaining capture workers.
ScreenshotNeo pricing is Free for 1,000 shots/month with no card; Starter $5 for 3,000; Growth $15 for 15,000; Pro $39 for 60,000; Scale $99 for 250,000; and Business $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Its responses include X-Page-Verdict and X-Billed headers, which help distinguish a clean billed capture from a result that should not be charged.
8. Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
| Remote image is missing or canvas export fails | Cross-origin image lacks CORS permission; canvas becomes tainted | Use an image host that sends CORS headers with useCORS, or a controlled proxy; do not expect the option to bypass browser security |
| Iframe content is absent | Cross-origin or sandboxed frame blocks DOM access | Capture within the frame’s origin, change allowed sandbox policy where appropriate, or use browser/server capture of the URL |
| Styles differ from the live page | DOM reconstruction does not implement every CSS property identically | Check supported CSS behavior, simplify the export view, or use a browser-engine capture where pixel fidelity matters |
| Canvas is blank or partially drawn | Canvas dimensions or memory use exceed platform limits | Lower scale, capture a smaller region, or split the page |
| “window is not defined” in Node.js | html2canvas requires browser globals | Run it in a browser context; use a server-side browser or hosted screenshot API for URL capture |
| PhantomJS output breaks on modern pages | QtWebKit is old and development is suspended | Keep only if legacy fidelity is required; migrate to maintained tooling or hosted rendering and compare captures |
| Remote API request times out | Slow page, large assets, or an overly short client timeout | Set a realistic timeout, reduce unnecessary page work, and retry transient failures with a limit |
| Capture contains a popup or consent layer | The capture system did not dismiss or remove that page element | Use explicit page interactions or a service with consent and overlay cleanup; inspect the returned verdict and billed headers when using ScreenshotNeo |
9. Frequently asked questions
Is PhantomJS still maintained?
No. Its official homepage says development is suspended until further notice. Treat it as a legacy dependency, not a new default.
Can html2canvas capture a cross-origin website?
Not by directly reading an arbitrary cross-origin page. It captures DOM accessible to the current browser context. Remote images need CORS permission or a proxy; cross-origin iframes remain blocked by browser security.
Does html2canvas run in Node.js?
No. It depends on window, document, and computed styles, so it is client-side. Use a browser runtime or server-side rendering tool for URL screenshots.
Which option is best for a dashboard export?
Start with html2canvas if the dashboard is already loaded in the user’s browser and the output can tolerate reconstruction differences. If the result must match browser pixels or include inaccessible external content, use a browser screenshot workflow.
Which option is best for repeated server-side captures?
Use a hosted rendering API if you need to avoid operating browsers and need automation. Compare output formats, job model, privacy terms, and current pricing against your volume before choosing.


