How to Set a Custom Viewport and Device Scale Factor for Selenium Screenshots
Set Selenium screenshot dimensions and device pixel ratio with Chrome emulation, then check the captured pixel size and choose viewport or full-page output.
To control a Chromium-based Selenium screenshot’s viewport and pixel density, set the emulated device width, height, and device scale factor (DPR). In Chrome DevTools Protocol (CDP), use Page.setDeviceMetricsOverride with width, height, deviceScaleFactor, and mobile. In Selenium’s documented JavaScript Chromium API, custom mobile emulation accepts width, height, and pixelRatio. Choose viewport-only or full-page capture separately: those settings describe the emulated page, not how much of it a screenshot contains.
This guide focuses on Chrome and Chromium because the device-metrics controls are CDP features. Selenium bindings, browser versions, and driver versions differ; confirm that your chosen API is supported by the versions you run.
1. Understand viewport, DPR, mobile mode, and screenshot scope
These settings solve different problems. Chrome defines DPR as the ratio between physical screen pixels and logical CSS pixels. For a viewport of 400 by 800 CSS pixels at DPR 2, a viewport screenshot may be 800 by 1600 image pixels. Check the actual output: capture behavior and full-page implementation can affect the dimensions.
| Setting | What it controls | What to check |
|---|---|---|
| Width and height | Emulated screen and viewport-related dimensions | window.innerWidth, window.innerHeight, and media queries |
| DPR / device scale factor | Relationship between CSS pixels and physical pixels | window.devicePixelRatio and resulting image dimensions |
| Mobile mode | Emulated device behavior in addition to dimensions | Responsive layout and mobile-specific behavior |
| Screenshot scope | Visible viewport or the full document | Image dimensions and whether below-the-fold content appears |
Setting a browser window size is not necessarily equivalent to setting emulated page metrics. When you need explicit control of Chromium’s viewport-related dimensions and DPR, use device emulation. Choose mobile mode deliberately; dimensions alone do not mean mobile behavior is enabled.
2. Configure custom mobile emulation in Selenium JavaScript
Selenium’s documented JavaScript Chromium API provides setMobileEmulation with a custom screen configuration. Its example uses 360 by 640 and a pixel ratio of 3.0; those are example values, not universal recommendations. Replace them with the dimensions and density you need.
const { Builder, By } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
async function main() {
const options = new chrome.Options();
options.setMobileEmulation({
deviceMetrics: {
width: 400,
height: 800,
pixelRatio: 2
}
});
const driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build();
try {
await driver.get('https://example.com');
await driver.wait(async () => {
return await driver.executeScript('return document.readyState') === 'complete';
}, 15000);
const metrics = await driver.executeScript(`return {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
devicePixelRatio: window.devicePixelRatio,
documentWidth: document.documentElement.scrollWidth,
documentHeight: document.documentElement.scrollHeight
}`);
console.log(metrics);
// Selenium's element screenshot API captures this element.
const element = await driver.findElement(By.css('body'));
await element.takeScreenshot().then(data =>
require('node:fs').writeFileSync('element.png', data, 'base64')
);
// A driver screenshot captures the current viewport in standard Selenium usage.
const screenshot = await driver.takeScreenshot();
require('node:fs').writeFileSync('viewport.png', screenshot, 'base64');
} finally {
await driver.quit();
}
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});
Install the binding with npm install selenium-webdriver and make Chrome available to Selenium. The exact options API is version-dependent; consult the Selenium JavaScript Chrome Options API for the version you use. A document-sized element screenshot is not a universal substitute for a browser’s full-page screenshot facility, especially for long or dynamically loaded pages.
3. Apply CDP device metrics from Selenium
CDP’s Page.setDeviceMetricsOverride exposes width, height, deviceScaleFactor, and mobile. It also overrides screen dimensions, window.innerWidth, window.innerHeight, and device-width/device-height media-query results. CDP command access differs by Selenium binding and version, so this Python example uses Selenium’s Chromium driver command interface to send the protocol command.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
options = Options()
# Add your environment's Chrome options here, for example headless mode if needed.
driver = webdriver.Chrome(options=options)
try:
driver.execute_cdp_cmd("Page.setDeviceMetricsOverride", {
"width": 400,
"height": 800,
"deviceScaleFactor": 2,
"mobile": True
})
driver.get("https://example.com")
WebDriverWait(driver, 15).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
print(driver.execute_script("return {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
dpr: window.devicePixelRatio,
documentWidth: document.documentElement.scrollWidth,
documentHeight: document.documentElement.scrollHeight
}"))
# Selenium's regular screenshot call captures the current viewport.
driver.save_screenshot("viewport.png")
finally:
driver.quit()
Run with pip install selenium, a compatible Chrome installation, and a Selenium-supported driver setup. execute_cdp_cmd is Chromium-specific. For another binding, use its documented CDP command mechanism and verify its signature against the installed Selenium version. The CDP reference is the moving Page domain protocol documentation; check the version matching your Chrome/driver when compatibility matters.
To clear the device-metrics override during the same session, send the command again with the reset values supported by your CDP version; the protocol documents zero for deviceScaleFactor as disabling that override. Starting a fresh browser session is a straightforward way to return to default emulation state.
4. Set DPR with cURL or direct CDP
cURL does not configure Selenium. It can send CDP only if you already have a running Chrome debugging endpoint and know its WebSocket URL. CDP commands are WebSocket messages, not ordinary HTTP requests to the browser debugging port, so a generic cURL request alone is not a runnable way to set device metrics. Use Selenium’s CDP interface or a WebSocket CDP client instead.
For example, the command payload you need to send over the active CDP session is:
{
"method": "Page.setDeviceMetricsOverride",
"params": {
"width": 400,
"height": 800,
"deviceScaleFactor": 2,
"mobile": true
}
}
The CDP session and target attachment determine where that command applies. Do not expose a remote debugging port to untrusted networks.
5. Choose viewport-only or full-page capture
A standard Selenium screenshot captures what is visible in the viewport. Chrome’s DevTools screenshot instructions distinguish a visible viewport capture from a full-size capture that includes content outside it. Choose the capture mechanism that explicitly provides the scope you need, and verify output dimensions rather than inferring them from the requested CSS dimensions.
- Viewport-only: use a normal Selenium screenshot after setting metrics; it captures the current visible browser viewport.
- Element: use the Selenium element screenshot API when only a particular element is needed. Ensure it is visible and positioned as expected.
- Full page: use the browser or driver facility documented for full-page capture in your Selenium/browser version. A normal viewport screenshot does not include the entire page.
For full-page captures, lazy-loaded images and content may not exist until scrolled into view. Scroll through the page and wait for content to settle when that content must appear, then use the full-page mechanism. Very long documents may produce large images, and the final image’s pixel dimensions may not equal viewport width and height multiplied by DPR in every capture path.
6. Validate the emulation and image dimensions
- Set width, height, DPR, and mobile mode explicitly.
- Navigate to the target page and wait for the content needed in the capture.
- Read
window.innerWidth,window.innerHeight, andwindow.devicePixelRatiofrom the page. - Check responsive media queries and the document’s scroll dimensions if layout is unexpected.
- Inspect the saved image’s actual pixel dimensions. For a typical viewport capture, expected dimensions are approximately CSS viewport dimensions multiplied by DPR, but verify rather than assume.
- Repeat with viewport-only and full-page capture to confirm the intended scope.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Screenshot has the wrong pixel dimensions | Confusing CSS dimensions with physical image pixels, using a different DPR, or capturing a different scope | Log viewport dimensions and devicePixelRatio; inspect the file dimensions; confirm viewport versus full page. |
| Layout stays desktop-like at phone width | Width and height were changed without enabling mobile emulation, or page responsive behavior depends on other signals | Set mobile mode explicitly and inspect the viewport meta tag and relevant media queries. |
window.innerWidth differs from configured width |
Window sizing was used instead of emulated device metrics, command did not apply to the active target, or the API signature differs | Apply the override to the current page target before checking, and verify the binding’s CDP method and browser version. |
| CDP command is unavailable or rejected | Non-Chromium browser, incompatible driver/binding, unsupported protocol command, or wrong parameter names | Use a Chromium browser and matching driver; consult the protocol version for that browser and the Selenium binding documentation. |
| Only the visible portion appears | Normal screenshot API captured the viewport | Use a full-page capture facility supported by your browser/driver and check its output dimensions. |
| Full-page image omits images or sections | Lazy loading, animation, delayed requests, or content requiring scroll interaction | Scroll the page, wait for target content to load and animations to settle, then capture. |
| Screenshot is blank or page is incomplete | Capture started before navigation or application rendering finished | Wait for the relevant selector or app-specific ready condition rather than relying only on a fixed short delay. |
| Emulation differs from a real phone | Desktop device mode is an approximation and does not reproduce all device hardware behavior | Validate hardware-dependent or device-specific behavior on the actual target device. |
8. Performance, reliability, and cost
Emulation changes rendering metrics; it does not itself guarantee that a page is ready to capture. Use a condition tied to the content you need, and avoid waiting for a fixed interval if a meaningful selector or application-ready signal is available. Full-page capture can require more rendering, memory, and image storage than viewport capture, particularly on long documents or at a high DPR. Choose the smallest viewport and density that answer the test question.
For repeatable runs, pin and record Selenium, Chrome, and driver versions, apply metrics consistently before measuring the page, and log the configured values with the resulting screenshot. Mobile emulation is a first-order approximation of mobile appearance, not a physical device. There is no separate charge inherent in these Selenium configuration settings; your costs depend on the machines and infrastructure used to run the browser.
9. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its one-call API returns a screenshot or PDF, and the API documentation lists the supported options, including viewport dimensions and device presets.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Use the same API request options to specify the capture configuration you need; see the docs for parameter names and supported values. ScreenshotNeo removes cookie banners, popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account to get started.
10. FAQ
Does DPR change CSS layout width?
DPR describes the relationship between physical pixels and CSS pixels. Set viewport dimensions and DPR separately, then inspect the page’s reported values and responsive layout.
Can emulation prove a page works on a particular phone?
No. It approximates mobile behavior in a desktop browser. Test on the actual device when hardware or device-specific behavior is important.
Do I need a mobile user agent as well?
Mobile mode and DPR are distinct controls. Whether a page depends on user-agent-specific behavior is application-dependent; configure and verify the signals your test requires.
Why can two screenshots with the same viewport settings differ in size?
They may use different screenshot scopes or capture implementations. Compare actual output dimensions and confirm whether each capture is viewport-only, element, or full page.


