ScreenshotNeo

BlogHow-to

How to Capture a Website Screenshot on an iPhone Simulator with Playwright

Use Playwright’s iPhone device preset to capture a mobile webpage, or use `simctl` to capture the actual iOS Simulator screen.

By the ScreenshotNeo team4 October 20267 min read

To capture a website at an iPhone-sized viewport with Playwright, create a browser context from Playwright’s iPhone device registry and save the page with page.screenshot(). That produces an image of a webpage rendered by Playwright with emulated device settings; it does not capture Apple’s iOS Simulator window. If you need the actual Simulator display, use Simulator’s screenshot command instead.

Playwright describes its device presets as emulating device parameters such as viewport, screen size, user agent, and touch behavior. The browser engine remains your choice: for example, use Chromium for a Chromium run or WebKit when you want to check rendering in Playwright’s WebKit engine. A WebKit capture is still a Playwright browser capture, not automatically a screenshot of Safari running inside Apple’s Simulator. See the [Playwright emulation guide](https://playwright.dev/docs/emulation) and [screenshot API](https://playwright.dev/docs/screenshots).

1. Capture a webpage with an iPhone preset

Install Playwright and its browser, then run a small Node.js script. The device preset below follows the documented iPhone 13 entry; make sure the preset exists in your installed Playwright version.

npm init -y
npm install playwright
npx playwright install chromium
const { chromium, devices } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  try {
    const context = await browser.newContext({
      ...devices['iPhone 13'],
    });
    const page = await context.newPage();

    await page.goto('https://example.com', { waitUntil: 'load' });
    await page.screenshot({ path: 'iphone-page.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

Save this as screenshot.js and run node screenshot.js. The output is iphone-page.png in the current directory. The try/finally ensures the browser is closed even if navigation or screenshot capture fails.

Use WebKit instead

If the relevant question is how a page renders in WebKit, install and launch that engine. It remains distinct from automating Apple’s Simulator.

npx playwright install webkit
const { webkit, devices } = require('playwright');

(async () => {
  const browser = await webkit.launch();
  try {
    const context = await browser.newContext({ ...devices['iPhone 13'] });
    const page = await context.newPage();
    await page.goto('https://example.com', { waitUntil: 'load' });
    await page.screenshot({ path: 'iphone-webkit.png' });
  } finally {
    await browser.close();
  }
})();

2. Choose the right capture: webpage or Simulator display

Need Use What the image represents
Automated screenshot at an iPhone-like viewport Playwright device preset and page.screenshot() A webpage rendered in a Playwright browser with emulated device parameters
Screenshot of the booted Apple iOS Simulator display Simulator screenshot UI or xcrun simctl The simulated device’s current screen
Automated, repeatable visual checks Playwright Test screenshot assertions A browser-page image compared against a stored baseline

The Playwright route navigates to a URL and can capture either the viewport or the full scrollable page. The Simulator route captures what is already visible in the booted simulated device; the command does not open a URL or automate Safari.

3. Capture the actual iOS Simulator screen

If the page is already open in an Apple Simulator and you need an image of that simulator display, run this in Terminal:

xcrun simctl io booted screenshot simulator-screen.png

This captures the booted simulator’s display and writes the file to the current directory. Apple’s cited Simulator guide is archived and marked retired, so check the Simulator Help or xcrun simctl io help installed with your Xcode setup for current command details. The research does not establish a standard Playwright workflow that drives Safari inside Apple’s Simulator; don’t treat the Playwright examples above as doing so.

4. Control screenshot size, format, and stability

Viewport versus full page

page.screenshot() captures the current viewport by default. Pass fullPage: true to capture the full scrollable page. Full-page output can be very tall, so use a viewport capture when you need a device-screen view and full-page capture when you need the whole document.

Image format and pixel scale

The file extension can select the image type; the screenshot API also accepts an explicit supported type. PNG is useful for lossless visual comparison. JPEG supports a quality setting. The scale option controls output dimensions: css uses one image pixel per CSS pixel, while device uses device pixels and can produce a higher-resolution, larger image. Choose based on whether compact review output or device-pixel detail matters.

await page.screenshot({
  path: 'iphone-page.png',
  fullPage: false,
  scale: 'css',
});

await page.screenshot({
  path: 'iphone-page.jpg',
  type: 'jpeg',
  quality: 85,
  fullPage: true,
  scale: 'device',
});

Other screenshot API controls include an output path, masks for selected elements, transparent backgrounds for supported image types, and a stylesheet for hiding or stabilizing dynamic elements. Consult the [Playwright screenshot API reference](https://playwright.dev/docs/api/class-page#page-screenshot) for the exact option types supported by your installed version.

Make repeatable visual checks

For a visual regression workflow, Playwright Test provides expect(page).toHaveScreenshot(). Screenshot assertions wait for two consecutive screenshots to match before comparing with the stored expectation. This assertion belongs to the Playwright Test runner; it is not part of the small standalone script above.

import { test, expect } from '@playwright/test';
import { devices } from '@playwright/test';

test.use({ ...devices['iPhone 13'] });

test('mobile homepage visual baseline', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveScreenshot('iphone-homepage.png', {
    fullPage: true,
  });
});

Run baseline generation and comparison in the same environment where possible. Browser version, operating system, settings, hardware, power source, and headless mode can affect rendering. Dynamic content can also vary; use the screenshot stylesheet controls to hide or stabilize volatile elements where appropriate. See [Playwright visual comparisons](https://playwright.dev/docs/test-snapshots) and its [screenshot assertion guidance](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1).

5. Or skip the browser setup

If the goal is a clean website screenshot rather than a local browser test, [ScreenshotNeo](https://screenshotneo.com) takes a screenshot with one GET request. Its API accepts common screenshot parameters, and its [API documentation](https://screenshotneo.com/docs/) describes the available options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. It also has an MCP server for AI agents, including Claude, Cursor, and other MCP clients.

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is on every plan. [Create a free ScreenshotNeo account](https://screenshotneo.com/account/sign-up/) to get started.

6. Troubleshooting

Symptom Likely cause Fix
devices['iPhone 13'] is undefined The installed Playwright version does not include that registry entry, or the key differs. Inspect the installed version’s device registry and use a preset it provides; keep the package version consistent in automation.
Browser launch reports a missing executable The Playwright package is installed, but its browser binary is not. Install the matching browser with npx playwright install chromium or npx playwright install webkit.
Screenshot shows the wrong portion of the page Viewport capture is the default. Set fullPage: true for the full scrollable page, or keep it false for the visible device viewport.
Image dimensions are larger than expected scale: 'device' uses device pixels. Choose scale: 'css' for one output pixel per CSS pixel.
Screenshots differ between runs Dynamic content or environment differences can change rendering. Stabilize or hide volatile elements, and generate and compare baselines with the same browser and host setup.
xcrun simctl says no device is booted There is no booted simulator selected. Start the intended simulator in Xcode’s Simulator app, then check xcrun simctl io help for the installed tool’s syntax.
The Simulator screenshot does not show the page The screenshot command captures the current device display; it does not navigate to a site. Open the page in the simulator first, or use Playwright to navigate and capture the webpage.

7. Performance, reliability, and cost

For local Playwright capture, runtime depends on browser startup, page loading, and the amount of content rendered; full-page output may require capturing substantially more page area than a viewport image. Reuse a browser process when automating many pages, close it in a cleanup path, and choose the smallest output scale and scope that meets the need. No benchmark is implied here.

For stable comparisons, pin the Playwright package and browser installation in your project, and run visual checks in a consistent environment. A screenshot that changes can indicate a rendering difference, but it can also reflect page content changing between captures. Treat the baseline as environment-specific unless you have verified portability.

Playwright itself is a browser automation library; this guide does not state a service price for it. The Simulator command uses the local Xcode toolchain. ScreenshotNeo’s stated prices are 1,000 free shots per month, Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free.

FAQ

Does an iPhone device preset run iOS?

No. It emulates device-related browser parameters in a Playwright browser. It does not establish that the page is running in Apple’s iOS Simulator.

Can Playwright capture the entire iOS Simulator window?

The documented Playwright screenshot call captures a browser page. For the actual booted Simulator display, use Simulator’s screenshot feature or the installed simctl command.

Should I use Chromium or WebKit?

Use the engine that matches the rendering behavior you need to check. The iPhone preset and browser engine are separately configurable in the examples; verify the page in the target engine.

Can I use these screenshots as pixel-perfect baselines on every machine?

Not safely by assumption. Playwright notes that rendering can vary with the environment, so keep baseline generation and comparison conditions consistent.