Comparison
A PhantomJS alternative that is actually maintained
PhantomJS was the go-to headless browser for PDF generation in Node.js and Python projects throughout the early 2010s. Its maintainer stepped down in 2018 and the project has received no security patches since. If your codebase still pulls in phantom, node-phantom, phantom-html-to-pdf, or html-pdf from npm, all of those are wrappers around the same abandoned binary. PDFPipe replaces the entire stack with a single HTTP call.
How they compare
| PDFPipe | PhantomJS | |
|---|---|---|
| Maintenance status | Actively maintained | Abandoned since 2018, no security patches |
| Browser engine | Full modern browser engine | WebKit 534 (circa 2012) |
| CSS support | Grid, flexbox, CSS variables, web fonts | Partial CSS 2.1, limited CSS 3 |
| Deployment | REST API, zero servers to run | Binary process you install and host |
| URL-to-PDF | POST a URL, get a PDF back | Requires scripting a page.open() call |
| SSRF protection | Sandboxed, blocks private and metadata IPs | None |
| Document storage | Optional hosted storage with signed URLs | None |
| Pricing | 500 free documents a month, flat per-document after | Free but you pay for infrastructure |
Before and after
A typical PhantomJS PDF script spins up a child process, writes a script file, waits for it to exit, and reads the output. The PDFPipe version is one fetch call.
Before (phantom-html-to-pdf)
import pdf from "phantom-html-to-pdf";
pdf()("<html><body><h1>Invoice</h1></body></html>", (err, result) => {
if (err) throw err;
result.stream.pipe(fs.createWriteStream("invoice.pdf"));
result.process.kill();
});After (PDFPipe)
const res = await fetch("https://api.pdfpipe.xyz/v1/pdf", {
method: "POST",
headers: { Authorization: "Bearer pp_live_your_key" },
body: JSON.stringify({
html: "<html><body><h1>Invoice</h1></body></html>",
options: { format: "A4" },
}),
});
fs.writeFileSync("invoice.pdf", Buffer.from(await res.arrayBuffer()));Why the npm wrappers are all deprecated
Every PhantomJS npm package (html-pdf, phantom-html-to-pdf, node-phantom, phantom) shells out to the same PhantomJS binary. That binary has not received a security patch since April 2018, does not support modern Node.js ARM builds, and frequently triggers antivirus flags in CI environments. The wrapper maintainers themselves recommend migrating away. PDFPipe removes the binary entirely: your app makes an HTTP request and receives a PDF.
When to stay with a local renderer
If your documents contain highly confidential data that must never leave your network, a self-hosted renderer makes sense. In that case, look at Puppeteer or Playwright with Chromium rather than PhantomJS. For everything else, PDFPipe handles rendering, scaling, and infrastructure so you do not have to.
Try PDFPipe on the live playground with no signup, then read the docs.
See pricing →