To capture a mobile-width screenshot in PhantomJS, create a webpage, set page.viewportSize before navigation, optionally set a mobile user-agent before page.open(), wait for a successful load, and call page.render(). The result is a repeatable responsive-layout image—not a guarantee of how a current iPhone or Android browser renders the page.
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 and request a particular user-agent string. Those controls are useful for checking responsive breakpoints and generating consistent assets, but they do not establish current-device equivalence.
- Viewport emulation:
page.viewportSizesets the layout viewport in CSS pixels. - User-agent selection:
page.settings.userAgentchanges the string sent with requests and can influence server-side markup. - Capture bounds:
page.clipRectselects the rectangle included in the image. - Not documented: the reviewed API does not provide an explicit device-pixel-ratio control, touch emulation switch, or current mobile-browser engine.
Use the output to review mobile CSS, not to claim real-device parity. Touch-only interactions, high-density rendering, browser-specific APIs, and modern JavaScript may behave differently on an actual handset.
Install and prepare PhantomJS
Install the PhantomJS executable appropriate for your operating system and verify it is on your PATH:
#1 Best Overall
- 【Strong Adsorption】The inspiration of the silicone phone suction case comes from the adhesive force of the octopus. Each suction cup phone mount is 3.15 inches long and 2.17 inches wide, with 24 independent suction cups providing a stronger and more stable suction force, so you don't have to worry about your phone falling during use.
- 【Back of Phone Suction Grip】Remove the adhesive film on the phone suction cup and stick it on the phone case. You can then fix the phone on any smooth surface, which is very convenient. (The phone suction cup cannot be removed and reused after being attached to the phone case. It is recommended to attach it to a regular phone case, not a valuable one.)
- 【Widely Used】Our non-slip silicone phone sticky grip mount attaches to almost any flat phone case and make it compatible with common mobile phones such as iPhone and Android.You can shoot, watch videos or video calls in the kitchen, gym, dance studio, bathroom and other places.
- 【Capture the Wonderful Picture】Whether you are a TikTok creator or just like to share videos and photos, this phone suction cup can help you hands-free capture wonderful videos and photos for sharing with friends.
- 【Note】You can fix the phone suction cup on a smooth surface such as a mirror or glass. If necessary, wipe the suction cup with a damp cloth to obtain stronger suction. Before releasing your hand, make sure the phone is firmly fixed. (Not applicable to rough walls, wooden surfaces, and other uneven surfaces)
phantomjs --version
The command-line documentation identifies 2.1.1 as the latest PhantomJS release documented there. Because it is legacy software, test your target sites before relying on it in a production pipeline. Save the following as capture-mobile.js.
Basic mobile screenshot script
var page = require('webpage').create();
// CSS viewport dimensions, not a promise of a physical handset display.
page.viewportSize = { width: 390, height: 844 };
// Set this before page.open(); it affects the initial navigation request.
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 directory containing the script:
phantomjs capture-mobile.js
The callback checks the navigation status before rendering. A successful callback means PhantomJS completed its initial page-open operation; it does not prove that every asynchronous component has finished.
Choose viewport dimensions deliberately
Set the width and height that represent the CSS layout scenario you want to inspect. The values in the example (390 by 844) are illustrative inputs, not an official iPhone preset or a guarantee of device equivalence. A narrower width can trigger different media queries, while the height controls how much of the initial viewport is visible.
| Goal | What to configure | What it proves |
|---|---|---|
| Responsive breakpoint review | page.viewportSize with the target CSS width and height |
How the page lays out at that viewport size |
| Server-side mobile markup | Viewport plus a mobile userAgent before page.open() |
How this server responds to the supplied request identity |
| Specific region capture | page.clipRect |
The selected rectangle, rather than automatically the entire document |
| Real touch or handset validation | Use a current browser/device testing system instead | PhantomJS does not document these capabilities |
Capture only a defined rectangle
Assign a clip rectangle when you need a fixed region. Coordinates and dimensions are in CSS pixels:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesRank #2
- SUPERIOR COMFORT — Unlike traditional circular ear buds, the design of EarPods is defined by the geometry of the ear. Which makes them more comfortable for more people than any other ear bud–style headphones.
- HIGH-QUALITY AUDIO — The speakers inside EarPods have been engineered to maximize sound output and minimize sound loss, which means you get high-quality audio.
- BUILT-IN REMOTE — EarPods with USB-C plug also include a built-in remote that lets you adjust the volume, control the playback of music and video, and answer or end calls with a pinch of the cord.
- COMPATIBILITY — Works with all devices that have a USB-C port.
- INTEGRATED MICROPHONE — A built-in microphone precisely captures your voice while you’re on the phone, taking a FaceTime call, or summoning Siri — so you’re always heard loud and clear.
page.clipRect = { top: 0, left: 0, width: 390, height: 844 };
Place this assignment before page.render(). A clip rectangle does not turn a viewport screenshot into a guaranteed full-document capture. Inspect the output and set bounds that match your purpose.
Use the user-agent only when needed
Some sites return different HTML to mobile and desktop user-agents. Set page.settings.userAgent before opening the URL. The settings reference says these settings apply during the initial page.open() call; changing the value after navigation may not affect the already-started request.
Wait for asynchronous content
The basic example renders in the page.open() callback, which is appropriate for pages whose useful content is present after the initial load. Modern applications often populate the DOM later. PhantomJS documentation does not define one delay that works for every site, so use a site-specific readiness condition and verify the image.
Poll for a known element
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';
page.open('https://example.com/', function (status) {
if (status !== 'success') {
console.log('Unable to load the page');
phantom.exit(1);
return;
}
var deadline = Date.now() + 10000;
var timer = setInterval(function () {
var ready = page.evaluate(function () {
return !!document.querySelector('[data-ready="true"]');
});
if (ready || Date.now() >= deadline) {
clearInterval(timer);
if (!ready) {
console.log('Readiness marker was not found; rendering current DOM');
}
page.render('mobile-ready.png');
phantom.exit(ready ? 0 : 2);
}
}, 200);
});
Replace the selector with a marker your application controls. page.evaluate() executes in the page context and returns serializable values, making it suitable for DOM-state checks; it is not a device-emulation feature. If the site has no reliable marker, render after a delay chosen from that site’s behavior and treat the result as an approximation.
Rank #3
- Secure Hold: Our PopSockets adhesive phone grip gives your cell phone a secure, comfortable hold in hand to help prevent drops while texting, taking photos, or scrolling on the go. Designed to stick firmly to most phone cases and devices.
- Hands-Free Made Easy: Easily turn your PopSocket into a phone stand to prop up your phone anywhere — perfect for watching videos, video calls, or following recipes. A must-have phone holder that keeps your device secure and ready for anything.
- Compatibility: Works with all phones, tablets, and Kindles. Sticks best to smooth, hard plastic cases and may not adhere to silicone or textured cases. Easily swap your PopTop to change up your style — just close the grip, press down, twist 90°, and snap on a new top.
- Black PopSockets: Simple, refined, and endlessly versatile — a timeless essential for any phone.
- PopSockets Ecosystem: Mix and match your favorite PopSockets products — from grips and wallets to cases and mounts — all designed to work together seamlessly.
Output formats and filenames
page.render() chooses the output format from the filename. PNG and JPEG are common choices; the render API also lists PDF, BMP, and PPM, while GIF availability depends on the Qt build.
page.render('mobile.png'); // PNG
page.render('mobile.jpg'); // JPEG
page.render('mobile.pdf'); // PDF, where supported
Use PNG for crisp UI text and pixel comparison, JPEG when a smaller photographic file is more important, and PDF when the deliverable is a document rather than a web-image fixture. Confirm the generated file and dimensions in your pipeline instead of assuming a particular format or full-page height.
Common failures and fixes
“Unable to load the page”
The callback status was not success. Check the URL, DNS and TLS compatibility, proxy requirements, and whether the site blocks the legacy PhantomJS engine. Keep the nonzero exit code so CI marks the capture as failed.
The page is desktop-sized
Ensure page.viewportSize is assigned before page.open(). If the server selects markup by user-agent, assign page.settings.userAgent before that same call. A mobile string alone does not change CSS layout when the viewport remains wide.
Rank #4
- [360 ° Flexible Rotation Design] Comes with a rotatable lanyard ring that supports 360 ° free rotation, effectively solving the problem of twisted and tangled lanyards
- [Wide compatibility] The ultra-thin 0.02-inch design does not block the charging port at all, and both wired and wireless charging can be used directly without removing the pad. Compatible with most smartphones such as iPhone, compatible with various wristbands, lanyards, crossbody straps, and keychains
- [Durable and Portable Material] Premium rust-resistant stainless steel material with good flexibility, which not only avoids scratching the phone case, but also has excellent anti rust and anti fading performance
- [Multi scenario Practical] Paired with a lanyard or wristband, hands-free use can be achieved. The phone is within reach and not easily dropped, ideal for daily commuting and outdoor activities. Suitable for full coverage phone cases, does not support half coverage phone cases
- [Quality Service] If you find any damage or other issues with the product upon receipt, please contact us immediately. We will handle it quickly
Content is missing
Initial navigation may have completed before an API call or client-side render. Wait for a known selector or application state, then inspect whether your readiness condition actually appears. Do not assume a universal sleep interval.
The screenshot is cropped unexpectedly
Review page.clipRect and its top, left, width and height values. Remove the clip rectangle for the default rendered region, or enlarge it deliberately. A single viewport render is not automatically a full-document screenshot.
The result does not match a phone
Check whether the page depends on touch events, device-pixel ratio, browser-specific APIs, or a current rendering engine. PhantomJS documents viewport and user-agent controls, not complete handset emulation. Validate those behaviors with a current device-capable browser tool.
Modern scripts fail
PhantomJS’s engine is old. Look for JavaScript syntax or web-platform features unavailable to it, and consider a maintained browser automation stack when compatibility with current mobile browsers is the requirement.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallBest Value
- 【PKYAA Double Sided Silicone Suction Phone Case Mount】PKYAA With Double Sided 40 Strong and Reliable individual suction cups, PKYAA provides a thicken and upgraded universal silicon suction mount for your phone.
- 【Friendly to Content Creators】If you are a content creator or an online influencer, you can create videos anywhere with this suction mount completely hands free with this silicone cell phone mount for cases.
- 【HANDS-FREE & Adhere to Mirrors】This Double Sided silicone suction phone case mount allows you to stick your phone to the mirror easily. No longer holding your phone in one hand to watch video tutorials while making up.
- 【Strong Grip on the Smooth Surface】You can easily hang your phone anywhere with a smooth surface. All you do is you clean off your phone and smooth surface. It is STURDY and it not only sticks to mirrors, it also sticks to windows, it sticks to refrigerators, tiles and other clean, flat surfaces.
- 【Press Down Firmly Every 30 Minutes】Use your palm or fingers to press the phone down firmly and check it's secure before letting go. Apply even pressure for a few seconds to allow the suction cup to adhere properly. To maintain the grip and prevent accidental falls, it's a good practice to periodically reapply pressure to the suction cup.
Make captures repeatable
- Keep viewport width, height, user-agent, clip rectangle and output format in source control.
- Use a deterministic readiness marker instead of an undocumented global delay.
- Record the URL and exit status alongside each artifact.
- Compare images at the same viewport and format; changing either can create differences unrelated to your CSS.
- Run representative pages, including one with late-loading images and one with server-side user-agent branching.
These practices make PhantomJS useful for regression fixtures, while the legacy engine caveat remains part of the interpretation of every result.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API when you want a mobile-width capture without installing PhantomJS. Supply a URL and viewport options through its API; the service can also load lazy images, wait for a selector, delay or network idle, set a user-agent, and select PNG, JPEG or WebP output. It accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.
For a one-call example, see the ScreenshotNeo documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same request in 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)
And 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(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', data));
ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients. Every feature is 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 to try it.
FAQ
Does PhantomJS emulate an iPhone exactly?
No. It approximates a mobile layout with a CSS viewport and optional user-agent string; the documented API does not establish touch, device-pixel-ratio or current-engine parity.
Should I set the user-agent before or after opening the URL?
Before. The settings documentation states that the user-agent setting takes effect during the initial page.open() call.
Can one render call guarantee a full-page image?
No. The capture rectangle and rendered region must be selected and checked for the page you are capturing.
What if I need current mobile-browser fidelity?
Use a maintained browser/device automation solution for that validation, or use an API such as ScreenshotNeo when your requirement is a clean, repeatable website image rather than touch-device testing.
Recommended Free Tools
Quick Recap
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.

