ScreenshotNeo

BlogComparisons

PhantomJS vs wkhtmltoimage for Web Page Screenshots and PDFs

Compare PhantomJS and wkhtmltoimage for screenshots and PDFs, understand their limits, and plan a workload-based evaluation or migration.

By the ScreenshotNeo team4 October 20269 min read

Short answer: PhantomJS and wkhtmltoimage can both render web pages, but they are not interchangeable. PhantomJS is a scriptable headless browser whose page.render() API supports PDF and several image formats. wkhtmltoimage is a command-line HTML-to-image tool from the wkhtmltopdf project. Both are built around Qt WebKit, and both projects have legacy maintenance status: PhantomJS says development is suspended, and the wkhtmltopdf repository is archived. For new or security-sensitive work, evaluate a maintained browser renderer against your actual pages before choosing either legacy tool.

There is no evidence here that either tool universally produces more accurate screenshots or PDFs. The right choice depends on your required output, page behavior, deployment environment, and the cost and risk of maintaining the renderer.

1. What each tool does

PhantomJS

PhantomJS is a scriptable headless browser based on QtWebKit. Its documented page.render() method can write PDF, PNG, JPEG, BMP, PPM, and, conditionally, GIF. This describes the API’s output options; it does not guarantee fidelity to a current desktop browser. The project homepage states that development is suspended. See the PhantomJS project and its render API documentation.

wkhtmltoimage

wkhtmltoimage is a command-line program in the wkhtmltopdf project for rendering HTML pages to image formats using Qt WebKit. The project repository is archived. Its sibling tool, wkhtmltopdf, targets PDF output; don’t assume wkhtmltoimage itself has the same output controls as PhantomJS’s PDF-capable API. See the archived project repository and the project’s status and technical discussion.

2. Comparison at a glance

Question PhantomJS wkhtmltoimage
How is it driven? Scriptable headless browser API Command-line HTML-to-image renderer
Image output PNG, JPEG, BMP, PPM, and conditional GIF are documented Image output is its stated purpose; verify the formats supported by your exact build
PDF output page.render() documents PDF wkhtmltoimage is the image tool; the project has a separate PDF tool, wkhtmltopdf
Rendering base QtWebKit Qt WebKit
Project status Development suspended Repository archived
Best reason to retain it An existing workflow depends on its scriptable browser API and its outputs meet requirements An existing command-line image workflow is reproducible and passes the pages you need

These project facts do not establish rendering parity, relative speed, or a universal winner. PhantomJS cautions that support for web standards should be detected and tested rather than assumed; check its supported web standards guidance.

3. Choose by workload, not by name

Before selecting or replacing a renderer, make a small representative page set. Include the hardest pages you must support: pages with client-side rendering, custom fonts, SVG or canvas, lazy-loaded images, long content, print styles, and remote assets. Record the expected dimensions, file type, page breaks, and visual details that matter to your use case.

  1. Define the output. Decide whether you need viewport screenshots, full-page images, PDFs, or a mix. Specify image format and quality, PDF page size and margins, orientation, and whether exact pagination matters.
  2. Define page readiness. Determine what must finish before capture: navigation, a known selector, application data, fonts, images, or animations. A fixed delay alone may be unreliable when network or page work varies.
  3. Check browser features. Test the actual CSS, JavaScript, font, SVG, canvas, and image behavior your pages rely on. Do not infer modern feature compatibility from the fact that a tool is a browser renderer.
  4. Check deployment. Verify the exact binary, operating system, required libraries, fonts, sandboxing, and packaging in the environment where it will run. The cited materials do not provide a current compatibility matrix for every build and platform.
  5. Compare outputs and operations. Review representative captures for layout and pagination, then assess whether you can patch, rebuild, isolate, and monitor the renderer over its expected lifetime.

4. Running a basic capture

The following minimal examples show the shape of each tool’s workflow. Exact command options, binary packaging, and output behavior can vary by build; consult the documentation shipped with the version you deploy. These examples are starting points, not proof that a page is fully loaded or rendered identically across environments.

