ScreenshotNeo

BlogHow-to

How to Capture a Mobile Website Screenshot with Playwright on an iPhone-Sized Viewport

Capture a mobile website with Playwright using an iPhone device profile or a custom viewport. Choose full-page capture and image scale for your use case.

By the ScreenshotNeo team4 October 20267 min read

Use a Playwright device profile such as iPhone 13 to emulate an iPhone-sized browser, navigate to the page, and save a screenshot with page.screenshot(). A device profile configures more than width and height, including browser parameters such as user agent and touch capability. This is browser emulation, not a screenshot from a physical iPhone.

1. Capture a page with an iPhone device profile

Install Playwright and its Chromium browser if you have not already. Save this as mobile-shot.mjs, then run it with Node.js. Use a device name available in your installed Playwright version.

npm install playwright
npx playwright install chromium
import { chromium, devices } from 'playwright';

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

try {
  await page.goto('https://example.com', { waitUntil: 'networkidle' });
  await page.screenshot({ path: 'mobile-page.png' });
} finally {
  await browser.close();
}

The screenshot is the current viewport by default. Replace https://example.com with the page you want to capture. The try/finally closes Chromium even if navigation or capture fails.

Playwright device profiles emulate browser behavior and device characteristics. They do not reproduce every aspect of a physical phone, carrier, or operating system. For actual-device verification, test on physical hardware separately. See the Playwright emulation guide.

2. Use a specific viewport instead

If you only need exact CSS viewport dimensions, configure a viewport directly. This does not apply the full set of characteristics in a named device profile.

import { chromium } from 'playwright';

const browser = await chromium.launch();
const context = await browser.newContext({
  viewport: { width: 390, height: 844 },
  deviceScaleFactor: 3,
  isMobile: true,
  hasTouch: true,
});
const page = await context.newPage();

try {
  await page.goto('https://example.com', { waitUntil: 'networkidle' });
  await page.screenshot({ path: 'mobile-page.png' });
} finally {
  await browser.close();
}

For a viewport-only setup, set just viewport. Add options such as isMobile, hasTouch or deviceScaleFactor when your test needs those emulated behaviors. A viewport alone does not set a mobile user agent or touch support.

Override a device profile safely

A device profile already includes a viewport. Put explicit overrides after the spread so your values win:

const context = await browser.newContext({
  ...devices['iPhone 13'],
  viewport: { width: 390, height: 844 },
});

3. Choose the capture extent and output scale

Use a viewport screenshot to inspect the initial screen. Set fullPage: true when you need the entire scrollable page. Select CSS scale for compact output or device scale when you need the emulated device-pixel resolution.

Option Effect Use it when
fullPage Captures the full scrollable page instead of the visible viewport You need below-the-fold content in one image
scale: 'css' One output pixel per CSS pixel Smaller, dimension-predictable images are useful
scale: 'device' Uses the emulated device pixel ratio You need a higher-resolution raster; files can be larger
type Selects PNG, JPEG or WebP output You need a specific format; otherwise the path extension determines it
await page.screenshot({
  path: 'mobile-page-full.png',
  fullPage: true,
  scale: 'css',
  type: 'png',
});

For a viewport-only image at device resolution, omit fullPage and use scale: 'device':

await page.screenshot({
  path: 'mobile-page-high-res.png',
  scale: 'device',
});

Full-page captures can be much taller and larger than viewport captures. Long pages with sticky elements or content that appears only after scrolling may need site-specific handling. Playwright’s screenshot API documents the available screenshot options.

4. Run it from Playwright Test

When screenshots belong to an automated test suite, define the device profile in a project configuration and use the test runner’s screenshot assertion or save a file explicitly.

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  projects: [
    {
      name: 'iPhone 13 emulation',
      use: { ...devices['iPhone 13'] },
    },
  ],
});
// mobile.spec.ts
import { test, expect } from '@playwright/test';

test('mobile page screenshot', async ({ page }) => {
  await page.goto('https://example.com');
  await page.screenshot({ path: 'mobile-page.png', fullPage: true });
});

To compare against a maintained visual baseline, Playwright Test provides expect(page).toHaveScreenshot(). That is a comparison workflow, distinct from saving a one-off image with page.screenshot(). See the visual comparisons guide.

