ScreenshotNeo

BlogHow-to

Why Is My Website Screenshot Blurry at Mobile Resolution?

Find out whether a blurry mobile screenshot comes from the viewport, image source, canvas, or capture pipeline, then fix and verify the right layer.

By the ScreenshotNeo team4 October 20269 min read

A website screenshot can look blurry on mobile because the page is being scaled from a wider virtual viewport, the browser selected an image with too few source pixels for its rendered size and device pixel ratio (DPR), a canvas has a low-resolution drawing buffer, or the capture/export pipeline resized the result. First compare the live page with the saved file at its native size. That tells you whether to inspect page rendering or screenshot processing.

CSS pixels describe layout; physical screen pixels describe the display. DPR relates the two. A screenshot that is enlarged beyond its native dimensions can look soft even when the browser rendered the page correctly. See MDN’s devicePixelRatio reference.

1. Identify which layer is blurry

  1. Open the page on the target phone and inspect the same area in the live browser.
  2. Open the saved screenshot at 100% scale, without zoom-to-fit or other viewer scaling.
  3. Compare the same text, borders, and image details.
What you see Likely area to inspect
The live page and saved file are both soft Viewport configuration, selected assets, CSS scaling, or canvas rendering.
The live page is sharp but the saved file is soft Capture dimensions, DPR settings, export resizing, compression, or later image processing.
Text is sharp but photographs are soft Image source selection, intrinsic size, or an enlarged raster asset.
Canvas artwork is soft while surrounding page content is sharp Canvas backing-buffer dimensions and drawing scale.

Use the image’s native pixel dimensions for this comparison. A preview that scales a large screenshot down to fit a window can look different from the image at 100%; conversely, enlarging a smaller image makes softness more visible.

2. Check the mobile viewport

For a responsive page, include a viewport declaration in the document head:

<meta name="viewport" content="width=device-width, initial-scale=1">

Without an appropriate viewport, some mobile browsers may lay out a page in a wider virtual viewport—typically 980 CSS pixels—and scale it down to fit the screen. That changes the effective layout and can make page content appear small. It can also affect which responsive image candidate is selected. MDN describes this behavior in its viewport meta documentation.

After adding or correcting the tag, reload the page and check the layout at the target width. Also look for horizontal overflow or CSS transforms that scale a large page or image down. The viewport tag enables the intended mobile layout; it cannot make a low-resolution source image contain more detail.

3. Check the image source and rendered size

For an <img>, inspect the candidate actually selected, its intrinsic dimensions, and its displayed CSS dimensions. In the browser console, select the image element and run:

const img = document.querySelector("img");
const rect = img.getBoundingClientRect();
console.table({
  currentSrc: img.currentSrc,
  intrinsicWidth: img.naturalWidth,
  intrinsicHeight: img.naturalHeight,
  renderedCssWidth: rect.width,
  renderedCssHeight: rect.height,
  devicePixelRatio: window.devicePixelRatio
});

currentSrc tells you which candidate the browser selected from srcset. naturalWidth and naturalHeight report the image’s intrinsic dimensions, while the bounding rectangle gives its rendered CSS dimensions. MDN documents currentSrc and how browsers choose from responsive image candidates.

As a rough diagnostic, compare intrinsic width with rendered CSS width multiplied by DPR. If the source has fewer pixels than the display needs, it may look soft; this is a clue, not a universal sharpness guarantee. Image quality, browser scaling, and the content itself also matter.

Provide suitable candidates and an accurate sizes hint for the layout:

<img
  src="/images/product-800.jpg"
  srcset="/images/product-480.jpg 480w,
          /images/product-800.jpg 800w,
          /images/product-1200.jpg 1200w"
  sizes="(max-width: 600px) 100vw, 800px"
  alt="Product shown from the front"
>

The width descriptors state the candidate widths. sizes describes the image’s expected rendered slot width so the browser can choose a suitable candidate. It does not change the CSS display size. Use candidates that cover the actual rendered sizes and densities in your layouts; avoid sending the largest file to every visitor when a smaller candidate will suffice. See MDN’s responsive images guide.

If the image is always displayed at a fixed CSS size and you have density variants, you can use density descriptors instead:

<img
  src="/images/icon-160.png"
  srcset="/images/icon-160.png 1x, /images/icon-320.png 2x"
  width="160"
  height="160"
  alt=""
>

For a different crop or composition on mobile, use <picture> with art-directed sources rather than stretching a small crop across a larger layout. For vector artwork such as simple icons, SVG can avoid the same fixed-raster-resolution limitation.

4. Check CSS background images

Background images do not use an <img> element’s srcset. If a CSS background needs alternatives for different pixel densities, CSS image-set() can offer resolution-labelled files:

.hero {
  background-image: image-set(
    url("/images/hero-1x.jpg") 1x,
    url("/images/hero-2x.jpg") 2x
  );
}

Confirm that the browser supports the syntax in your target environment and that each file contains enough detail for its intended display size. MDN documents CSS image-set().

5. Fix a canvas drawing buffer that is too small

A canvas has a drawing buffer set by its width and height attributes, separate from its CSS display size. If the buffer only has one pixel per CSS pixel, the browser may have to scale it for a higher-DPR display. Size the buffer using DPR, then scale the context so drawing coordinates remain in CSS pixels:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const rect = canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;

