Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use PhantomJS’s webpage module: set a phone-sized page.viewportSize, optionally set a mobile user-agent before page.open(), wait for a successful load, then call page.render(). The result is a repeatable mobile-width screenshot, not proof of identical rendering on a current iPhone or Android device.

What PhantomJS can and cannot emulate

PhantomJS 2.1.1 is legacy command-line browser software. Its documented controls let you choose a CSS viewport, request a user-agent-sensitive version of a page, select a capture rectangle and write an image or PDF. They do not document device-pixel-ratio control, touch input, or a switch that emulates a particular modern handset.

Therefore, describe the output accurately: it is a mobile-width or responsive screenshot. A real-device test is still needed when layout or behavior depends on touch events, high-density displays, browser-specific APIs, or a current mobile rendering engine.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prerequisites and the capture workflow

  • Install the PhantomJS executable and make sure phantomjs is on your command path.
  • Create a JavaScript file that imports webpage.
  • Choose the CSS viewport width and height you want to review.
  • Set page.settings.userAgent before the first page.open() call if the server changes markup for mobile clients.
  • Render only after the open callback reports success.

The official PhantomJS screen-capture, command-line, render, page-automation, settings, evaluate and quick-start references document this sequence and the APIs used below.

Basic mobile screenshot script

Save this as capture.js. The 390 × 844 values and user-agent string are illustrative inputs; they are not an official iPhone preset or a guarantee of device equivalence.

var page = require('webpage').create();

// CSS viewport dimensions to inspect.
page.viewportSize = { width: 390, height: 844 };

// Set this before page.open() when the server uses the UA to choose content.
page.settings.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';

page.open('https://example.com/', function (status) {
  if (status !== 'success') {
    console.log('Unable to load the page');
    phantom.exit(1);
    return;
  }

  page.render('mobile.png');
  phantom.exit();
});

Run it from the same directory:

phantomjs capture.js

A successful run writes mobile.png. The render filename selects the format; documented formats include PNG, JPEG, BMP, PPM and PDF. GIF support depends on the Qt build.

Control viewport, crop and output

Choose the CSS viewport

page.viewportSize controls the layout viewport—the width against which responsive CSS media queries are evaluated. Set it before navigation:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
page.viewportSize = { width: 375, height: 812 };

Use dimensions that match the scenario you are reviewing, rather than assuming that one width represents every phone. Changing the viewport changes layout; it does not add touch support or change the browser engine.

Capture a defined rectangle

page.clipRect limits the rendered area. This is useful for a card, hero region or fixed-size review surface:

page.clipRect = { top: 0, left: 0, width: 390, height: 844 };

A single viewport render should not automatically be called a full-document capture. Set bounds deliberately and inspect the result. If you need content below the initial viewport, determine suitable capture bounds for that page and verify the output.

Select a file format

Change only the extension when the required format is supported:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
page.render('mobile.jpg');
// or
page.render('mobile.pdf');

JPEG is useful where file size matters; PNG preserves crisp text and transparency-related detail. PDF output follows PhantomJS’s render API and is not a substitute for validating a responsive image capture.

Make asynchronous pages complete before rendering

The basic example renders in the page.open() callback, which confirms navigation succeeded. Modern applications often populate the DOM after that callback. PhantomJS documentation does not define a universal delay that works for every site, so use a site-specific readiness condition and verify the image.

Poll for a known element

page.evaluate() runs JavaScript in the page context and returns serializable values. It can test whether an application-specific element exists:

var page = require('webpage').create();
page.viewportSize = { width: 390, height: 844 };
page.settings.userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';

var deadline = Date.now() + 15000;
function waitForContent() {
  var ready = page.evaluate(function () {
    return !!document.querySelector('[data-screenshot-ready]');
  });

  if (ready) {
    page.render('mobile-ready.png');
    phantom.exit();
  } else if (Date.now() > deadline) {
    console.log('Timed out waiting for the page-specific ready marker');
    phantom.exit(2);
  } else {
    setTimeout(waitForContent, 250);
  }
}

page.open('https://example.com/', function (status) {
  if (status !== 'success') {
    console.log('Unable to load the page');
    phantom.exit(1);
    return;
  }
  waitForContent();
});

Replace [data-screenshot-ready] with a marker your application sets after its data and images are ready. If no reliable marker exists, use a bounded, site-specific delay and inspect several captures; never assume a fixed sleep works universally.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

