Why Mobile Screenshots Matter
Over 60% of web traffic comes from mobile devices. If your site looks broken on a phone, you’re losing customers. Manual testing on every device is impractical — there are hundreds of screen sizes to consider.
Automated mobile screenshots let you verify responsive layouts at every breakpoint without touching a physical device.
Common Mobile Viewports
Here are the key viewport sizes to test:
| Device | Width | Height | Scale |
|---|---|---|---|
| iPhone SE | 375 | 667 | 2x |
| iPhone 14 | 390 | 844 | 3x |
| iPhone 14 Pro Max | 430 | 932 | 3x |
| Samsung Galaxy S23 | 360 | 780 | 3x |
| iPad Mini | 768 | 1024 | 2x |
| iPad Pro 12.9" | 1024 | 1366 | 2x |
Basic Mobile Screenshot
Capture a screenshot at a mobile viewport using the ToolCenter:
const axios = require('axios');
async function mobileScreenshot(url, device = 'iphone14') {
const devices = {
iphone_se: { width: 375, height: 667, deviceScaleFactor: 2, mobile: true },
iphone14: { width: 390, height: 844, deviceScaleFactor: 3, mobile: true },
iphone14_max: { width: 430, height: 932, deviceScaleFactor: 3, mobile: true },
galaxy_s23: { width: 360, height: 780, deviceScaleFactor: 3, mobile: true },
ipad_mini: { width: 768, height: 1024, deviceScaleFactor: 2, mobile: true },
ipad_pro: { width: 1024, height: 1366, deviceScaleFactor: 2, mobile: true },
};
const config = devices[device] || devices.iphone14;
const response = await axios.post(
'https://api.toolcenter.dev/v1/screenshot',
{
url: url,
width: config.width,
height: config.height,
deviceScaleFactor: config.deviceScaleFactor,
mobile: config.mobile,
format: 'png',
},
{
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
responseType: 'arraybuffer',
}
);
return response.data;
}
Python Version
import requests
DEVICES = {
'iphone_se': {'width': 375, 'height': 667, 'deviceScaleFactor': 2, 'mobile': True},
'iphone14': {'width': 390, 'height': 844, 'deviceScaleFactor': 3, 'mobile': True},
'galaxy_s23': {'width': 360, 'height': 780, 'deviceScaleFactor': 3, 'mobile': True},
'ipad_mini': {'width': 768, 'height': 1024, 'deviceScaleFactor': 2, 'mobile': True},
}
def mobile_screenshot(url, device='iphone14'):
config = DEVICES.get(device, DEVICES['iphone14'])
response = requests.post(
'https://api.toolcenter.dev/v1/screenshot',
json={'url': url, 'format': 'png', **config},
headers={'Authorization': 'Bearer YOUR_API_KEY'}
)
return response.content
Capturing All Breakpoints at Once
Test your site across all device sizes in one shot:
const fs = require('fs');
async function captureAllBreakpoints(url) {
const breakpoints = [
{ name: 'mobile-small', width: 320, height: 568, mobile: true, deviceScaleFactor: 2 },
{ name: 'mobile', width: 375, height: 667, mobile: true, deviceScaleFactor: 2 },
{ name: 'mobile-large', width: 430, height: 932, mobile: true, deviceScaleFactor: 3 },
{ name: 'tablet', width: 768, height: 1024, mobile: true, deviceScaleFactor: 2 },
{ name: 'laptop', width: 1280, height: 800, mobile: false, deviceScaleFactor: 1 },
{ name: 'desktop', width: 1920, height: 1080, mobile: false, deviceScaleFactor: 1 },
];
const results = await Promise.all(
breakpoints.map(async (bp) => {
const response = await axios.post(
'https://api.toolcenter.dev/v1/screenshot',
{
url: url,
width: bp.width,
height: bp.height,
mobile: bp.mobile,
deviceScaleFactor: bp.deviceScaleFactor,
format: 'png',
},
{
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
responseType: 'arraybuffer',
}
);
return { name: bp.name, data: response.data };
})
);
// Save all screenshots
for (const result of results) {
fs.writeFileSync(`screenshots/${result.name}.png`, result.data);
}
return results;
}
User Agent Strings
Mobile sites sometimes serve different content based on the User-Agent. Set it to match the device:
const response = await axios.post(
'https://api.toolcenter.dev/v1/screenshot',
{
url: 'https://example.com',
width: 390,
height: 844,
mobile: true,
deviceScaleFactor: 3,
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
format: 'png',
},
{
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
responseType: 'arraybuffer',
}
);
Landscape Mode
Capture landscape orientations by swapping width and height:
async function landscapeScreenshot(url) {
const response = await axios.post(
'https://api.toolcenter.dev/v1/screenshot',
{
url: url,
width: 844, // iPhone 14 height becomes landscape width
height: 390, // iPhone 14 width becomes landscape height
mobile: true,
deviceScaleFactor: 3,
format: 'png',
},
{
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
responseType: 'arraybuffer',
}
);
return response.data;
}
Automating Responsive Testing in CI/CD
Integrate mobile screenshots into your deployment pipeline:
# .github/workflows/responsive-test.yml
name: Responsive Design Test
on:
pull_request:
branches: [main]
jobs:
screenshots:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install
- run: node scripts/capture-responsive.js
env:
DEVTOOLBOX_API_KEY: ${{ secrets.DEVTOOLBOX_API_KEY }}
TARGET_URL: ${{ github.event.deployment.environment_url }}
- uses: actions/upload-artifact@v4
with:
name: responsive-screenshots
path: screenshots/
Building a Responsive Preview Dashboard
Create a simple dashboard that shows all device previews:
const express = require('express');
const app = express();
app.get('/preview', async (req, res) => {
const { url } = req.query;
if (!url) return res.status(400).send('URL required');
const devices = [
{ name: 'iPhone SE', width: 375, height: 667, mobile: true, deviceScaleFactor: 2 },
{ name: 'iPhone 14', width: 390, height: 844, mobile: true, deviceScaleFactor: 3 },
{ name: 'iPad', width: 768, height: 1024, mobile: true, deviceScaleFactor: 2 },
{ name: 'Desktop', width: 1440, height: 900, mobile: false, deviceScaleFactor: 1 },
];
const screenshots = await Promise.all(
devices.map(async (device) => {
const response = await axios.post(
'https://api.toolcenter.dev/v1/screenshot',
{ url, ...device, format: 'png' },
{ headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, responseType: 'arraybuffer' }
);
const base64 = Buffer.from(response.data).toString('base64');
return { ...device, image: `data:image/png;base64,${base64}` };
})
);
const html = `
<html><body style="font-family:system-ui;padding:20px;">
<h1>Responsive Preview: ${url}</h1>
<div style="display:flex;gap:20px;flex-wrap:wrap;">
${screenshots.map(s => `
<div style="text-align:center;">
<h3>${s.name} (${s.width}×${s.height})</h3>
<img src="${s.image}" style="max-width:300px;border:1px solid #ddd;border-radius:8px;" />
</div>
`).join('')}
</div></body></html>
`;
res.send(html);
});
app.listen(3000);
Monitoring Responsive Breakages
Set up automated checks that catch responsive issues:
import requests
from PIL import Image
from io import BytesIO
def check_responsive(url):
issues = []
# Capture mobile screenshot
response = requests.post(
'https://api.toolcenter.dev/v1/screenshot',
json={'url': url, 'width': 375, 'height': 667, 'mobile': True, 'fullPage': True, 'format': 'png'},
headers={'Authorization': 'Bearer YOUR_API_KEY'}
)
img = Image.open(BytesIO(response.content))
# Check if page is wider than viewport (horizontal scroll)
if img.width > 375 * 2: # Account for device scale factor
issues.append('Horizontal overflow detected on mobile')
# Check if page is extremely tall (possible layout break)
if img.height > 667 * 2 * 10:
issues.append('Page is unusually tall on mobile — possible layout issue')
return issues
Conclusion
Mobile screenshot testing with the ToolCenter eliminates the need for device farms and manual testing. Capture every viewport size programmatically, integrate it into your CI/CD pipeline, and catch responsive design issues before your users do. The parallel request support means you can test 6+ breakpoints in the time it takes to capture one screenshot.