How to Use PhantomJS Screenshot Scripts in AWS Lambda
Run a legacy PhantomJS screenshot script in Lambda with careful packaging, or use a maintained browser approach. Learn the limits, deployment steps, and failure fixes.
PhantomJS can run in AWS Lambda only if you supply an executable built for the Lambda operating system and architecture, along with its required libraries. AWS supports ZIP packages and container images, but its documentation does not certify any PhantomJS binary or old Lambda layer for a current runtime. PhantomJS is legacy software: its project says development is suspended. Treat this as a migration or compatibility-validation task, not a currently supported recipe. PhantomJS project
If you need to preserve an existing script, package it and validate the exact artifact on the selected Lambda runtime. If this is a new screenshot service, evaluate a maintained Chromium-based approach or use a screenshot API such as ScreenshotNeo.
1. Understand what Lambda must run
PhantomJS is a separate executable that runs a JavaScript file; it is not a browser API built into Node.js. Its documented command shape is phantomjs [options] somescript.js [args...], and the CLI guide covers PhantomJS 2.1.1. That is a version reference in legacy documentation, not evidence of a current supported release. PhantomJS command-line documentation
The basic capture sequence is to create a webpage, open a URL, render after the open callback, then exit. The capture guide shows viewport and clip rectangle controls, and documents PNG, JPEG, GIF, and PDF output. PhantomJS screen capture guide
2. Write or adapt the PhantomJS script
This example accepts the target URL and output path as command-line arguments. It sets a viewport and writes a PNG once page.open() reports success. Save it as capture.js.
var page = require('webpage').create();
var system = require('system');
var url = system.args[1];
var outputPath = system.args[2] || '/tmp/screenshot.png';
if (!url) {
console.error('Usage: phantomjs capture.js <url> [output-path]');
phantom.exit(2);
}
page.viewportSize = { width: 1440, height: 900 };
page.open(url, function (status) {
if (status !== 'success') {
console.error('Could not load URL: ' + url);
phantom.exit(1);
return;
}
page.render(outputPath, { format: 'png' });
console.log(outputPath);
phantom.exit(0);
});
Run locally with a compatible PhantomJS executable using phantomjs capture.js https://example.com /tmp/screenshot.png. This command illustrates the documented CLI shape; it does not assert that a particular binary works on Lambda.
The callback indicates that the page-open operation completed, but it does not prove a modern single-page app has finished loading its data, fonts, or animations. Where the script needs a page-specific readiness condition, add one based on the page’s actual behavior. Do not assume a fixed delay is correct for every site.
3. Choose a Lambda package format
Choose the Lambda operating system/runtime and CPU architecture before sourcing or building the executable. Confirm the binary architecture, shared libraries, executable permissions, and runtime dependencies. A binary that works on a developer machine can still fail in the Lambda environment.
| Deployment | What it provides | Constraint to check |
|---|---|---|
| ZIP package and optional layer | Package the function code, script, executable, and dependencies together or split dependencies into a layer. | Combined unzipped package contents, including layers, have a 250 MB maximum. |
| Container image | More control over the build and runtime environment. | Uncompressed image size can be up to 10 GB. You still must verify the executable against the chosen Lambda runtime and architecture. |
These are AWS service limits, not recommended PhantomJS package sizes or proof of compatibility. Check the current AWS Lambda quotas before publishing or deploying; quotas can change.
ZIP deployment checklist
- Build or obtain a Linux PhantomJS binary for the selected Lambda architecture and verify all required shared libraries are available.
- Include the executable,
capture.js, and any required dependencies in the deployment package or a compatible layer. - Ensure the executable has execute permission in the packaged artifact.
- Invoke the executable from the function and send output to a writable temporary path such as
/tmp/screenshot.png. - Return the image in the response or persist it to object storage before the invocation environment is reused or discarded.
- Deploy and validate the actual package on the target Lambda runtime. Packaging success alone does not prove the browser can start or render.
Container image checklist
- Choose a Lambda-compatible base and target architecture deliberately.
- Install the executable and its shared libraries in the image, then set permissions and paths explicitly.
- Configure the image entry point and handler according to the Lambda container-image contract.
- Run an invocation on the deployed Lambda configuration and inspect startup errors, output files, and logs.
A container offers build control, not automatic browser compatibility. AWS describes supported packaging approaches and quotas, but the cited documentation makes no PhantomJS compatibility promise. AWS container images
4. Invoke PhantomJS from a Lambda function
The following Node.js handler shows the process boundary and temporary output path. It assumes you have already placed a verified executable and script at /opt/bin/phantomjs and /var/task/capture.js. The paths are packaging choices; change them to match your artifact. This is a deployment template, not a claim that an unspecified PhantomJS binary will run on every Lambda runtime.
const { execFile } = require('node:child_process');
const { promisify } = require('node:util');
const { readFile } = require('node:fs/promises');
const execFileAsync = promisify(execFile);
exports.handler = async (event) => {
const url = event && event.url;
if (typeof url !== 'string' || !/^https?:\/\//i.test(url)) {
return { statusCode: 400, body: 'Provide an http or https URL.' };
}
const outputPath = '/tmp/screenshot.png';
try {
await execFileAsync('/opt/bin/phantomjs', [
'/var/task/capture.js', url, outputPath
], { timeout: 60000, maxBuffer: 1024 * 1024 });
const image = await readFile(outputPath);
return {
statusCode: 200,
headers: { 'content-type': 'image/png' },
isBase64Encoded: true,
body: image.toString('base64')
};
} catch (error) {
console.error('PhantomJS capture failed', error);
return { statusCode: 502, body: 'Screenshot capture failed.' };
}
};
Returning a base64 image is suitable only when the response path and payload limits fit your use case. For larger images or asynchronous jobs, store the file in object storage and return a reference. Avoid passing arbitrary shell strings to a shell; this example uses execFile with separate arguments.
5. Configure resources and output handling
Lambda allows memory from 128 MB to 10,240 MB, an ordinary function timeout up to 900 seconds, and configurable /tmp storage from 512 MB to 10,240 MB. These are upper and lower service limits, not suggested PhantomJS settings. Set memory, timeout, and temporary storage based on measurements of your own pages and package. AWS Lambda quotas
- Memory: measure browser startup and rendering for representative pages, including heavy pages. Increase only as needed and observe duration and failures.
- Timeout: allow for browser startup, page navigation, rendering, and output persistence. Handle a timed-out child process as a failed capture.
- Temporary storage: keep screenshots and temporary browser files under writable temporary storage; size it for concurrent files and page behavior.
- Output: make persistence part of the invocation. Temporary files are not durable storage.
- Concurrency: account for simultaneous invocations and downstream storage or destination limits. A warm environment may be reused, so use unique output names if files could overlap.
6. Decide whether to keep PhantomJS or migrate
Keep a legacy script only when its current output and behavior are acceptable and you can validate the exact binary in your deployment environment. PhantomJS development is suspended, which is a maintenance and security consideration. PhantomJS project status
For a new implementation, evaluate a Chromium-based serverless browser and verify the exact project and browser build you intend to deploy. The serverless-chrome repository describes Lambda scaffolding and screenshot examples, but it does not certify current package maintenance or compatibility for a particular build. serverless-chrome repository
| Decision factor | Keep PhantomJS | Evaluate Chromium automation |
|---|---|---|
| Maintenance posture | Project development is suspended. | Check the selected project’s current maintenance status. |
| Compatibility | Validate the binary, libraries, architecture, and target pages. | Validate the chosen browser build and Lambda environment. |
| Deployment footprint | Measure ZIP/layer contents or container size. | Measure browser and dependency size against the same limits. |
| Migration effort | Existing PhantomJS page APIs may remain in place. | Port and verify page setup, readiness logic, and screenshot output. |
| Performance and fidelity | Measure startup, render duration, memory, and output for real pages. | Measure the same cases; the available sources provide no comparative benchmark. |
7. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
Exec format error |
The executable targets a different operating system or CPU architecture. | Inspect the binary architecture and rebuild or obtain a binary matching the selected Lambda environment. |
No such file or directory although the binary exists |
A required dynamic loader or shared library is missing, or the configured path is wrong. | Check the binary’s linked libraries in the target environment and package the required dependencies; verify the executable path. |
Permission denied |
The executable bit is missing or the path cannot be executed. | Preserve executable permissions in the ZIP/image and verify directory permissions. |
| Function times out | Navigation, browser startup, or rendering exceeds the configured timeout, or the page never reaches the script’s completion path. | Log each phase, use a page-specific readiness condition, bound child-process execution, and tune timeout based on observed duration. |
| Screenshot is blank or incomplete | The page failed to load, capture happened before asynchronous content was ready, or rendering failed. | Check the page-open status and logs, wait for a meaningful page condition, and inspect the actual output file before returning it. |
| Works locally but not in Lambda | Different libraries, runtime, architecture, permissions, writable paths, or environment assumptions. | Test the exact packaged artifact in the target Lambda configuration; use /tmp for generated files and inspect startup errors. |
| Package exceeds ZIP limit | The executable and dependencies exceed the combined unzipped package allowance. | Measure the full package including layers; consider a container image if its build/runtime control and size fit the deployment. |
| Output file missing on later request | The function relied on temporary local storage as durable storage. | Return the bytes during the invocation or persist the screenshot to object storage before returning. |
8. Performance, reliability, and cost
There is no source-backed universal memory setting, timeout, cold-start figure, screenshot speed, or cost comparison for PhantomJS on Lambda. Measure with representative target pages and the exact deployed artifact. Record browser startup, navigation, readiness, render, and persistence times separately so the slow stage is clear.
Reliability depends on more than a successful process exit: check the page-load result, ensure a non-empty output exists, handle process errors and timeouts, and make persistence failures visible. Retest after changing the binary, runtime, architecture, libraries, or base image. Since PhantomJS development is suspended, include migration planning in ongoing maintenance.
Lambda charges depend on the AWS configuration and usage; the research sources here do not provide a PhantomJS-specific cost figure. Estimate using your account’s current Lambda pricing and measured invocation duration and memory, including retries and storage. Do not infer a cost from the service limits.
Or skip the browser setup
ScreenshotNeo provides a screenshot API and MCP server. One GET request returns an image or PDF; see the ScreenshotNeo 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 bytes = new Uint8Array(await res.arrayBuffer());
- Cookie banners are accepted and removed, and known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdffor AI agents and MCP clients. - The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
Frequently asked questions
Does PhantomJS still work on AWS Lambda?
It may run if the executable and dependencies match the chosen Lambda environment, but no reviewed source certifies a current PhantomJS binary/runtime pairing. Validate the deployed artifact directly.
Can I use an old PhantomJS Lambda layer?
An old layer is not evidence of current support. Check its architecture, libraries, runtime assumptions, and package permissions, then test it on the exact target configuration.
Can PhantomJS capture a full page or PDF?
The PhantomJS capture guide documents rendering and viewport or clip rectangle controls, as well as PNG, JPEG, GIF, and PDF output. Confirm the behavior your script needs with its selected version.
Should I rewrite the script in Chromium automation?
Consider it for new work or when current-site compatibility and maintenance matter. Evaluate a specific maintained project and build, then compare fidelity, artifact size, cold start, memory, and porting effort in your own environment.


