Mobile screenshots

To capture what a page looks like on a phone or tablet, you have two tools: a device preset that sets everything in one word, or a custom viewport where you set each property. This guide explains which to use and why a narrow viewport alone is often not enough. It is part of the capture guides.

The minimal request

The requests below need an API key in RS_API_KEY (get one free).

GET, with a device preset:

curl -G "https://api.renderscreenshot.com/v1/screenshot" \
  -H "Authorization: Bearer $RS_API_KEY" \
  --data-urlencode "url=https://example.com" \
  -d device=iphone_14 \
  -o iphone.png

POST, with the same preset:

curl -X POST https://api.renderscreenshot.com/v1/screenshot \
  -H "Authorization: Bearer $RS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "viewport": { "device": "iphone_14" }
  }' \
  -o iphone.png

The response is a 1170 x 2532 PNG: a 390 x 844 viewport at a device scale of 3.

Three ways to get a mobile capture

Approach You set Good for
device preset One id, for example iphone_14, pixel_7 or ipad_air Realistic captures of a known device
preset: mobile or mobile_landscape One preset that also sets format and cache defaults Quick portrait or landscape phone shots
Custom viewport width, height, scale, mobile, touch, landscape A device that is not in the list, or exact control for tests

A device preset overrides width, height, scale and mobile. Set landscape: true next to a device to swap width and height.

Why width alone is not enough

Many teams start with width: 390 and get a desktop page squeezed into a narrow window. That happens because three separate things make a browser behave like a phone:

  1. The layout viewport. A real phone honours the page's <meta name="viewport" content="width=device-width"> tag. Chrome applies that tag only in mobile emulation, which is viewport.mobile: true. Without it, a page that has no tag still lays out at a desktop width.
  2. Input capabilities. Media queries such as (hover: none) and (pointer: coarse) describe a touch screen. viewport.touch: true turns on touch events, which some sites check before they show the mobile menu or swipe controls.
  3. The user agent. Some sites choose the mobile template on the server by reading the User-Agent header. A narrow window with a desktop user agent gets the desktop HTML. Device presets send that device's user agent; with a custom viewport, set browser.user_agent yourself. The custom user agent guide shows the effect.

A device preset handles all three, so start there. Switch to a custom viewport only when you need a size that is not in the list.

Device presets

Get the current list from the API rather than from a copy in your code:

curl https://api.renderscreenshot.com/v1/devices \
  -H "Authorization: Bearer $RS_API_KEY"

Each entry has an id, a viewport (width and height in CSS pixels), a scale, and the mobile and touch flags. A selection:

Device id Viewport (CSS px) Scale Output image (px)
iphone_se 375 x 667 2 750 x 1334
iphone_14 390 x 844 3 1170 x 2532
pixel_7_pro 412 x 892 3.5 1442 x 3122
ipad_air 820 x 1180 2 1640 x 2360
ipad_pro_12 1024 x 1366 2 2048 x 2732

The output size is always viewport times scale. A large scale makes large files: see retina screenshots for the measured cost, and use viewport.scale: 1 together with a device-sized custom viewport if you only need the layout.

An unknown device id fails with a validation_error (HTTP 400) before any rendering, so a typo never uses a credit.

Custom viewport

For a device that is not in the list, set the properties yourself:

{
  "url": "https://example.com",
  "viewport": {
    "width": 360,
    "height": 780,
    "scale": 3,
    "mobile": true,
    "touch": true
  },
  "browser": {
    "user_agent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36"
  }
}
Parameter Default Limits Effect
viewport.width 1280 1 to 7,680 Layout width in CSS pixels
viewport.height 800 1 to 4,320 Visible height; also the image height in viewport mode
viewport.scale 1 1 to 3 Device pixel ratio; multiplies output pixels
viewport.mobile false Applies the meta viewport tag, as a phone does
viewport.touch false Enables touch events
viewport.landscape false Swaps width and height