PhantomJS: render a page to PNG

// capture.js
var page = require('webpage').create();
var url = 'https://example.com';

page.viewportSize = { width: 1280, height: 900 };
page.open(url, function (status) {
  if (status !== 'success') {
    console.error('Could not load ' + url + ': ' + status);
    phantom.exit(1);
    return;
  }
  page.render('page.png');
  phantom.exit(0);
});

Run it with the PhantomJS executable and script path: phantomjs capture.js. This minimal callback waits for page opening to finish; applications that load data after navigation may need an application-specific readiness signal before rendering. PhantomJS’s screen capture guide covers capture concepts, and the render API lists supported output formats and options.

PhantomJS: render a PDF

// capture-pdf.js
var page = require('webpage').create();
var url = 'https://example.com';

page.open(url, function (status) {
  if (status !== 'success') {
    console.error('Could not load ' + url + ': ' + status);
    phantom.exit(1);
    return;
  }
  page.render('page.pdf');
  phantom.exit(0);
});

For production documents, validate page size, margins, print CSS, page breaks, fonts, and long-document behavior with the exact PhantomJS build you intend to use. The render API documents PDF output; consult that API for its supported settings rather than assuming controls from another renderer apply.

wkhtmltoimage: render a URL to an image

wkhtmltoimage https://example.com page.png

Use the help output and documentation for your installed binary to inspect its available settings, such as viewport or capture behavior. Do not assume an option exists in every packaged build. If your actual need is PDF output, evaluate the project’s separate wkhtmltopdf tool and compare its output independently.

5. Options and configuration to evaluate

Option names and availability depend on the tool and build. Treat this as a requirements checklist, then confirm each setting in the version-specific documentation before relying on it.

Area What to specify or verify
Viewport and page length Viewport width and height; viewport-only versus full content; behavior for very tall pages
Output Supported image type; quality and compression; PDF page dimensions, margins, orientation, and page breaks
Readiness Navigation completion, selector or application-ready signal, delayed requests, fonts, and image loading
Page behavior JavaScript execution, print styles, animation state, fixed and sticky elements, and lazy content
Assets Remote URLs, redirects, authentication, cookies, local files, fonts, and certificate behavior
Runtime Binary version, OS and libraries, process isolation, timeouts, temporary files, and concurrency

PhantomJS’s documentation explicitly cautions developers to check and test feature support. For both tools, test with your own content and exact binaries rather than copying assumptions from a different Qt/WebKit build.

6. Edge cases that change the result

  • JavaScript applications: Navigation can complete before asynchronous application data appears. Wait for a page-specific condition and fail clearly if it never arrives.
  • Lazy images and infinite scrolling: Content may only load after scrolling or interaction. Decide whether the capture should trigger that behavior, and cap work for unbounded pages.
  • Fonts and remote assets: Missing fonts or blocked requests can change line wrapping and therefore screenshot dimensions or PDF pagination. Confirm asset availability from the renderer’s runtime.
  • Print versus screen layout: PDF output may use print styles and page-breaking rules that differ from screenshot layout. Validate both output types separately.
  • Very long pages: Large page dimensions can consume substantial memory or create unwieldy image files. Prefer a defined viewport, segmented captures, or paginated PDF when those match the requirement.
  • Untrusted URLs: A renderer that visits arbitrary URLs is a server-side network boundary. Restrict destinations and access to internal resources, isolate processes, and apply resource and time limits appropriate to your environment.
  • Build differences: OS libraries, fonts, and packaged Qt/WebKit versions can change behavior. Pin and record the exact runtime and verify it in deployment.

7. Maintenance, security, and migration

PhantomJS’s project says development is suspended, and the wkhtmltopdf repository is archived. That makes maintenance and browser-engine currency important parts of a new system’s decision. It does not establish that every deployed binary has a particular vulnerability or that one replacement is automatically suitable. Assess the exact build, its dependencies, your threat model, and whether updates are available.

