ScreenshotNeo

BlogComparisons

PhantomJS vs Puppeteer for Capturing Full-Page Screenshots

Compare PhantomJS and Puppeteer for full-page screenshots, with runnable code, setup guidance, troubleshooting, and a maintained alternative.

By the ScreenshotNeo team4 October 20269 min read

For new automated full-page screenshot work, choose Puppeteer. Its documented Page.screenshot() API supports fullPage: true. PhantomJS was built for headless WebKit scripting and screen capture, but its project says development is suspended and GitHub marks the repository archived and read-only since May 30, 2023. This recommendation follows documented capability and maintenance status; the available sources do not establish that either tool is faster, more accurate, or more compatible across sites.

If you want a managed screenshot API instead of maintaining a browser runtime, try ScreenshotNeo first: it removes known consent banners, popups, and chat widgets before capture, bills only clean shots, and its paid plans start at $5 for 3,000 screenshots.

At a glance

Question Puppeteer PhantomJS
Can it request a full-page screenshot? Yes. Set fullPage: true; the documented default is false. Screen capture is among its intended use cases. The supplied project sources do not document a directly comparable current full-page option.
Project status The supplied sources document its screenshot API. They do not provide a status comparison beyond that. Development is suspended; repository archived May 30, 2023. Version 2.1 is identified as the latest stable release.
Best fit New Node.js screenshot automation where a maintained browser automation stack is appropriate. Existing legacy systems that already depend on PhantomJS and have a reason to preserve that runtime.
Head-to-head performance evidence No controlled capture-quality, speed, reliability, or compatibility benchmark was found in the research for this article.

How do I take a full-page screenshot with Puppeteer?

Install Puppeteer, navigate to the target, and pass fullPage: true to page.screenshot(). Puppeteer documents this option as a boolean that requests capture of the full page; its default is false. Its screenshot API returns a promise and supports binary and base64 forms. The file example below uses the binary result.

1. Install

mkdir full-page-shot
cd full-page-shot
npm init -y
npm install puppeteer

Puppeteer normally downloads a compatible browser during installation. If your deployment manages the browser separately, check Puppeteer’s installation guidance and configure the executable path for that environment.

2. Save a full-page PNG

// screenshot.js
const puppeteer = require('puppeteer');

