ScreenshotNeo

BlogHow-to

How to Set a Screenshot API Device Scale Factor for Retina Captures

Set a screenshot’s device scale factor for sharper 2x output. Learn the difference between browser DPR and image scale, with runnable examples and troubleshooting.

By the ScreenshotNeo team4 October 20268 min read

For a 2x retina screenshot, set the browser’s device scale factor (also called device pixel ratio, or DPR) to 2. The exact parameter and where you set it depend on the browser library or screenshot API. In Playwright, set deviceScaleFactor: 2 on the browser context; to save one output pixel per device pixel, also set screenshot scale: "device". These are separate controls. For a hosted API, check its current documentation for the accepted option and how it maps to output pixels.

What device scale factor changes

The device scale factor tells the browser how device pixels relate to CSS pixels. At a factor of 2, a 400 × 300 CSS-pixel viewport can be rendered using a 800 × 600 device-pixel surface. Whether the downloaded image has those dimensions also depends on the screenshot tool’s output scale setting and capture mode.

In Playwright, deviceScaleFactor configures the browser context’s device pixel ratio. The screenshot option scale controls output pixels: "css" produces one image pixel per CSS pixel, while "device" produces one per device pixel. Thus, a DPR of 2 alone does not guarantee a 2x-sized saved file if output is explicitly scaled to CSS pixels. [Playwright browser type documentation]

Setting Controls Typical retina choice
Viewport width and height Page layout size in CSS pixels Set to the intended layout viewport
Device scale factor / DPR Browser’s device-pixel ratio 2 for a common 2x capture
Screenshot output scale Pixels written per CSS pixel device in Playwright for device-pixel output

Playwright: runnable Node.js example

Install Playwright and its Chromium browser, then save this as retina-shot.mjs. It captures a 1440 × 900 CSS-pixel viewport at DPR 2 and saves a PNG at device scale.

npm install -D playwright
npx playwright install chromium
import { chromium } from 'playwright';

const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
  viewport: { width: 1440, height: 900 },
  deviceScaleFactor: 2,
});
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'retina.png', fullPage: true, scale: 'device' });
await browser.close();

Run it with node retina-shot.mjs. Replace the target URL with a page you are authorized to capture. A full-page image’s dimensions depend on the rendered document height; a viewport screenshot uses the configured viewport dimensions. Playwright documents that device-scale screenshots can be twice as large or larger. [Playwright screenshot documentation]

Playwright options to choose deliberately

  • viewport: width and height in CSS pixels. Keep this fixed when comparing captures so layout changes do not get mistaken for scale changes.
  • deviceScaleFactor: browser context setting. Use 2 for 2x; use 1 for standard density. It belongs on the context, not the screenshot call.
  • scale: screenshot option, "css" or "device". Choose "device" when the image should retain device-pixel density.
  • fullPage: captures the full scrollable page. It can create a very tall, large image; use a viewport capture if you only need the visible area.
  • type and path: select a supported image format and output path as needed. For this example, the default PNG is explicit through the filename.

For consistent visual checks, set the viewport, DPR, output scale, browser version, and page readiness condition explicitly. A retina setting changes pixel density, not the page’s CSS layout width.

Browserless hosted screenshot API

Browserless documents a REST Screenshot API that accepts a URL and screenshot options, including viewport configuration and device scale factor. Its viewport reference lists deviceScaleFactor and says the default is 1. Use the endpoint’s current request schema when preparing a request: the REST documentation notes Puppeteer-style screenshot options, and configuration surfaces can differ by API version. [Browserless REST Screenshot API; Browserless viewport reference]

The dossier does not provide a verified REST request body for a particular Browserless version, so do not copy an assumed JSON shape. Consult its current REST or OpenAPI reference, then set the documented device scale factor to 2 and confirm whether its output dimensions use CSS or device pixels.

Browserless also shows a GraphQL viewport mutation with width, height, and deviceScaleFactor; its example uses a 375 × 667 viewport and supplies the factor explicitly. Treat that as a documentation example, not a claim that a request was run.

Other tools: parameter names differ

There is no universal screenshot API parameter name, allowed range, or output behavior. ScreenshotAPI’s reference lists deviceScaleFactor from 1 to 5 and separately describes CSS versus device rendering scale. Check how the provider combines these settings before relying on specific output dimensions. [ScreenshotAPI documentation]

