Blog 7 min read

How to Take Mobile Screenshots of Any Website: Developer Guide

Capture mobile screenshots of any website using device emulation. Covers iPhone, Android, iPad, and custom viewports with Node.js, Python, and API examples.

SnapRender Team
|

How to Take Mobile Screenshots of Any Website

Testing and capturing how websites look on mobile devices is a common need for developers, QA teams, and designers. Whether you're checking responsive layouts, generating mobile previews for a portfolio, or building a cross-device testing pipeline, you need a way to render web pages as they appear on specific mobile devices.

This guide covers how to capture mobile screenshots using device emulation, making a desktop browser behave exactly like an iPhone, Pixel, or iPad, with working code examples in Node.js, Python, and via API.

What Is Device Emulation?

Device emulation means configuring a headless browser to mimic a specific mobile device. This includes:

  • Viewport size: The screen resolution (e.g., 393x852 for iPhone 15 Pro)
  • Device scale factor (DPR): How many physical pixels per CSS pixel (e.g., 3x for iPhones)
  • User agent string: Tells the website which device is requesting the page
  • Touch events: Enables touch-based interactions
  • Media queries: Triggers responsive CSS breakpoints

When all of these are set correctly, the website renders its mobile layout, exactly as it would on a real device.

Method 1: Puppeteer (Node.js)

Puppeteer includes built-in device descriptors for dozens of popular devices.

Using Built-In Device Presets

import puppeteer, { KnownDevices } from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

// Emulate iPhone 15 Pro
const device = KnownDevices['iPhone 15 Pro'];
await page.emulate(device);

await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({ path: 'iphone15pro.png' });

await browser.close();

Available Devices

Puppeteer includes presets for:

Device Viewport DPR
iPhone 14 390x844 3
iPhone 15 Pro 393x852 3
iPhone 15 Pro Max 430x932 3
iPhone SE 375x667 2
iPad Pro 11 834x1194 2
Pixel 7 412x915 2.625
Galaxy S21 360x800 3

You can list all available devices:

import { KnownDevices } from 'puppeteer';
console.log(Object.keys(KnownDevices));

Custom Device Configuration

If you need a device that's not in the presets:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.setViewport({
  width: 412,
  height: 915,
  deviceScaleFactor: 2.625,
  isMobile: true,
  hasTouch: true
});

await page.setUserAgent(
  'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36'
);

await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({ path: 'pixel8.png' });

await browser.close();

Landscape Mode

Swap width and height for landscape orientation:

const device = KnownDevices['iPhone 15 Pro landscape'];
await page.emulate(device);

Or manually:

await page.setViewport({
  width: 852,   // Height becomes width in landscape
  height: 393,  // Width becomes height
  deviceScaleFactor: 3,
  isMobile: true,
  hasTouch: true
});

Method 2: Playwright (Node.js / Python)

Node.js

import { chromium, devices } from 'playwright';

const browser = await chromium.launch();

// Use built-in device preset
const context = await browser.newContext({
  ...devices['iPhone 15 Pro']
});

const page = await context.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'mobile.png' });

await browser.close();

Python

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()

    # Use built-in device preset
    device = p.devices["iPhone 15 Pro"]
    context = browser.new_context(**device)

    page = context.new_page()
    page.goto("https://example.com")
    page.screenshot(path="mobile.png")

    browser.close()

Multiple Devices in One Script

Capture the same page across multiple devices:

from playwright.sync_api import sync_playwright

DEVICES = [
    "iPhone 15 Pro",
    "iPhone SE",
    "Pixel 7",
    "iPad Pro 11",
    "Galaxy S21"
]

with sync_playwright() as p:
    browser = p.chromium.launch()

    for device_name in DEVICES:
        device = p.devices[device_name]
        context = browser.new_context(**device)
        page = context.new_page()

        page.goto("https://example.com", wait_until="networkidle")

        filename = device_name.lower().replace(" ", "_") + ".png"
        page.screenshot(path=filename)
        print(f"Captured: {device_name} → {filename}")

        context.close()

    browser.close()

Method 3: Screenshot API

A screenshot API handles device emulation server-side. No browser installation, no device configuration, no memory management.

cURL

# iPhone 15 Pro screenshot
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&device=iphone_15_pro&format=png" \
  -H "X-API-Key: YOUR_API_KEY" \
  --output iphone.png

# iPad Pro screenshot
curl "https://app.snap-render.com/v1/screenshot?url=https://example.com&device=ipad_pro&format=png" \
  -H "X-API-Key: YOUR_API_KEY" \
  --output ipad.png

Node.js

import { SnapRender } from 'snaprender';

const client = new SnapRender('YOUR_API_KEY');

// iPhone screenshot
const iphone = await client.screenshot({
  url: 'https://example.com',
  device: 'iphone_15_pro',
  format: 'png'
});

