Image Optimization (image-optimization)
Summary
HTTP checks for image size, format, lazy loading, and alt text.
Classification
- Category:
PERFORMANCE - Plugin id:
image-optimization - Version:
1.1.0 - Target types:
WEBSITE,WEBSHOP - Weight class:
MEDIUM - Risk level: not set on plugin object
- Browser required: No (HTTP / Node / other — see source)
- Tier / group: Tier 1 — HTTP-only
Schedule
- scheduleHints:
{ defaultInterval: '0 6 * * 1', priority: 7 } - Prerequisites: None declared on this plugin.
Configurable inputs
Public keys are derived from inputSchema: z.object({ ... }) (underscore-prefixed keys are runtime-only and omitted here).
| Field | Notes |
|---|---|
timeout |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
maxImages |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
oversizeThresholdKB |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
crawlDelay |
Zod field in inputSchema — see source for defaults, min/max, and .describe(). |
samplePages |
Optional injected pages when Run on other pages is enabled on the target profile. |
Multi-page mode
When Run on other pages is enabled, scans up to 11 pages (homepage + 10 samples). Applies maxImages per page; findings include pageUrl in evidence for oversized images.
Runtime / injected config
- Prior throttle metrics may be injected for adaptive politeness.
Checks that produce findings
These checks run inside this plugin during a single test run. They are not separate tests in the database — each becomes a Finding linked to the Run for image-optimization.
| Check | Typical severity | Why |
|---|---|---|
| Oversized image (one finding per image) | INFO if ≤500 KB; WARNING if >500 KB | Extra bytes slow LCP and mobile load; large hero/product images are the biggest easy win on performance scores. |
| Legacy format images (JPEG/PNG/GIF, not WebP/AVIF/SVG) | INFO if ≤5 images; WARNING if >5 | Legacy formats typically waste 25–50% bandwidth versus modern formats, hurting Core Web Vitals without changing layout. |
Below-fold images without loading="lazy" |
INFO if ≤5; WARNING if >5 | Eager below-fold downloads compete with critical resources on first paint and inflate transfer on every visit. |
Images missing alt text (alt absent or empty) |
INFO if ≤3; WARNING if >3 | Missing alt hurts accessibility, image search, and SEO; decorative images should use alt="" explicitly. |
How each check works
- Fetch and extract — GET the target URL and parse HTML with Cheerio. Collect
<img>sources fromsrc,data-src, ordata-lazy-src, plus URLs from<source srcset>. Deduplicate and cap atmaxImages(default 50). Data-URI images are skipped. - Measure file size — For each URL, SSRF-check then HEAD (8s timeout). Use
Content-Lengthwhen present; otherwise full GET (10s). Failed fetches are skipped for oversize logic but still counted for alt/lazy/format checks when size is 0. - Adaptive throttle — Batches of
currentConcurrency(starts at 3, can drop to 1) withcrawlDelayms (default 200) between batches. Honors prior run throttle hints and backs off on 429/403/WAF signals viaAdaptiveThrottleManager. - Oversized — Classify slot from HTML
width×height: hero (>500k px² → 300 KB cap), standard (>40k → 150 KB), thumbnail (>5k → 50 KB), icon (else → 10 KB). Missing dimensions default to standard (150 KB). One finding per image over its slot threshold. Note:oversizeThresholdKBin config is not used by the current implementation. - Legacy format — Count images with
fileSize > 0where content-type and extension are not webp/avif/svg. Single aggregate finding. - Lazy load — Treat images after the first three in scan order as “below fold”; flag those without
loading="lazy". Aggregate finding. - Alt text — Count images where
altis null or empty string. Aggregate finding. - Run status — Any WARNING → run
warning; any oversized image also forceswarningeven if all severities are INFO.
Caveats and concerns
- Homepage-only — Only the configured target URL is scanned; images on other routes are not checked.
- HEAD/GET limitations — Some CDNs omit
Content-Lengthon HEAD or block bots; size may be 0 and oversize checks skipped for that asset. - Display size guess — Without rendered layout, classification uses HTML width/height attributes only; CSS-sized images may be mis-bucketed.
- Below-fold heuristic — “After the first 3 images” is not viewport-aware; above-the-fold images can be misclassified.
- srcset-only images — Pulled from
<source srcset>without lazy/alt from the parent<picture>. - No browser rendering — Cannot detect overserving (natural vs displayed dimensions) or CSS background images.
Source
packages/test-plugins/src/plugins/image-optimization.ts