For the shot-scraper command-line tool, its documentation describes --retina as using device scale factor 2. This is specific to that tool, not a portable API parameter. [shot-scraper screenshot documentation]

cURL, Python, and Node.js with ScreenshotNeo

ScreenshotNeo is a website screenshot API. Its API accepts common screenshot API parameter names, including deviceScaleFactor, to make switching easier. Set it to 2 for a 2x capture. Check the ScreenshotNeo API documentation for the current options and output formats. These examples save the returned image bytes; use a target URL you are authorized to capture.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -d deviceScaleFactor=2 \
  -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://stripe.com",
        "deviceScaleFactor": 2,
    },
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
  deviceScaleFactor: '2',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

The Node.js example uses Bun’s file writer to keep the fetch example compact. In Node.js, save the response body with the built-in filesystem API instead:

import { writeFile } from 'node:fs/promises';

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
  deviceScaleFactor: '2',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Or skip the browser setup

With ScreenshotNeo, one GET request returns a screenshot. Cookie banners are accepted like a visitor and 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers say whether the page was clean and billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -d deviceScaleFactor=2 \
  -o shot.webp

Sign up for 1,000 free screenshots a month, with no card required.

Verify the output dimensions

  1. Record the CSS viewport width and height.
  2. Set DPR to 2 in the browser context or API request.
  3. Choose device-pixel output if the tool exposes a separate scale setting.
  4. Capture a viewport-only image and inspect its pixel dimensions. With a 1440 × 900 CSS viewport and 2x device-pixel output, the expected viewport image is 2880 × 1800 pixels.
  5. If dimensions remain 1440 × 900, check whether output scale is set to CSS pixels or the service ignores/does not support the DPR option.

For full-page captures, compare width first and account for document height and lazy-loaded content. Do not assume the height is exactly twice a previous capture if the page rendered differently.

Common problems and fixes

Symptom Likely cause Fix
Image dimensions are unchanged DPR is set, but screenshot output is CSS-scaled; or the API ignored the option. For Playwright, set scale: "device". For a hosted API, confirm the parameter name and output behavior in its current reference.
Page layout looks different The viewport width changed, or the target page uses responsive breakpoints. Keep CSS viewport dimensions the same while changing only DPR.
Screenshot is unexpectedly large Full-page capture, high DPR, or a long document increased pixel dimensions. Use viewport-only capture, lower DPR, or resize/compress after capture if supported by your workflow.
Option is rejected or silently ignored Provider uses a different name, range, nesting, or API version. Check the provider’s endpoint reference and accepted values; do not assume one service’s request shape works on another.
Fonts or images appear incomplete Capture happened before page assets loaded or before lazy content entered view. Wait for an appropriate selector or readiness condition; for Playwright, choose a navigation wait condition suited to the page and wait for a key element where needed.
Retina output looks soft The page’s source images or CSS assets are low resolution, or the image was later downscaled/upscaled. Check the original asset resolution and avoid enlarging a 1x image after capture. DPR cannot create detail absent from the source.

Performance, reliability, and cost

At DPR 2, a viewport capture has about four times as many pixels as the same CSS-sized capture at DPR 1; DPR 3 has about nine times as many. This follows from multiplying both image dimensions by the scale factor. More pixels can increase encoding time, memory use, response size, and downstream storage or transfer costs. Full-page captures amplify this because page height is also included.

Use the lowest DPR that meets the display or inspection need. Keep capture settings fixed for repeatable comparisons, set an explicit timeout, and retry only transient failures with a bounded retry policy. A timeout or blank result should not be interpreted as a successful image; inspect the response status and any provider-specific result headers.

ScreenshotNeo bills only clean shots: bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Its response includes X-Page-Verdict and X-Billed headers. Listed monthly plans are Free with 1,000 shots, Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free, and every feature is on every plan. Higher pixel counts still produce larger files to transfer and store, so factor those into your own infrastructure.

FAQ

Is a physical retina display or accessory required?

No. The cited configuration is software-controlled through browser or screenshot-tool settings; it does not require hardware.

Is device scale factor the same as viewport size?

No. Viewport dimensions describe CSS layout size; device scale factor describes pixel density. Set both explicitly when reproducibility matters.

Should I always use 2x?

No. Use 2 when the consuming display or workflow needs 2x pixels. Higher factors increase pixel count and file size without restoring detail missing from the page’s assets.

Can I use the same parameter with every screenshot API?

No. Names, ranges, defaults, and output scaling differ. Use the target provider’s current API reference.