canvas.width = Math.round(rect.width * dpr);
canvas.height = Math.round(rect.height * dpr);
ctx.scale(dpr, dpr);

// Continue drawing in CSS-pixel coordinates.
ctx.fillRect(10, 10, 100, 40);

Run the sizing after the canvas has its intended CSS dimensions. If the element is resized later, resize the buffer and redraw; changing the canvas dimensions clears its drawing buffer. If you use a framework or chart library, check whether it already applies DPR scaling before adding another scale factor. Double-scaling can make drawings and coordinate calculations wrong. MDN’s canvas DPR example shows the same basic approach.

6. Reproduce the capture conditions

In Chrome DevTools, open Device Mode, choose a viewport or enter custom dimensions, and set DPR when needed. Capture the viewport or use the full-size screenshot command for the whole page. Compare the saved file’s pixel dimensions with the intended viewport and DPR. Chrome’s Device Mode documentation explains its viewport simulation, DPR controls, and screenshot options.

Emulation is useful for isolating viewport and image-selection issues, but it is an approximation. It does not establish that every operating system, browser, zoom level, or capture path behaves identically. When the discrepancy persists, compare against a capture made on the actual device and browser.

7. Inspect the screenshot pipeline

If the browser’s live rendering is sharp but the output file is not, check each transformation after rendering:

  • Capture viewport: Confirm the capture uses the intended CSS width, height, and DPR. A low-DPR capture can contain fewer output pixels than expected.
  • Output dimensions: Inspect the file’s actual pixel width and height. Do not infer them from the CSS viewport alone; capture tools may expose separate scale or output-size settings.
  • Resizing: Look for a later step that downsizes the screenshot, then enlarges it for display or export.
  • Format and quality: Lossy formats and aggressive compression can soften detail or introduce artifacts, especially around text and sharp edges. Compare a lossless output where available.
  • Viewing environment: Check the file at 100% in an image viewer. A browser preview or editor canvas may rescale it for presentation.

When comparing two captures, keep page URL, viewport, DPR, browser conditions, and output processing consistent. Otherwise, a change in one of those variables can be mistaken for an image or CSS fix.

8. Common problems and fixes

Symptom Likely cause What to do
The mobile layout looks like a scaled desktop page Missing or unsuitable viewport declaration. Add the viewport meta tag, reload, and inspect responsive breakpoints and horizontal overflow.
A photograph is soft but surrounding text is sharp The selected raster candidate lacks enough source detail, or the image is enlarged. Check currentSrc, intrinsic dimensions, rendered size, DPR, srcset, and sizes.
A chart or drawing is soft on a high-density screen Canvas backing dimensions match CSS dimensions only. Scale the drawing buffer by DPR, scale the context once, and redraw after resizing.
The live page looks sharp but the downloaded capture looks soft Capture DPR, output resizing, compression, or a later processing step. Compare dimensions and format at each stage; capture again with matched viewport and DPR.
Only a CSS hero or background looks soft A single background asset is being scaled to cover the layout. Provide adequate-resolution assets and consider image-set() or an art-directed mobile background.
The fix improves one phone but increases image weight elsewhere A large asset is being served to all viewport and density combinations. Provide responsive candidates and accurate sizes; verify the selected file across target conditions.
The canvas becomes the wrong size or drawing coordinates stop matching DPR scaling was applied more than once, or the canvas was resized without redrawing. Centralize buffer sizing, reset and apply the scale once, then redraw using CSS-pixel coordinates.

9. Performance, reliability, and cost tradeoffs

Higher-resolution raster candidates and larger screenshot outputs carry more image data. Choose source candidates that preserve detail at the target rendered size and DPR, but do not reflexively send oversized images to every device. Responsive image selection is designed to balance resolution and transfer cost. Canvas buffers also grow with DPR in both dimensions, so their pixel count grows approximately with DPR squared; account for memory and redraw work when sizing large canvases.

For repeatable diagnosis, record the target viewport, DPR, browser, image URL selected, and output dimensions. Repeat captures under the same conditions before attributing a change to a code fix. Use an actual device when emulation does not reproduce the reported issue.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. A single request captures a URL as an image or PDF; for this diagnosis, capture the target URL and compare its output dimensions and rendering with the device result. See the ScreenshotNeo API documentation.

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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Replace the example URL with your page. ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed; response headers report the page verdict and billing status. 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 and capture up to 1,000 screenshots a month with no card.

FAQ

Does a higher DPR always make a screenshot sharper?

No. Higher DPR can increase output detail when the capture path renders at that density, but it cannot restore detail missing from a source image or correct a later resize.

Does the CSS width attribute make an image sharper?

No. It affects the displayed dimensions and layout. Use a source with enough pixels for the rendered size and DPR, and let responsive image selection choose an appropriate candidate.

Why does the same image look sharp on desktop but soft on a phone?

The phone may render it at a different CSS size or DPR, or select a different responsive candidate. Inspect the actual selected URL and compare the source dimensions with the mobile rendered size.

Can I diagnose this from a screenshot alone?

A screenshot can reveal softness and its location, but without the live page, source assets, and capture conditions it may not identify which layer caused it. Compare against the target device and inspect the page and capture settings.