Open source · MIT · Node 20+

find-oversized-images

A command line tool that finds images much bigger than the size they are shown at, then writes the srcset and sizes that fix them. It checks a phone, a tablet and a desktop viewport and estimates how many KB you would save.

npx find-oversized-images https://example.com

What it does

Lighthouse says “properly size images”. This tells you which ones, by how much, and why the browser got a file that big. It opens the page in the Chrome or Edge you already have (headless, no browser download), at phone, tablet and desktop size. For every <img> it compares the file's pixels with the pixels the screen can actually use, taking object-fit and device pixel ratio into account. Because it measures the same image at three widths, it can also write the responsive markup that fixes it, not just name the problem. No browser window opens: the browser runs in the background and the report prints in your terminal.

Sample output

A real run on the Wikipedia article for Cat, desktop only:

npx find-oversized-images https://en.wikipedia.org/wiki/Cat --desktop
https://en.wikipedia.org/wiki/Cat

Desktop 1366x768 @1x   54 images, 2 oversized, 17 not loaded, LCP: not an <img>
  extra  unused  file     shown     size  est. save  image
   2.0x     75%  250x167  124x83   14 KB      ~7 KB  250px-Felis_catus-cat_on_snow.jpg
    Fix: No srcset, so every screen downloads this 250px file. Add a srcset that includes a 125w version.
   2.0x     75%  250x357  125x178  32 KB     ~16 KB  250px-Gustav_chocolate.jpg
    Fix: No srcset, so every screen downloads this 250px file. Add a srcset that includes a 125w version.
  Total: ~23 KB could be saved (estimate, conservative)
ColumnMeaning
extraHow many times wider the file is than the screen can use. 1 is right-sized. Images at 2 or more are listed.
unusedShare of the file's pixels that never reach the screen.
file / shownFile size in pixels, and the box it is drawn in (CSS pixels).
sizeBytes over the network, as the browser reports them. Works for cross-origin images too.
est. saveA rough, deliberately low estimate: size x (1 - 1 / extra).
Fix (line below)Why the browser got a file that big: no srcset, a sizes value wider than the box, no small enough file in srcset, or x descriptors. Shopify images also get the width= to request.

The saving is scaled by width only, so it stays on the low side. Use it to decide what to fix first, not as a measurement. When the Largest Contentful Paint image is oversized, it is marked <- LCP. Images with the same box and the same problem, like a grid of product cards, are one row with a count.

Paste-ready fixes

Knowing an image is 3x too big still leaves you to work out what sizes should be. That is the part this does for you.

npx find-oversized-images https://example.com --fix-code

It writes image-fixes.md with one block per image, and puts the same blocks in the HTML report:

<!-- keep this image's other attributes (alt, class, loading) -->
<img
  src="https://cdn.shopify.com/s/files/1/abaya.jpg?v=1778&width=750"
  srcset="https://cdn.shopify.com/s/files/1/abaya.jpg?v=1778&width=300 300w,
          https://cdn.shopify.com/s/files/1/abaya.jpg?v=1778&width=600 600w,
          https://cdn.shopify.com/s/files/1/abaya.jpg?v=1778&width=750 750w"
  sizes="(max-width: 480px) 242px, (max-width: 1024px) 299px, 280px">

On the Shopify CDN those URLs work as they are, because Shopify resizes on request. Everywhere else you get the widths and placeholder names, and a line saying those files have to be produced: the tool will not invent URLs for files that do not exist. On WordPress there is no per-image snippet either, since WordPress builds srcset from its registered sizes, so it prints the widths to register instead.

The values lean slightly high on purpose. Measurements are taken at 390, 768 and 1366 pixels, but each media query covers a range, and a file that is a little too big costs bytes while a file that is too small is visibly blurry. An image that could not be measured at every viewport, like a lazy image that never loads on a phone, is marked Not fully measured with the missing viewport named, so you know which ones to check before pasting.

The report has no Copy button, because it ships no scripts at all: click the code block once to select it, then Ctrl+C.

HTML report with thumbnails

npx find-oversized-images https://example.com --html

Saves oversized-report.html in the current folder and opens it in your browser. Each group shows its fix and thumbnails of the images; click one to open the file. The paste-ready code for every image is at the bottom of the same report. The report has no scripts and nothing is uploaded anywhere. In Windows Terminal, VS Code and other modern terminals, the image names in the table are clickable too.

Main flags

FlagWhat it does
--mobileOnly the phone viewport (390x844 at 3x)
--tabletOnly the tablet viewport (768x1024 at 2x)
--desktopOnly the desktop viewport (1366x768 at 1x)
--width <px>Custom viewport width. Replaces the defaults.
--dpr <n>Custom device pixel ratio (default 1)
--threshold <n>List images at or above this extra (default 2)
--fail-on <n>Exit with code 1 if any image has extra of n or more
--htmlAlso save oversized-report.html with thumbnails and fixes, and open it
--no-openWith --html, save the report without opening it
--fix-codeAlso write image-fixes.md with the paste-ready srcset and sizes for each image
--allOne row per image, instead of grouping images with the same problem
--jsonPrint JSON with every image, not just the oversized ones
--timeout <ms>Page load timeout (default 30000)
--browser-path <path>Use this Chrome or Edge executable

Use it in CI

Add --fail-on to stop a deploy when someone ships an image that is far too big:

npx find-oversized-images https://staging.example.com --fail-on 3
Exit codeMeaning
0Ran fine
1An image crossed --fail-on
2Something went wrong (bad URL, no browser, page failed to load)

Limits

  • Only <img> elements. CSS backgrounds, iframes, shadow DOM and canvas are not checked.
  • SVG files are skipped, since they scale to any size.
  • One page per run. It reports and does not resize anything.
  • Images behind a click (tabs, carousels) can show up as “not loaded”.
  • The generated sizes comes from three measured widths, so the values between them are rounded up rather than measured. Read it before you paste it.
  • A site that serves different markup to phones and desktops may give an image only one measurement, and one measurement is not enough to write responsive markup. Those images get no code rather than a guess.

Prefer a report in the browser?

If you do not want to install anything, the Website Image Auditor scans a public page from your browser, shows heavy and legacy-format images, and lets you download optimized replacements.

Source, issues and releases

Built by Muhaymin Bin Mehmood. MIT licensed. Bug reports and pull requests are welcome on GitHub.