User-agent selection and its limits

Set page.settings.userAgent before page.open(). The settings documentation says these values take effect during the initial open call, so changing the string after navigation may not change the response you already received.

A mobile user-agent can cause a server to send mobile-oriented markup, while the narrow viewport triggers responsive CSS. Those two controls are independent: a site can use either one, both, or neither. They still do not establish touch capability, modern JavaScript compatibility, device-pixel-ratio behavior or parity with a current handset.

Common failures and fixes

Symptom Likely cause Fix
Unable to load the page DNS, TLS, network, redirect or site availability problem. Open the URL from the same machine, check the exact URL and retry. Keep the status check and do not render a failed page.
Desktop layout in the image Viewport is wide, or the server did not receive a mobile user-agent. Set page.viewportSize before opening and set the user-agent before page.open(). Confirm the page’s own responsive breakpoints.
Blank or partially populated image Rendering occurred before asynchronous content was ready. Poll for a page-specific DOM marker with page.evaluate(), or use a bounded delay selected for that site; then inspect the output.
Only the top portion appears The capture rectangle covers only the viewport or a short clip. Set page.clipRect to the intended region and verify its dimensions. Do not label a viewport capture full-page without checking it.
Unexpected dialogs or overlays Consent banners, chat widgets or application modals cover the page. Handle the page state in your script where possible, or use a capture service that removes common overlays before billing and capture.
Modern site scripts fail PhantomJS’s engine is old and may not support current browser features. Use PhantomJS only for compatible legacy targets, or capture with a maintained browser/service when current-engine fidelity is required.

Repeatable capture checklist

  1. Define the CSS width and height, and record them with the output.
  2. Decide whether the server needs a mobile user-agent.
  3. Set viewport and user-agent before the first page.open().
  4. Check the callback status before calling page.render().
  5. Wait for a known application state when content loads asynchronously.
  6. Choose a clip rectangle or document bounds intentionally.
  7. Use the extension that matches the required output format.
  8. Review the image for overlays, missing images, horizontal overflow and content below the fold.
  9. Repeat at each target width; one narrow viewport is not a device compatibility matrix.

Performance, reliability and cost considerations

PhantomJS runs locally, so runtime depends on your machine, network, target site and any readiness polling. A long timeout can hide a broken page; a short one can capture incomplete content. Record the URL, viewport, user-agent, timestamp and readiness rule alongside artifacts so differences are diagnosable.

For modern, JavaScript-heavy sites, a maintained browser engine is generally a better technical fit than this legacy engine. If you need scheduled or distributed captures, also account for process isolation, retries, storage, authentication and the cost of running browser workers. PhantomJS itself does not provide a hosted usage meter or a guarantee that failed loads are free.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. One request returns a PNG, JPEG, WebP or PDF, and its capture options include mobile viewport sizes, 12 device presets, custom user-agents, full-page loading, selector clips, waits, custom CSS and JavaScript, cookies, headers, geolocation, timezone, blocking rules, caching and async webhooks. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.

Using the ScreenshotNeo API documentation, a one-call mobile capture looks like this:

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)
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}`);

The MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients. Every feature is available on every plan: 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

When to choose each approach

Requirement PhantomJS script ScreenshotNeo
Local, offline-controlled workflow Yes, provided the legacy engine can load the site. Hosted request; requires API access.
CSS viewport and user-agent Supported through viewportSize and settings.userAgent. Supported, plus device presets and additional capture controls.
Consent and overlay cleanup Must be handled by your script or page state. Built-in removal of known consent, newsletter and chat overlays.
Modern browser or touch fidelity Not established by the documented API. Use the service’s documented options, but validate any requirement that depends on a specific real handset.
Billing on failed pages Local execution; no service billing model. Failed loads, bot checks, blank pages, timeouts and cache hits are not billed.

Frequently Asked Questions

Does PhantomJS create an actual iPhone screenshot?

No. It can combine a phone-like CSS viewport with a mobile user-agent, but the documented API does not provide full device metrics, touch emulation or current mobile-browser parity.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Where should the user-agent be assigned?

Assign page.settings.userAgent before the first page.open(); the settings apply during the initial open call.

Can I capture a whole page with page.render()?

Only if you deliberately set and verify capture bounds that include the required document area. A normal viewport render is not automatically a guaranteed full-document screenshot.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.