async function main() {
  const url = process.argv[2] || 'https://example.com';
  const browser = await puppeteer.launch({ headless: true });

  try {
    const page = await browser.newPage({
      viewport: { width: 1440, height: 900 },
      deviceScaleFactor: 1,
    });

    await page.goto(url, { waitUntil: 'networkidle2', timeout: 60_000 });
    await page.screenshot({ path: 'full-page.png', fullPage: true });
    console.log('Saved full-page.png');
  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
node screenshot.js https://example.com

The viewport sets the page’s layout width and the initial browser viewport. fullPage asks Puppeteer to capture beyond that viewport to the page’s full dimensions. It does not guarantee that lazy content, animations, embedded media, or every dynamically-rendered section has finished loading. For pages with those behaviors, define readiness for the particular site and inspect the output.

Common screenshot options

Option Use Practical note
fullPage Capture the full page when true. Defaults to false. It controls capture area, not page readiness.
type Choose an image format such as PNG or JPEG. Follow the API’s format-specific constraints; check the current options reference for supported values.
quality Set lossy image quality for supported formats. Consult the API reference for applicable formats and valid range; do not assume it affects PNG.
omitBackground Capture without the default page background where supported. Useful when transparency is needed; inspect how the page itself paints backgrounds.
clip Capture a specified rectangle. Use when the desired output is a region rather than the entire document.
encoding Request binary or base64 screenshot output. Binary output is usually simpler for writing a file; base64 is useful when embedding in a data flow.

Option names and availability can change by Puppeteer version. Refer to the ScreenshotOptions API for the version you install, and the Page.screenshot() API for return types and method behavior.

Capture a particular element

If the target is a chart, article body, or card, locate it and use its element screenshot method. Puppeteer’s guide says the element screenshot operation attempts to scroll a hidden element into view.

const element = await page.waitForSelector('main article', { timeout: 15_000 });
if (!element) throw new Error('Article element was not found');
await element.screenshot({ path: 'article.png' });

This is different from fullPage: true: an element screenshot is bounded to the selected element. See the Puppeteer screenshot guide.

Can PhantomJS capture full pages?

PhantomJS is described by its project as a scriptable headless WebKit browser, and screen capture is among its stated use cases. Its archived project status makes it a poor starting point for new screenshot systems. Existing installations may still run in a compatible environment; suspension does not mean the software is impossible to execute.

The project README says development is suspended until further notice, the repository became read-only on May 30, 2023, and version 2.1 is the latest stable release. The changelog dates version 2.1.0 to January 23, 2016. These are maintenance and history facts, not evidence that every PhantomJS capture fails or that Puppeteer is universally superior in fidelity.

For new work, the clearer choice is Puppeteer because its current documented screenshot API explicitly exposes a full-page option. For a legacy system, test the actual target pages and deployment constraints before changing tools. Do not infer pixel parity or universal site compatibility from either project’s documentation.

How should I handle dynamic pages and long captures?

  1. Choose a readiness condition. Navigation completion is not the same as application readiness. If the page renders data after navigation, wait for a site-specific selector or state that indicates the content is present.
  2. Account for lazy-loaded content. Full-page capture requests the document area, but does not establish that every below-the-fold image or component has loaded. Where needed, scroll through the page or trigger the site’s own loading behavior before capture, then verify the saved image.
  3. Check media and animation. A Puppeteer issue report opened July 18, 2024 describes missing embedded video thumbnails in one user’s setup (Puppeteer 22.13.1, Node 20, macOS), even after attempts to wait for network idle. It is one page-specific report, not proof of a general or current defect. If media matters, inspect output and use a page-specific readiness strategy.
  4. Set bounded waits. Use timeouts so a stalled page cannot occupy a worker forever. Capture diagnostic details on timeout and decide whether to retry based on the failure type.
  5. Manage very tall output. A full-page image can be much larger than a viewport image. Consider whether the consuming system needs one tall image, several viewport captures, a selected element, or a PDF.

The steps above are practical guidance; the cited documentation does not promise that a particular wait condition solves every dynamic-page issue.

How do I choose between them?

Situation Recommendation Reason
Starting a new Node.js screenshot job Puppeteer Its documented screenshot options include fullPage: true; PhantomJS is archived and suspended.
Maintaining an existing PhantomJS pipeline Evaluate migration to Puppeteer against real target pages Preserve known output requirements and compare representative captures; no controlled comparison in the researched sources establishes a universal result.
Need screenshots without browser installation and runtime operations ScreenshotNeo A single API request returns a screenshot or PDF, and clean shots are billed according to the supplied product facts.
Need AI agents to request captures ScreenshotNeo Its MCP server provides take_screenshot, get_page_info, and capture_pdf.

When comparing any screenshot tools, evaluate the specific dimensions that matter to your job: output format, viewport, readiness behavior, authentication needs, network access, privacy, operational burden, and cost. The research here does not establish a general speed or fidelity winner.

Or skip the browser setup

ScreenshotNeo is the managed alternative to try first when you need a screenshot API. Its clean-capture steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. An MCP server lets Claude, Cursor, or another MCP client request screenshots. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000. Every feature is on every plan.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo API documentation for parameters and setup. Sign up for 1,000 free screenshots a month with no card.

Troubleshooting

Symptom Likely cause What to do
Screenshot contains only the viewport fullPage was omitted or false. Pass { fullPage: true } to page.screenshot().
Content below the fold is missing Lazy loading or client-side rendering had not completed. Wait for the relevant content, trigger the page’s loading behavior if appropriate, and inspect the resulting image.
Navigation times out The site may keep connections open, load slowly, or fail to reach the selected lifecycle event. Use a readiness condition suited to the target page, set a bounded timeout, and capture diagnostics. Network-idle waiting is not a universal readiness guarantee.
Embedded media preview is absent Media rendering can depend on page behavior and environment. Check the target in the same environment and wait for its actual rendered state. One report of missing video thumbnails does not establish a general Puppeteer defect.
Image is unexpectedly huge Full-page dimensions and device scale multiply output size. Use an appropriate viewport and scale, capture an element if that meets the need, or split the job into sections.
PhantomJS behaves differently across systems It is an older archived runtime; the supplied sources do not provide a current compatibility matrix. Reproduce in the intended deployment environment and plan a migration where ongoing maintenance is required.
Screenshot request succeeds but saved file is invalid The caller may have received an error response or non-image body. Check the HTTP status and response headers before writing bytes; log a bounded error body without exposing secrets.

Performance, reliability, and cost

Performance: No controlled benchmark in the researched sources compares PhantomJS and Puppeteer. Measure your representative pages, including tall documents and media-heavy sites, under the actual browser version, machine limits, and concurrency you plan to use.

Reliability: Browser-based capture depends on navigation, rendering, page scripts, and the environment. Bound navigation and readiness waits, close browser instances in cleanup paths, record failures separately from valid captures, and retry only when the failure can plausibly be transient. Full-page mode does not guarantee complete dynamic content.

Cost: Self-hosted Puppeteer and PhantomJS do not have a per-screenshot fee specified by the cited project materials, but operating a capture service still consumes compute, storage, engineering, and maintenance time. ScreenshotNeo’s stated pricing is Free for 1,000 shots/month with no card; Starter $5 for 3,000; Growth $15 for 15,000; Pro $39 for 60,000; Scale $99 for 250,000; Business $249 for 1,000,000. Yearly billing gives two months free. Every feature is on every plan. Only clean shots are billed; bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing.

FAQ

Is PhantomJS still maintained?

The project says development is suspended until further notice, and GitHub marks its repository archived and read-only since May 30, 2023.

Does fullPage: true ensure every image and video is loaded?

No. It requests a full-page capture area; page readiness and media rendering are separate concerns.

Is Puppeteer proven to be faster than PhantomJS?

The research used for this article found no controlled head-to-head speed benchmark, so it does not support that claim.

Can I capture just one element with Puppeteer?

Yes. Puppeteer documents ElementHandle.screenshot(); use it when the output should be limited to a specific element.

Sources