Custom scale accepts 1 to 3. Device presets can use their real ratio, for example 3.5 for pixel_7_pro.

Full-page mobile captures

Mobile pages are long. Combine a device with full-page capture to get the whole scroll height at the device width:

{
  "url": "https://example.com/blog/post",
  "viewport": { "device": "iphone_14" },
  "capture": { "mode": "full_page", "scroll": { "simulate": true } }
}

At scale 3, a 6,000 px tall mobile page becomes an 18,000 px tall image. If the image is for a web page or for a vision model, set viewport.scale: 1 or resize the output. The full-page guide covers scroll.max_height.

SDK examples

Device preset first, then a custom viewport.

Node.js

import { writeFile } from 'node:fs/promises';
import { Client, TakeOptions } from 'renderscreenshot';

const client = new Client(process.env.RS_API_KEY);

const phone = await client.take(TakeOptions.url('https://example.com').device('iphone_14'));
await writeFile('iphone.png', phone);

const custom = await client.take(
  TakeOptions.url('https://example.com').width(360).height(780).scale(3).mobile()
);
await writeFile('custom.png', custom);

Python

import os
from renderscreenshot import Client, TakeOptions

client = Client(os.environ['RS_API_KEY'])

phone = client.take(TakeOptions.url('https://example.com').device('iphone_14'))
custom = client.take(
    TakeOptions.url('https://example.com').width(360).height(780).scale(3).mobile()
)
with open('iphone.png', 'wb') as f:
    f.write(phone)

Ruby

require 'renderscreenshot'

client = RenderScreenshot.client(ENV.fetch('RS_API_KEY'))

phone = client.take(RenderScreenshot::TakeOptions.url('https://example.com').device('iphone_14'))
custom = client.take(
  RenderScreenshot::TakeOptions.url('https://example.com').width(360).height(780).scale(3).mobile
)
File.binwrite('iphone.png', phone)

PHP

use RenderScreenshot\Client;
use RenderScreenshot\TakeOptions;

$client = new Client(getenv('RS_API_KEY'));

$phone = $client->take(TakeOptions::url('https://example.com')->device('iphone_14'));
$custom = $client->take(
    TakeOptions::url('https://example.com')->width(360)->height(780)->scale(3)->mobile()
);
file_put_contents('iphone.png', $phone);

Java

Client client = new Client(System.getenv("RS_API_KEY"));

byte[] phone = client.take(TakeOptions.url("https://example.com").device("iphone_14"));
byte[] custom = client.take(
    TakeOptions.url("https://example.com").width(360).height(780).scale(3.0).mobile()
);
Files.write(Path.of("iphone.png"), phone);

Go

phone, err := client.Take(ctx, rs.URL("https://example.com").Device("iphone_14"))
if err != nil {
    log.Fatal(err)
}
custom, err := client.Take(ctx,
    rs.URL("https://example.com").Width(360).Height(780).Scale(3).Mobile(),
)
if err != nil {
    log.Fatal(err)
}
os.WriteFile("iphone.png", phone, 0o644)
os.WriteFile("custom.png", custom, 0o644)

Troubleshooting

Symptom Likely cause Fix
Desktop layout in a narrow image mobile not set, so the meta viewport tag is ignored Use a device preset or set viewport.mobile: true
Mobile layout, but tiny text The page has no meta viewport tag Expected for such pages; this is what a phone shows too
Desktop HTML even with mobile: true The server picks the template from the user agent Use a device preset, or set browser.user_agent to a mobile string
Hamburger menu or swipe UI missing Site checks for touch support Set viewport.touch: true
App install banner or cookie sheet covers the page Mobile-only overlays block.cookie_banners: true, or page.hide with the banner selector
Image is huge Scale 3 times full page height Use viewport.scale: 1 or output.resize
validation_error naming the device Device id not in the list Check GET /v1/devices
Landscape needed Portrait is the default viewport.landscape: true or preset: mobile_landscape

Related in this topic

Was this page helpful?