// Android screenshot
const pixel = await client.screenshot({
  url: 'https://example.com',
  device: 'pixel_7',
  format: 'png'
});

// Custom viewport (no predefined device)
const custom = await client.screenshot({
  url: 'https://example.com',
  width: 375,
  height: 812,
  format: 'png'
});

Python

from snaprender import SnapRender

client = SnapRender("YOUR_API_KEY")

# iPhone screenshot
iphone = client.screenshot(
    url="https://example.com",
    device="iphone_15_pro",
    format="png"
)

with open("iphone.png", "wb") as f:
    f.write(iphone)

# Multiple devices
devices = ["iphone_15_pro", "iphone_14", "pixel_7", "ipad_pro"]

for device in devices:
    image = client.screenshot(
        url="https://example.com",
        device=device,
        format="png"
    )
    with open(f"{device}.png", "wb") as f:
        f.write(image)
    print(f"Captured: {device}")

Available Devices via API

SnapRender supports these device presets:

Device ID Device Viewport DPR
iphone_14 iPhone 14 390x844 3
iphone_15_pro iPhone 15 Pro 393x852 3
iphone_15_pro_max iPhone 15 Pro Max 430x932 3
pixel_7 Pixel 7 412x915 2.625
ipad_pro iPad Pro 12.9" 1024x1366 2
macbook_pro MacBook Pro 1440x900 2

You can also pass any custom width and height instead of using a preset.

Common Use Cases

Responsive Design Testing

Capture the same page at multiple breakpoints to verify responsive layouts:

import { SnapRender } from 'snaprender';

const client = new SnapRender('YOUR_API_KEY');

const breakpoints = [
  { name: 'mobile', width: 375, height: 812 },
  { name: 'tablet', width: 768, height: 1024 },
  { name: 'desktop', width: 1440, height: 900 },
  { name: 'wide', width: 1920, height: 1080 }
];

for (const bp of breakpoints) {
  const image = await client.screenshot({
    url: 'https://example.com',
    width: bp.width,
    height: bp.height,
    format: 'webp'
  });

  await writeFile(`${bp.name}.webp`, image);
  console.log(`Captured: ${bp.name} (${bp.width}x${bp.height})`);
}

App Store / Marketing Screenshots

Generate device-framed screenshots for app store listings or marketing pages:

// Capture at device-native resolution
const image = await client.screenshot({
  url: 'https://your-app.com/dashboard',
  device: 'iphone_15_pro',
  format: 'png'
});

// The image is at 3x DPR (1179x2556 actual pixels)
// Perfect for App Store screenshot requirements

Visual Regression Testing

Compare mobile screenshots over time to catch unintended layout changes:

import hashlib
from snaprender import SnapRender

client = SnapRender("YOUR_API_KEY")

def capture_and_compare(url: str, device: str, baseline_path: str) -> bool:
    """Capture a screenshot and compare to baseline."""
    current = client.screenshot(url=url, device=device, format="png")

    current_hash = hashlib.sha256(current).hexdigest()

    try:
        with open(baseline_path, "rb") as f:
            baseline_hash = hashlib.sha256(f.read()).hexdigest()

        if current_hash != baseline_hash:
            print(f"Visual change detected for {device}!")
            with open(f"diff_{device}.png", "wb") as f:
                f.write(current)
            return False
        return True

    except FileNotFoundError:
        # No baseline exists, save current as baseline
        with open(baseline_path, "wb") as f:
            f.write(current)
        return True

Dark Mode on Mobile

Combine device emulation with dark mode for complete coverage:

const image = await client.screenshot({
  url: 'https://example.com',
  device: 'iphone_15_pro',
  dark_mode: true,
  format: 'png'
});

Comparison

Feature Puppeteer/Playwright Screenshot API
Setup time 30-60 min 2 min
Browser installation Required (~150MB) Not needed
Built-in device presets Yes Yes
Custom viewports Yes Yes
Dark mode Yes Yes
Ad blocking Manual implementation Built-in
Cookie banner removal Manual implementation Built-in
Memory usage 50-300MB per capture None (server-side)
Concurrent captures Limited by RAM Limited by plan

Which Approach Should You Use?

Use Puppeteer or Playwright if:

  • You need to interact with the page before capturing (login, click, scroll)
  • You're already running browser automation for other tasks
  • You want zero third-party dependencies

Use a screenshot API if:

  • You just need the images without managing infrastructure
  • You're capturing across many devices and want consistent results
  • You need ad blocking and cookie banner removal without building it yourself

SnapRender supports all major device presets, dark mode, ad blocking, and cookie banner removal. 500 free screenshots per month, no credit card required. Get your API key and start capturing mobile screenshots in minutes.

Try SnapRender Free

500 free screenshots/month, no credit card required.

Sign up free