A PhantomJS alternative for screenshots & PDFs

PhantomJS was the first headless browser most of us used, and plenty of production systems still call phantomjs rasterize.js. But development was suspended in 2018 once headless Chrome shipped, the GitHub repository is archived, and its QtWebKit engine predates flexbox fixes, CSS grid and ES2015 JavaScript.

Symptoms you've outgrown it

The replacements, honestly compared

OptionGood for / trade-off
Puppeteer (Node)Closest to the PhantomJS scripting model, same engine as Chrome.
You run and patch headless Chromium (~300MB, memory spikes, fonts).
Playwright (Node, Python, Java, .NET)Chromium, Firefox and WebKit; great for test suites (CasperJS users).
Same operating burden as Puppeteer.
A hosted API (Shotmint, ScreenshotOne, Urlbox, …)Screenshots and PDFs with one HTTP call from any language, nothing to install.
Costs per render; no multi-step scripted flows (logins, clicks).

If your PhantomJS scripts drive tests or click through pages, move them to Playwright. If they only turn a URL or HTML into a PNG or PDF (which is what most rasterize.js setups do), an API call replaces the whole binary.

Before and after

// Before: rasterize.js (run with: phantomjs rasterize.js URL out.png)
var page = require("webpage").create();
var system = require("system");
page.viewportSize = { width: 1280, height: 800 };
page.open(system.args[1], function (status) {
  window.setTimeout(function () {
    page.render(system.args[2]);
    phantom.exit();
  }, 500);
});
# After: one HTTP call (Chromium). PhantomJS captured the full page by default.
curl -G https://shotmint.creasework.com/v1/screenshot \
  -H "X-API-Key: $SHOTMINT_KEY" \
  --data-urlencode "url=https://example.com" \
  -d width=1280 -d full_page=true -d delay=500 \
  -o out.png

Node.js

const params = new URLSearchParams({ url: "https://example.com", width: "1280", full_page: "true" });
const r = await fetch("https://shotmint.creasework.com/v1/screenshot?" + params, {
  headers: { "X-API-Key": process.env.SHOTMINT_KEY },
});
if (!r.ok) throw new Error(await r.text());
require("fs").writeFileSync("out.png", Buffer.from(await r.arrayBuffer()));

Python (PDF, replacing page.paperSize)

import os, requests
r = requests.get("https://shotmint.creasework.com/v1/pdf",
    headers={"X-API-Key": os.environ["SHOTMINT_KEY"]},
    params={"url": "https://example.com", "format": "A4", "margin": "1cm"}, timeout=60)
r.raise_for_status()
open("out.pdf", "wb").write(r.content)

Option mapping

PhantomJSShotmint
page.viewportSize = {width, height}width, height
page.render() (whole page by default)full_page=true (without it you get just the viewport)
page.clipRect = {top, left, width, height}selector=#element to capture one element, or width/height for the top of the page
page.zoomFactor = 2device_scale_factor=2 (sharp retina output, not just scaled)
page.render(f, {format: "jpeg", quality: "80"})format=jpeg (or webp), quality=80
page.render("out.pdf") with page.paperSize = {format, orientation, margin}/v1/pdf with format, landscape=true, margin
page.settings.userAgentuser_agent
window.setTimeout(render, ms)delay=ms, or wait_until=networkidle
page.content = html / page.setContent()html in a POST body
page.evaluate() to hide elementshide_selectors=.cookie-banner,#chat
paperSize.header / footer callbacksNot supported. Put them in your HTML; a <thead> repeats on every page

Migration gotchas

Want to compare the output first? Try the free full-page screenshot tool or URL to PDF (no key needed). Moving off a different stack? See the wkhtmltopdf and Puppeteer guides.

What it costs

One screenshot or PDF = one credit. €5 buys 2,000 renders, credits never expire and there's no subscription. Failed renders are refunded automatically.

Try it with 100 free renders

No signup, no card. Get a key in one click, then buy credits only if you need more (from €5 for 2,000, never expire).

Get a free API key Full API reference