Performance audit rules: page speed and Core Web Vitals
Audit rules for page speed: render-blocking resources, JavaScript and CSS weight, caching, compression and fonts, the causes of slow Core Web Vitals.
Performance rules read the HTML and the response headers to find what makes a page slow: render-blocking resources, oversized CSS and JavaScript, missing caching and compression, and the markup patterns behind each Core Web Vital. They report the causes a static read can see, not the metrics themselves, which need a real browser to measure.
Run only these rules
squirrel audit https://example.com --rule-include perfReliability, the other category in the Performance score group, has its own code. Add it with --rule-include perf,reliability.
Where to start
These carry the highest severity and weight in the category.
- JavaScript bundle too large: the 250 KB and 1 MB limits: Scripts over 250 KB warn and over 1 MB fail. squirrel measures every JavaScript file the crawl found and names the pages that load it.
- CSS file too large: the 150 KB and 500 KB thresholds: Stylesheets over 150 KB warn and over 500 KB fail. squirrel measures every CSS file the crawl found and names the pages that load it.
- LCP image not preloaded: what squirrel counts as a hero: Likely Largest Contentful Paint images loaded with no preload. squirrel checks the first three eligible candidate images on every page.
- Time to First Byte: the 600ms and 1000ms thresholds: A server that takes over 600ms to send the first byte, or over 1000ms. squirrel measures TTFB on every fresh fetch.
- Images without width and height: the CLS risk squirrel finds: Images and iframes with no dimensions, so the browser cannot reserve space before they load. squirrel lists every one by page.
Rules
| Rule | What it flags | Severity | Scope |
|---|---|---|---|
| Animated GIF on a page: convert to video for the bytes | GIF images used for animation, and videos with no modern codec source. squirrel finds both in the markup. | warning | Per-page |
| Audits that need a browser: what a static crawl cannot see | The runtime metrics no HTML analysis can produce. squirrel lists them so the gap in a static audit is explicit. | info | Per-page |
| Cache-Control on a page: what squirrel reads and expects | A response with no caching headers, no-cache with no validator, or a static asset cached for under a day. squirrel reads the headers per page. | warning | Per-page |
| core-js and Babel helpers: legacy JavaScript in a bundle | Polyfill bundles and ES5 transpilation helpers shipped to browsers that do not need them. squirrel reads script URLs and inline code. | info | Per-page |
| Critical request chains: the blocking head resources counted | Blocking stylesheets and scripts in head, plus every inline CSS @import a browser fetches. squirrel counts each as a link in the chain before first paint. | warning | Per-page |
| CSS file too large: the 150 KB and 500 KB thresholds | Stylesheets over 150 KB warn and over 500 KB fail. squirrel measures every CSS file the crawl found and names the pages that load it. | error | Site-wide |
| Exposed source maps: sourceMappingURL in production output | A sourceMappingURL comment or SourceMap header pointing at a map anyone can fetch. squirrel finds them in the page. | info | Per-page |
| fetchpriority=‘high’: the LCP image hint squirrel checks | A hero image loaded eagerly with neither fetchpriority=‘high’ nor a matching preload. squirrel picks the likely LCP candidate per page. | warning | Per-page |
| font-display swap: the @font-face rule squirrel looks for | An @font-face block with no font-display, or Google Fonts loaded without a preconnect. squirrel reads the inline CSS on every page. | warning | Per-page |
| Google Fonts blocking render: the font CSS squirrel flags | A stylesheet from a hosted font service in head, blocking first paint. squirrel checks eight providers and inline @import too. | warning | Per-page |
| Hidden carousel slides still download: eager images inside | Images in inactive carousel slides loaded eagerly, so the browser fetches them anyway. squirrel walks up eight ancestors to find them. | warning | Per-page |
| HTTP/2 and HTTP/3: what the response headers can tell you | Whether the server advertises HTTP/2 or HTTP/3. squirrel reads Alt-Svc and the Server header, and says when it cannot tell. | info | Per-page |
| Images without width and height: the CLS risk squirrel finds | Images and iframes with no dimensions, so the browser cannot reserve space before they load. squirrel lists every one by page. | warning | Per-page |
| JavaScript bundle too large: the 250 KB and 1 MB limits | Scripts over 250 KB warn and over 1 MB fail. squirrel measures every JavaScript file the crawl found and names the pages that load it. | error | Site-wide |
| Large DOM: node count, depth and children per element | A page at 1,500 DOM nodes or more, deeper than 32 levels, or with an element holding more than 60 children. squirrel counts all three. | warning | Per-page |
| LCP image not preloaded: what squirrel counts as a hero | Likely Largest Contentful Paint images loaded with no preload. squirrel checks the first three eligible candidate images on every page. | warning | Per-page |
| loading=lazy on a hero image: the LCP delay squirrel finds | An above-fold image marked loading=lazy, which delays the paint that matters. squirrel checks the first three eligible images. | warning | Per-page |
| No compression detected: gzip and Brotli on the response | A text response served with no Content-Encoding, or with compression explicitly disabled. squirrel reads the headers on every page. | warning | Per-page |
| Outdated jQuery and friends: the libraries squirrel detects | Twenty-two known JavaScript libraries detected by URL, bundled code or markup, with a version check against known CVEs. | warning | Per-page |
| rel=preconnect: the CDN origins squirrel checks for a hint | A page loading from a known CDN with no preconnect for that origin. squirrel checks thirteen common hosts. | info | Per-page |
| Render-blocking resources: the ones squirrel counts in head | Stylesheets and scripts in head that hold up first paint. squirrel counts them per page and lists each URL. | warning | Per-page |
| Same library loaded twice: duplicate JavaScript on a page | One library loaded from two script tags, or at two different versions. squirrel reads library names out of the script URLs. | warning | Per-page |
| Script URL redirects: a 3xx in front of every script load | JavaScript files that answer with a 3xx before serving. squirrel reports every one with the pages that reference it. | warning | Site-wide |
| Third-party scripts and INP: what squirrel counts per page | More than five known third-party scripts, or more than three that block the parser. squirrel counts both on every page. | info | Per-page |
| Time to First Byte: the 600ms and 1000ms thresholds | A server that takes over 600ms to send the first byte, or over 1000ms. squirrel measures TTFB on every fresh fetch. | warning | Per-page |
| Total page weight: the 1600 KB and 5000 KB thresholds | Each page scored on its own weight: its HTML, CSS, JavaScript, images and fonts. squirrel warns at 1600 KB and fails at 5000 KB. | warning | Site-wide, scored per page |
| Uncompressed CSS and JS: assets served without gzip | Large text sub-resources served with no Content-Encoding, while the HTML around them is compressed. squirrel checks every crawled asset. | warning | Site-wide |
| Unminified CSS: how squirrel tells minified from formatted | Stylesheets that read as source rather than build output. squirrel analyses inline CSS and judges linked files by their filename. | warning | Per-page |
| Unminified JavaScript: the signals squirrel reads in a file | Scripts that read as source rather than build output. squirrel analyses the content it has and judges the rest by filename. | warning | Per-page |
| Weak caching across a site: freshness, validators, gzip | Most pages missing a freshness lifetime, an ETag, or compression. squirrel measures the share across every crawled HTML response. | warning | Site-wide |
Key terms
- Client-side redirect: A redirect done in the page (meta refresh or JavaScript) rather than with an HTTP 3xx response.
- Client-side rendering: Building page content in the browser with JavaScript; agents and many fetchers that do not run JavaScript see an empty page.
- Core Web Vitals: Google’s three user-experience metrics: LCP for loading, INP for responsiveness and CLS for visual stability, judged at the 75th percentile of real visits.
- Cumulative Layout Shift (CLS): A score for how much visible content moves unexpectedly while the page is in use; good is 0.1 or less.
- DOM size: The number and depth of elements in a page’s document tree; large DOMs slow style calculation and interactions.
- fetchpriority: An HTML attribute (high, low, auto) that hints how urgently the browser should fetch an image, script or link.
- font-display: The @font-face descriptor (swap, optional, fallback) that decides what text shows while a web font loads.
- HTTP caching: Response headers (Cache-Control, ETag, Expires) that let browsers and CDNs reuse a response instead of fetching it again.
- HTTP compression: Compressing text responses (HTML, CSS, JS, JSON) with gzip, Brotli or zstd, signalled by Content-Encoding.
- Image width and height attributes: Declared width and height on
<img>that let the browser reserve space before the file loads, preventing layout shift. - Interaction to Next Paint (INP): The latency from a user interaction to the next frame, taken across the visit; good is 200 milliseconds or less. It replaced FID in March 2024.
- Largest Contentful Paint (LCP): The time until the largest image or text block in the viewport renders; good is 2.5 seconds or less.
- Lazy loading: Deferring off-screen images and iframes with loading=“lazy” so they load as the visitor scrolls.
- Leaked secrets: Credentials or private keys shipped to the browser in HTML, scripts or source maps.
- Minification: Removing whitespace, comments and long names from CSS and JavaScript so the file is smaller without changing behaviour.
- Modern image formats: WebP and AVIF, which encode the same image in fewer bytes than JPEG or PNG.
- Page weight: The total bytes a page downloads across HTML, CSS, JavaScript, images and fonts.
- Redirect chain: A sequence of two or more redirects between the requested URL and the final response.
- Render-blocking resources: Stylesheets and synchronous scripts in the head that the browser must fetch before it can paint anything.
- Time to First Byte (TTFB): The time from the request until the first byte of the response arrives, covering redirects, DNS, connection and server time.
Related categories
Images covers image file size, formats, responsive sizes and the width and height attributes that reserve space. Accessibility checks the same pages for people using a screen reader, a keyboard or zoom. Agent experience asks how heavy a page is for an agent to read, and whether its content needs JavaScript at all.
Learn more
- Core Web Vitals guide
- Lighthouse alternative, for auditing a whole site rather than one page
- Core Web Vitals checker
- Sample report, with the Performance section on a real site
Disable all Performance rules
[rules]
disable = ["perf/*"]