For a new pipeline, prototype a maintained browser-based renderer and compare it with representative pages before committing. The wkhtmltopdf status page discusses historical Qt/WebKit limitations and modern browser-based PDF tooling. jsreport recommends moving from its PhantomJS PDF recipe to Chrome-based PDF printing, citing the archived project and potential security issues. These are project recommendations, not a guarantee that Chrome or another browser will reproduce your current output without adjustment. See the wkhtmltopdf status page and jsreport’s PhantomJS PDF recipe.

Migration should be treated as a compatibility project: capture a baseline, implement equivalent page readiness and print behavior in the candidate, compare visual and document outputs, and roll out with a way to detect failures. Include layouts with long text, unusual fonts, and page breaks in the review.

8. Performance, reliability, and cost

The research sources provide no head-to-head benchmark, current operational cost, or reliability rate for these tools. Measure your own workload rather than assuming a winner. Track render duration, memory use, timeouts, failed navigation, output size, and visual regressions across representative pages and deployment conditions.

  • Throughput: Measure cold and warm runs, then vary concurrency carefully. A browser process can consume meaningful memory; set limits from observed behavior in your environment.
  • Reliability: Use explicit timeouts, bounded retries for transient failures, and clear distinction between navigation failure and a valid but unexpected page. Avoid retry loops that amplify a failing upstream site.
  • Reproducibility: Pin the executable and runtime dependencies, record configuration, and keep fonts and other required assets available in deployment.
  • Cost: Include engineering time for maintaining legacy binaries, operating isolated capture workers, diagnosing page changes, and migrating templates. No source here supports a numeric cost comparison.

9. Troubleshooting

Symptom Likely cause What to do
Screenshot is blank or mostly empty Navigation failed, content is rendered later, or required assets did not load Check navigation status and runtime logs; wait for a page-specific ready condition; verify network and asset access.
Text or layout differs from a normal browser Unsupported or differently implemented CSS/JavaScript, missing fonts, or an older engine Reduce the page to a representative case, inspect feature support, ensure fonts load, and test a maintained renderer.
Capture is cut off Viewport capture used where full content was expected, or page dimensions were not configured as intended Confirm viewport and full-page behavior in the exact tool build; test a long page and inspect dimensions.
PDF pagination is wrong Print CSS, page size, margins, font metrics, or page-break rules differ Set and verify document settings supported by the renderer; inspect print styles and compare page boundaries.
Images or fonts are missing Remote request failure, authentication or certificate issue, or capture happened before loading completed Verify access from the renderer host, inspect failed requests where available, and wait for assets or a readiness condition.
Process hangs or times out Long-running JavaScript, stalled network requests, or unbounded page content Apply an overall timeout, constrain page work, log the URL and phase, and fail the job cleanly.
Works locally but fails in deployment Different binary, OS libraries, fonts, permissions, or network policy Compare exact versions and runtime dependencies; package or provision the required assets and reproduce inside the deployment environment.

10. Or skip the browser setup

If you need screenshots from URLs without maintaining a legacy rendering binary, ScreenshotNeo is a managed screenshot API and MCP server from ScreenshotNeo. Its one-call API returns an image or PDF; see the API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms along with newsletter popups and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for 1,000 free screenshots a month, with no card required.

11. Frequently asked questions

Can PhantomJS create PDFs?

Yes. PhantomJS’s page.render() documentation lists PDF among its output formats. Validate print layout and pagination with your exact version and content.

Is wkhtmltoimage the same as wkhtmltopdf?

No. wkhtmltoimage renders pages to images; wkhtmltopdf is the project’s separate PDF tool. Their capabilities and options should be checked independently.

Which is more accurate?

The available evidence does not establish a universal accuracy winner. Compare both, or a maintained candidate, using your own pages and acceptance criteria.

Should I migrate an existing installation immediately?

Not solely based on the project status. Inventory the exact binary and dependencies, assess exposure and support needs, and test a candidate renderer against the layouts and outputs your workflow depends on.

Can either tool guarantee modern browser behavior?

No such guarantee follows from the cited documentation. Feature support depends on the engine and build; test the specific standards and page behaviors you need.