# Retina and high-DPI website screenshots: 2× and 3× captures, file sizes and limits

> Take sharp retina website screenshots at 2× or 3×: device pixel ratio in Puppeteer, Playwright and our API, file sizes measured, and the width cap.

Published 2026-11-08 · https://shareglint.com/en/guides/retina-screenshots

A screenshot taken at 1× looks soft on almost every screen people use today: phones, most laptops and many monitors draw two or three physical pixels per CSS pixel. A "retina" or high-DPI screenshot captures the page at that density, so text and icons stay crisp when the picture is shown at its intended size. This page shows how in Puppeteer, Playwright and our API, and what the extra pixels cost in file size.

**How we measured.** On 2026-11-08 we captured python.org's first screen at a 1280×800 viewport through our API at pixel ratios 1, 2 and 3, as PNG and WebP, plus a full page at 2× and two over-wide requests to see the cap.

## What the pixel ratio does

The page does not change. A 1280×800 viewport lays the page out at 1280 CSS pixels wide in every case, with the same breakpoints, the same line breaks and the same layout. Only the drawing changes: at ratio 2 each CSS pixel is drawn as 2×2 image pixels, at ratio 3 as 3×3. Text is rasterised at the higher density, so the letters are sharper, not just bigger. In the browser the same number is [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio).

That is different from a bigger viewport. 2560×1600 at 1× is a different layout — the page sees a wide desktop and may show more columns — and its text stays the same physical size, so it looks tiny when the picture is shrunk to fit.

## Puppeteer and Playwright

```javascript
// Puppeteer
await page.setViewport({ width: 1280, height: 800, deviceScaleFactor: 2 });
await page.screenshot({ path: 'retina.png' });
```

```javascript
// Playwright
const context = await browser.newContext({ viewport: { width: 1280, height: 800 }, deviceScaleFactor: 2 });
const page = await context.newPage();
await page.screenshot({ path: 'retina.png' });
```

Puppeteer's `deviceScaleFactor` is documented as "Specify device scale factor. See devicePixelRatio for more info" ([Puppeteer: Viewport](https://pptr.dev/api/puppeteer.viewport)). Playwright adds a `scale` option on `screenshot()`: `"device"` (the default) keeps one image pixel per device pixel, `"css"` one per CSS pixel, so "screenshots of high-dpi devices will be twice as large or even larger" with the default ([Playwright: page.screenshot](https://playwright.dev/docs/api/class-page)). Device descriptors set the ratio for you: an iPhone 15 is 3.

## Our API: `scale`

```bash
curl -X POST "https://shareglint.com/v1/screenshots?wait=true" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.python.org/", "scale": 2, "format": "webp", "block_cookie_banners": true}'
```

`scale` takes 1, 2 or 3 (`1.5` was refused with "`scale` must be one of: 1, 2, 3."); device presets bring their own ratio unless you set it. What came back:

| Ratio | Picture | PNG | WebP (quality 85) |
|---|---|---|---|
| 1 | 1280×800 | 133 KB | 56 KB |
| 2 | 2560×1600 | 323 KB | 129 KB |
| 3 | 3840×2400 | 533 KB | 208 KB |
| 2, full page | 2560×5216 | 1.1 MB | — |

Four times the pixels at 2× cost 2.4 times the PNG bytes and 2.3 times the WebP bytes: flat areas compress no matter how many pixels they cover. Render times were 6.5–9.0 s for all of them, the page's own loading dominating; the pixel ratio barely showed.

## The width cap

A file is at most **7,680 px** wide. When `viewport_width × scale` would exceed that, the ratio is lowered to fit instead of refusing the request: a 3840×1080 viewport at `scale: 3` came back as 7680×2160 — the same picture as `scale: 2`, and in fact the same file, because the lowered request matched the cached one. Chrome itself captures up to 16,384 px; the lower cap keeps files at a size anyone can open.

The height of a full-page capture has its own cap, 16,000 px of picture, and it counts image pixels, not CSS pixels. At 2× a long page is therefore cut after half as much of the page as at 1×, and at 3× after a third. For a very long article or a documentation page, a full-page capture at 1× shows the whole page where a 3× one stops partway; pick the ratio by how the picture will be used, not by habit.

## Which ratio to use

- **2×** for anything shown on a web page, in docs, in a slide or an email at its natural size. It matches most laptops and many phones, and it is the sweet spot of sharpness per byte.
- **3×** for phone screenshots meant to look native on a phone (App Store-style images; our `iphone-15` preset uses 3) and for print at small sizes.
- **1×** for thumbnails you will shrink anyway, visual-regression baselines (smaller diffs, faster comparisons) and anything where file size matters more than detail.

If the picture will be displayed smaller than its CSS size — a 1280 px page shown 400 px wide — 1× is already more than enough pixels; capture at 1× and resize ([website thumbnails](https://shareglint.com/en/guides/website-thumbnails)). Ratio only helps when the image is shown at or near its CSS size on a dense screen.

## In HTML: tell the browser what you have

A 2× image shown at its CSS size needs its CSS size in the markup, or it is drawn twice as large:

```html
<img src="shot-2x.webp" width="1280" height="800" alt="python.org home page">
<!-- or offer both and let the browser pick -->
<img src="shot-1x.webp" srcset="shot-1x.webp 1x, shot-2x.webp 2x" width="1280" height="800" alt="python.org home page">
```

To check what a page actually shows, open the image in DevTools and compare its `naturalWidth` (pixels in the file) with its rendered width (CSS pixels on the page): a 2× screenshot shown correctly has a `naturalWidth` twice the rendered width. If the two are equal on a retina screen, the browser is stretching a 1× picture, which is the usual reason a screenshot looks soft in a blog post or a README.

## Cost

The pixel ratio does not change the price: a viewport capture is 1 render of the quota at any `scale`, a full page 2, and repeats with the same options within 24 hours are free ([pricing](https://shareglint.com/en/pricing)). For phone-sized pictures with the right ratio and user agent, see [mobile website screenshots](https://shareglint.com/en/guides/mobile-website-screenshot); for why 1× pictures look blurry, [blank or blurry screenshots](https://shareglint.com/en/guides/puppeteer-screenshot-blank-or-blurry).

## FAQ

### How do I take a retina screenshot of a website?

Capture with a device pixel ratio of 2 (or 3). The page lays out at the same CSS size, but every CSS pixel becomes 2×2 (or 3×3) image pixels, so a 1280×800 viewport gives a 2560×1600 picture. In Puppeteer set deviceScaleFactor: 2 in setViewport; in Playwright set deviceScaleFactor on the context; in our API send "scale": 2.

### How much bigger is a 2× screenshot?

Four times the pixels, less than four times the bytes. python.org's first screen was 133 KB at 1×, 323 KB at 2× and 533 KB at 3× as PNG; as WebP 56, 129 and 208 KB.

### Is there a maximum size?

Our API caps the file's width at 7,680 px and lowers the pixel ratio to fit: a 3840 px wide viewport asked at 3× came back at 2×, 7680×2160. Chrome's own capture limit is 16,384 px; full-page heights have their own cap of 16,000 px.
