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.comWhat 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 --desktophttps://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)| Column | Meaning |
|---|---|
| extra | How many times wider the file is than the screen can use. 1 is right-sized. Images at 2 or more are listed. |
| unused | Share of the file's pixels that never reach the screen. |
| file / shown | File size in pixels, and the box it is drawn in (CSS pixels). |
| size | Bytes over the network, as the browser reports them. Works for cross-origin images too. |
| est. save | A 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-codeIt 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 --htmlSaves 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
| Flag | What it does |
|---|---|
| --mobile | Only the phone viewport (390x844 at 3x) |
| --tablet | Only the tablet viewport (768x1024 at 2x) |
| --desktop | Only 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 |
| --html | Also save oversized-report.html with thumbnails and fixes, and open it |
| --no-open | With --html, save the report without opening it |
| --fix-code | Also write image-fixes.md with the paste-ready srcset and sizes for each image |
| --all | One row per image, instead of grouping images with the same problem |
| --json | Print 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 code | Meaning |
|---|---|
| 0 | Ran fine |
| 1 | An image crossed --fail-on |
| 2 | Something 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
sizescomes 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.