The API captures any URL at multiple viewport sizes in a single script. Pass width=375 for a phone layout, width=768 for a tablet, width=1440 for a wide desktop. Or use the device parameter and let the API handle viewport, user agent, and touch emulation together. Three API calls, three screenshots, three breakpoints. You get the actual responsive layouts your users see, not a browser window manually resized in DevTools.
Why manual responsive checks don't scale
Chrome DevTools has a responsive mode. You drag the handle, the page reflows, you eyeball whether the layout looks right. Works fine for one page. Maybe two. But when you're shipping updates to a site with 40 landing pages and a designer asks "can you show me how these look on mobile before we go live?" that manual process eats an afternoon.
And it misses things. DevTools doesn't change the user agent when you resize the viewport, so sites that serve different content based on the UA string show you a desktop page in a narrow window. Cookie banners render differently. Touch targets don't resize. You think you're testing the mobile experience, but you're testing something that no actual phone user would see.
The API solves both problems. It captures real responsive layouts (with proper device emulation) and does it fast enough to automate across every page you need to check.
Capture three breakpoints in one script
Most responsive sites define layouts at three widths: phone (under 480px), tablet (768px), and desktop (1024px or wider). Some add a fourth for wide screens above 1440px. Here's a batch capture that hits all three standard breakpoints for any URL:
# Mobile (375px — standard iPhone)
curl "https://api.screenshotrun.com/v1/screenshots/capture?\
url=https://example.com\
&width=375\
&device=mobile\
&format=png\
&response_type=json" \
-H "Authorization: Bearer YOUR_API_KEY"
# Tablet (768px — iPad portrait)
curl "https://api.screenshotrun.com/v1/screenshots/capture?\
url=https://example.com\
&width=768\
&device=tablet\
&format=png\
&response_type=json" \
-H "Authorization: Bearer YOUR_API_KEY"
# Desktop (1440px — standard wide screen)
curl "https://api.screenshotrun.com/v1/screenshots/capture?\
url=https://example.com\
&width=1440\
&format=png\
&response_type=json" \
-H "Authorization: Bearer YOUR_API_KEY"
The device=mobile parameter does more than shrink the viewport. It sets a mobile user agent, enables touch emulation, and applies a 2x device pixel ratio. Pages that detect mobile browsers via navigator.userAgent or navigator.maxTouchPoints render their actual mobile layout, not a desktop page squeezed into a narrow window.
Automate responsive previews for client handoff
Design agencies and freelancers show clients responsive previews during the review cycle. The usual approach: open staging in Chrome, manually resize to phone, screenshot, resize to tablet, screenshot, resize to desktop, screenshot. Paste all three into a PDF or Figma frame. Repeat for every page in the project. A 10-page site means 30 screenshots. By hand.
Here's a Python script that generates all breakpoints for a list of URLs and downloads the images:
import requests
import os
API = "https://api.screenshotrun.com/v1/screenshots/capture"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
breakpoints = [
{"name": "mobile", "width": 375, "device": "mobile"},
{"name": "tablet", "width": 768, "device": "tablet"},
{"name": "desktop", "width": 1440, "device": ""},
]
urls = [
"https://staging.client-site.com",
"https://staging.client-site.com/about",
"https://staging.client-site.com/pricing",
"https://staging.client-site.com/contact",
]
os.makedirs("previews", exist_ok=True)
for url in urls:
page_name = url.rstrip("/").split("/")[-1] or "home"
for bp in breakpoints:
params = {
"url": url,
"width": bp["width"],
"format": "png",
"full_page": "true",
"block_cookies": "true",
}
if bp["device"]:
params["device"] = bp["device"]
resp = requests.get(API, headers=HEADERS, params=params)
filename = f"previews/{page_name}-{bp['name']}.png"
with open(filename, "wb") as f:
f.write(resp.content)
print(f"Saved {filename}")
Run this once, get 12 screenshots organized by page and breakpoint. I usually drop them straight into a Notion page or Google Slides deck for the client. The whole thing takes about 30 seconds for four pages. Compare that to the manual alternative.
Responsive regression testing in CI/CD
Visual regression testing usually runs at one viewport. You capture a reference screenshot, then compare it against the current build. But responsive bugs hide at specific breakpoints. A padding issue that only appears at 768px. A hero image that overflows at 375px but looks fine at 1440px. A navigation collapse that breaks between 480px and 767px.
Testing at a single width misses all of these. Why not triple your coverage without tripling the effort? The API calls run in parallel.
// responsive-regression.js — run in CI
const breakpoints = [
{ name: 'mobile', width: 375, device: 'mobile' },
{ name: 'tablet', width: 768, device: 'tablet' },
{ name: 'desktop', width: 1440 },
];
const API = 'https://api.screenshotrun.com/v1/screenshots/capture';
async function captureBreakpoints(url) {
const captures = breakpoints.map(async (bp) => {
const params = new URLSearchParams({
url,
width: bp.width,
format: 'png',
block_cookies: 'true',
block_ads: 'true',
response_type: 'json',
...(bp.device && { device: bp.device }),
});
const resp = await fetch(`${API}?${params}`, {
headers: { Authorization: `Bearer ${process.env.SCREENSHOT_API_KEY}` },
});
const data = await resp.json();
return { breakpoint: bp.name, url: data.data.screenshot_url };
});
return Promise.all(captures);
}
// Capture all pages at all breakpoints
const pages = ['/', '/pricing', '/docs', '/blog'];
for (const page of pages) {
const results = await captureBreakpoints(`https://staging.myapp.com${page}`);
console.log(`${page}:`, results);
// Compare against reference images with your preferred diff tool
}
Each page gets three screenshots. Compare them against your stored reference images using pixel-diff tools like pixelmatch or Percy. Responsive bugs that would've slipped into production show up as red highlights in the diff.
Device-specific captures that go beyond viewport width
Setting width=375 gives you a narrow viewport. But a real iPhone does more than just narrow the viewport. It sends a mobile user agent. It reports touch support. It applies a 2x device pixel ratio. Sites use all of these signals to decide what to render.
I've seen e-commerce sites that show completely different product layouts based on the user agent string alone (not viewport width). Media sites that serve lighter images to mobile UAs. SaaS dashboards that hide entire feature sections on touch devices. If you only change the width, you miss all of that.
The device parameter handles the full package:
| Parameter | desktop (default) | mobile | tablet |
|---|---|---|---|
| Viewport | 1280×800 | 375×812 | 768×1024 |
| User agent | Chrome on Windows | Safari on iPhone | Safari on iPad |
| Touch emulation | Off | On | On |
| Device pixel ratio | 1x | 2x | 2x |
For deeper device emulation details (custom user agents, retina output, specific device dimensions), see the custom viewport feature page.
Build a responsive preview gallery
Some teams build internal tools that show responsive previews as a gallery — phone, tablet, and desktop side by side for every page on the site. Product managers use it to review launches. QA uses it as a visual checklist before every release. Marketing teams use it to verify that landing pages look right on the devices their audience actually uses (analytics show 60% mobile? better make sure the mobile layout works).
The webhook parameter is useful here. Instead of polling for results, the API sends a POST to your endpoint when each screenshot is ready. Your gallery app updates in real time as captures complete.
curl "https://api.screenshotrun.com/v1/screenshots/capture?\
url=https://mysite.com/landing\
&device=mobile\
&format=png\
&webhook_url=https://my-app.com/webhooks/screenshot-ready\
&response_type=json" \
-H "Authorization: Bearer YOUR_API_KEY"
The webhook payload includes the screenshot URL, the parameters you passed (so you know which breakpoint it belongs to), and a timestamp. Build a simple frontend that groups captures by URL and breakpoint, and you have a responsive preview dashboard without any browser automation to maintain.
What responsive screenshots miss (and how to work around it)
Device emulation isn't the same as running on a real device. The API uses headless Chromium on Linux, so there are differences worth knowing about.
Fonts. Chrome on Linux uses Liberation Sans where macOS shows Helvetica. If the site doesn't load web fonts via @font-face or Google Fonts, the screenshot may show slightly different text metrics. Line heights shift, text wraps at different points, and occasionally a heading that fits on one line on a Mac wraps onto two on Linux. For most sites with web fonts loaded, this doesn't matter. For pixel-perfect comparisons against a macOS design comp, it's worth knowing.
iOS Safari rendering quirks don't transfer. The API emulates mobile user agents and viewport dimensions, but the rendering engine is still Chromium. Safari-specific CSS bugs (the iOS viewport height issue with 100vh, WebKit-specific flexbox behaviors, iOS scroll bounce) won't appear in the screenshots. If you need to test actual Safari rendering, you still need a real device or BrowserStack.
Animations and scroll effects freeze at a point in time. Parallax effects, CSS transitions, and JavaScript animations render in whatever state they're in when the capture fires. The delay parameter controls when that moment is, but the screenshot is still a static snapshot. For animated elements, consider adding css=*{animation:none!important;transition:none!important;} to get a clean, repeatable capture.
How many API calls does responsive testing need?
How many? Depends on how many pages you test and at how many breakpoints. A typical setup: 3 breakpoints (mobile, tablet, desktop) across your key pages.
| Scenario | Pages | Breakpoints | Captures/run | Monthly (weekly runs) |
|---|---|---|---|---|
| Small site review | 8 | 3 | 24 | 96 |
| Agency client handoff | 15 | 3 | 45 | 180 |
| CI/CD on every deploy | 20 | 3 | 60 | 1,200 (20 deploys) |
| Large site QA sweep | 50 | 4 | 200 | 800 |
Even the CI/CD scenario stays well within the Starter plan. Responsive testing sounds expensive if you've priced out BrowserStack subscriptions or tried maintaining a Puppeteer device farm. The API turns it into a few hundred HTTP requests.
Responsive screenshots vs. BrowserStack and Responsively
BrowserStack Screenshots ($29/month for the cheapest plan that includes screenshots) captures on real devices — real iPhones, real Samsungs, real iPads. It's the gold standard for verifying platform-specific rendering. But it's slow (1-2 minutes per capture), the free tier barely exists, and there's no API for automation. You click through a web interface and wait.
Responsively App is free and open source. It shows multiple viewports side by side in real time as you develop. Excellent for local development. But it only works on your machine, it doesn't integrate into CI/CD, and you can't generate shareable preview images from it.
The API sits between the two. Faster than BrowserStack (2-3 seconds per capture), automatable, and good enough for 90% of responsive checks. Not real devices — emulated Chrome with device parameters. When pixel-perfect Safari rendering matters, use BrowserStack. When you need automated responsive previews at scale, the API is less setup and less cost.
FAQ#
Three breakpoints cover 95% of responsive layouts: 375px (mobile), 768px (tablet), and 1440px (desktop). These match the most common CSS media query breakpoints. If your analytics show significant traffic from specific devices like iPhone 16 Pro (402px) or iPad Pro 11-inch (834px), add those as a fourth or fifth breakpoint.
Setting width only changes the viewport size — the page still thinks it is running on a desktop browser. The device parameter (mobile, tablet) also sets a mobile user agent, enables touch emulation, and applies a 2x device pixel ratio. Sites that detect mobile browsers via navigator.userAgent or navigator.maxTouchPoints will render their actual mobile layout only when the device parameter is used.
Each API call captures one viewport configuration. To get mobile, tablet, and desktop screenshots, you make three separate API calls with different width or device parameters. The calls can run in parallel, so capturing all three breakpoints for one URL takes about the same time as a single capture (2-3 seconds).
Emulated. The API uses headless Chromium with device-specific viewport sizes, user agents, and touch emulation. It does not run on actual iPhones or iPads. This covers about 90% of responsive testing needs. For verifying Safari-specific CSS bugs or platform-specific rendering, you need a real device cloud like BrowserStack.
Use full_page=true to trigger scroll-based lazy loading, and add delay=2000 to give images time to render after scrolling. For pages using Intersection Observer, the API scrolls the full document before capturing, which triggers the observer callbacks. If specific images still appear as placeholders, increase the delay to 3000-4000ms.
Yes. Add dark_mode=true to each API call alongside your device or width parameter. This sets prefers-color-scheme: dark in the browser, so sites with CSS dark mode media queries render in dark mode. Capturing 3 breakpoints in both light and dark mode means 6 API calls per URL.