5. Select the right workflow

Need Recommended setup Tradeoff
Emulate a named iPhone model’s browser profile ...devices['iPhone 13'] Profile behavior depends on the device registry in your Playwright version
Control exact viewport dimensions viewport: { width, height } Dimensions alone do not configure the full mobile profile
Review the first screen Default viewport screenshot Content below the fold is excluded
Review the whole page fullPage: true Image height and memory use can grow with page length
Keep pixel dimensions compact scale: 'css' Does not retain the emulated high-DPI pixel count
Capture device-pixel detail scale: 'device' Can produce a larger image

6. Wait for the page to be ready

Choose navigation and page-readiness conditions according to how the site loads. networkidle waits for network activity to settle, but analytics, streaming requests or long polling can prevent that state. If that happens, wait for the important content instead:

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('main article').waitFor({ state: 'visible' });
await page.screenshot({ path: 'mobile-page.png', fullPage: true });

For content that appears after a known delay, a short explicit wait can help, but waiting for a meaningful selector is usually more reliable than guessing a delay. Lazy-loaded images may need scrolling or page-specific preparation before a full-page capture. Confirm the resulting image includes the content you need.

7. Troubleshooting

Symptom Likely cause Fix
“Unknown device” or missing profile The installed Playwright version does not contain that device name Check the current version’s device registry and choose an available name; the official guide’s iPhone 13 example may differ by version.
Screenshot has desktop layout Only viewport width was set, or the page was captured before mobile layout took effect Use a device profile, or configure the mobile characteristics your scenario needs. Confirm the page has finished loading before capture.
Explicit viewport is ignored The viewport was set before spreading a profile, so the profile overwrote it Spread the device profile first, then set viewport.
Full-page image is unexpectedly large The page is long, or device scale multiplies pixel dimensions Use scale: 'css', capture only the viewport, or resize/process the image for its downstream use.
Images or dynamic sections are missing Capture happened before content loaded, or lazy content has not been triggered Wait for a relevant locator; scroll or otherwise trigger lazy content before capturing.
Screenshot differs across machines OS, browser version, settings, hardware, power source or headless mode can change rendering Generate and compare baselines in the same environment, and review new baselines before accepting them.

8. Performance, reliability and cost

  • Runtime: launching a browser for every URL adds setup work. For batches, reuse a browser and create an appropriate context per device profile while keeping each page isolated.
  • Image size: full-page and device-scale screenshots increase pixel count and memory use. Use viewport captures and CSS scale when those meet the requirement.
  • Repeatability: pin the Playwright version and run visual captures in a consistent operating system and browser environment. Rendering can vary across environments; treat baseline updates as reviewable changes.
  • Failures: set a navigation timeout appropriate for the site, wait for the content that matters, and close the browser in a finally block. A timeout should be surfaced as a failed capture rather than silently saved as a success.
  • Cost: Playwright is a software workflow that runs in your own environment. Budget for the machine or CI capacity that runs it; the research for this guide supplies no benchmark or fixed operating cost.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Send a GET request with the page URL to receive an image or PDF, without installing Playwright or managing a browser for this capture. This one-call example returns a screenshot of the same type of target page; ScreenshotNeo’s supplied facts do not claim that this API call emulates an iPhone device profile or sets an arbitrary viewport.

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

See the ScreenshotNeo API documentation for request options. Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, blank pages and failed loads are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents call take_screenshot, get_page_info and capture_pdf. 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 try it.

10. FAQ

Can Playwright take a screenshot of a mobile website without a phone?

Yes. A device profile or configured browser context emulates mobile browser characteristics. It does not constitute testing on physical hardware.

What is the difference between a device profile and a viewport?

A profile provides a bundle of emulated device and browser parameters. A viewport specifies the page’s width and height in CSS pixels.

How do I start Playwright with an iPhone profile?

For interactive recording, run npx playwright codegen --device="iPhone 13" https://example.com. Use a device name available in the installed version. The separate --viewport-size="800,600" option sets dimensions rather than selecting a named profile. See the codegen documentation.

Why do screenshot baselines change after an environment update?

Rendering can vary with the operating system, browser version, settings, hardware, power source and headless mode. Keep the baseline environment consistent and review changes before updating expected images.