How to Create a PDF of a Web Page with PhantomJS
Use PhantomJS's webpage API to open a URL, check the load status, and render a PDF. Includes a runnable script, layout tips, troubleshooting, and a hosted option.
To create a PDF of a web page with PhantomJS, create a webpage, open the URL, check that loading succeeded, render the page to a filename ending in .pdf, then exit PhantomJS. Save the script below as webpage-to-pdf.js and run it with PhantomJS installed:
var page = require('webpage').create();
var url = 'https://example.com/';
var output = 'page.pdf';
page.open(url, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit(1);
return;
}
page.render(output);
phantom.exit();
});
phantomjs webpage-to-pdf.js
page.open(url, callback) calls the callback with a success or failure status after loading finishes. Check that result before calling page.render. PhantomJS documents PDF as a supported render format. See the page.open API, page.render API, and the official PhantomJS site.
1. Run the supplied rasterize.js example
PhantomJS also documents a command-line example named rasterize.js. It accepts a URL and an output filename, so it is a quick way to try PDF rendering without writing a custom page script:
phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf
The example uses a printable page URL and writes the result to jakarta.pdf. Use this approach when its existing behavior fits your task. Write your own webpage script when you need to control loading, viewport size, or error handling. Both approaches depend on the same PhantomJS project. The example is documented in the official screen-capture guide.
2. Choose a viewport before opening the page
A page may render differently at different browser-window sizes because its layout responds to the viewport. Set page.viewportSize before page.open when you need a particular layout:
var page = require('webpage').create();
page.viewportSize = { width: 1280, height: 900 };
page.open('https://example.com/', function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit(1);
return;
}
page.render('page.pdf');
phantom.exit();
});
The viewport property sets the dimensions used for page layout; it does not promise a particular paper size or page-break behavior. Choose dimensions that produce the layout you want, then inspect the generated PDF. The viewportSize API reference describes the property.
3. Handle pages that finish work after loading
The page.open callback tells you that the page load succeeded or failed. Some sites continue work after that event, such as fetching content or updating the page with JavaScript. The official examples sometimes wait briefly before capturing, but a fixed delay cannot guarantee that every site’s asynchronous content is ready.
When you control the page or know how it signals readiness, wait for that site-specific condition before rendering. If you use a delay, treat it as a pragmatic allowance for that page and verify that the PDF contains the expected content. Do not remove the load-status check: a delay after a failed navigation does not make the page usable.
4. Inspect and validate the PDF
- Run the script from a directory where you can write the output file, or set
outputto a writable path. - Check the process exit status. The example exits with status
1if navigation fails. - Open the resulting PDF and check that the expected page content and responsive layout are present.
- If the page is blank or incomplete, confirm the URL is reachable and investigate whether the site renders important content after the load callback.
The output extension should be .pdf for PDF rendering. PhantomJS’s documented capture example uses this convention.
5. Common problems and fixes
| Symptom | Likely cause | What to do |
|---|---|---|
Unable to load the address! |
page.open returned a failure status. |
Check the URL and whether the host is reachable from the machine running PhantomJS. Keep the status check and avoid rendering after a failed open. |
| No PDF appears | The script may have run from a different working directory, the destination may not be writable, or the render call may not have been reached. | Use an explicit writable output path, confirm navigation succeeded, and check the command’s exit status. |
| The PDF is blank or missing late content | The page may populate content after the initial load event. | Wait for a readiness condition specific to the page where possible. A short fixed delay may help some pages, but is not a general completion guarantee. |
| The page layout is unexpectedly narrow or wide | The viewport used for responsive layout differs from the intended one. | Set page.viewportSize before opening the URL, then render and inspect again. |
The script cannot find webpage or phantom |
The file is being run by a regular JavaScript runtime instead of the PhantomJS command-line executable. | Run it with phantomjs webpage-to-pdf.js in an environment where PhantomJS is installed. |
6. Performance, reliability, and maintenance
Each capture requires PhantomJS to open and render the target page, so page load behavior affects how long the job takes. A fixed wait adds that delay to every capture; use it only when the page needs time beyond the load callback. Reuse a known-good viewport and avoid capturing a page before its required content is ready.
For reliable automation, preserve the load-status check, write output to a known writable location, and validate representative PDFs when changing the target page or viewport. A successful page load is not proof that every late-rendered element is present.
There is also a maintenance consideration: the current official PhantomJS homepage says, “Important: PhantomJS development is suspended until further notice.” PhantomJS can still be relevant for maintaining an existing workflow, but account for the project’s suspended development when selecting a tool for a new system. No current-browser compatibility or head-to-head comparison is implied here. See the official project notice.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a screenshot or PDF. For example, this cURL request saves a PDF:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-d format=pdf \
-o page.pdf
See the ScreenshotNeo API documentation for the available parameters. Python and Node.js examples are also available:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com", "format": "pdf"},
timeout=90,
)
r.raise_for_status()
open("page.pdf", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com',
format: 'pdf'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
await Bun.write('page.pdf', res);
- Cookie and consent banners, newsletter popups, and chat widgets are removed before the capture; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. The response identifies the page verdict and billing status in headers.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Can PhantomJS render a web page directly to PDF?
Yes. Its documented page.render workflow supports PDF output. Open the page, check the result, then render to a PDF filename.
Should I use a custom script or rasterize.js?
Use rasterize.js for the documented command-line example. Use a custom script when you need to set the viewport or handle load failure explicitly.
Is PhantomJS still being developed?
The official homepage says development is suspended until further notice. Consider that maintenance status when choosing it for a new workflow.


