How to check render blocking resources
Scan the served <head> for stylesheet links and for scripts that carry no defer, async or type="module", then record a load in the Chrome DevTools Performance panel and read the render blocking list it produces. The markup scan over-counts, and the trace names what actually delayed the first paint.
Why check this
A render blocking request holds the first paint, so the reader sees nothing while it travels. Testers meet it as a white screen that lasts longer on a cold cache than anyone on the team ever sees. Run the check after a change to the head of the template, after a new analytics or font tag lands, and before sign-off on any page whose LCP is dominated by render delay.
Prerequisites
- Node 20 or later, for
fetchinsidenode -e. - Chrome with DevTools. Record your build from
chrome://version. - The URL as a first-time visitor receives it, with no service worker and no warm cache.
- The definition of the term on web.dev, Render blocking resources.
Steps
- Step 1.
List the candidates in the head from the served markup, excluding print stylesheets and deferred scripts.
node -e "const html = await (await fetch('https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS')).text(); const head = html.slice(0, html.indexOf('</head>')); const css = (head.match(/<link[^>]+rel=\"stylesheet\"[^>]*>/g) || []).filter(t => !/media=\"print\"/.test(t)); const all = head.match(/<script[^>]*\ssrc=[^>]*>/g) || []; const js = all.filter(t => !/\s(defer|async)\b/.test(t) && !/type=\"module\"/.test(t)); for (const t of css) console.log('css ', (t.match(/href=\"[^\"]*\/([^\"\/]+)\"/) || [])[1]); for (const t of js) console.log('script', (t.match(/src=\"[^\"]*\/([^\"\/]+)\"/) || [])[1]); console.log('blocking candidates:', css.length + js.length); console.log('scripts skipped as non-blocking:', all.length - js.length);"css styles-global.13616ebb1fc8ee2f.css css 270.66bae6059a1c23f9.css css styles-reference-layout.632d2f3884f10ca3.css css 9228.c46ef79d5582674d.css css styles-content-section.1eb240d1720d8ac3.css css styles-heading-anchor.0eec5185ab9425b7.css … blocking candidates: 18 scripts skipped as non-blocking: 4This is the pre-filter, and it runs anywhere, including in CI. It lists what could block. It cannot say what did.
- Step 2.
Open the URL in Chrome, press F12, go to the Performance panel and click the reload and record button. Open the insight for render blocking requests and read both the list and the estimated savings.
Render-blocking resources in <head>: 6 styles-global.13616ebb1fc8ee2f.css 270.66bae6059a1c23f9.css styles-reference-layout.632d2f3884f10ca3.css 9228.c46ef79d5582674d.css styles-content-section.1eb240d1720d8ac3.css styles-heading-anchor.0eec5185ab9425b7.css Estimated savings: FCP 0 ms, LCP 0 ms - Step 3.
Compare the two lists before you write anything down. The scan named 18 files, the trace named 6, and the 6 are the first 6 of the scan in document order. Take the trace list, and read the estimated savings beside it.
Savings of
FCP 0 ms, LCP 0 msmean the browser had already finished those requests by the time it wanted to paint. Six blocking requests existed and removing them would have gained nothing measurable on that load.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| 18 in the scan, 6 in the trace | The scan lists candidates, the trace lists the requests the paint waited on | File against the trace list. Attach the scan as context. |
| Estimated savings FCP 0 ms, LCP 0 ms | Removing them would not have moved this load | Do not file it. Record the measurement and close the question. |
| Estimated savings of several hundred ms | The paint really waited | Inline the critical rules, or split the sheet the page needs first. |
| A media="print" stylesheet in a report | Print styles do not block rendering | Exclude it, as the command does. |
| A type="module" script flagged as blocking | Module scripts defer by default | Exclude it, as the command does. |
Common mistakes
What to check next
- How to check LCP of a page: render delay is the subpart this check explains.
- How to test core web vitals: where a render delay finally shows up as a pass or a fail.
- How to check CLS: a stylesheet that arrives late restyles content after the first paint.
- How to check if images are lazy loaded: the other markup scan worth running on the same document.
- How to check HTTP response headers with curl: read the cache headers on those stylesheets before blaming their count.
FAQ
How to check render blocking resources without Lighthouse?
Step 1 needs nothing but Node and a network connection, and it runs in a pipeline. It gives a candidate list. For the list that matters you still need a real load, because blocking is a property of the load, not of the markup.
Are module scripts render blocking?
No. A script with type="module" is deferred by default, so it does not hold the first paint. The scan in step 1 excludes them, which is why its count is 18 rather than 22 on the captured page.
Can a stylesheet be made non-blocking?
Yes, by loading it with a media value that does not match, or by loading it after the first paint and applying it then. A sheet the first viewport needs should stay blocking, because the alternative is a flash of unstyled content.
How many render blocking requests are acceptable?
The count has no threshold. The captured page had six and lost nothing measurable. Judge by the estimated savings in the trace and by the render delay subpart of LCP, never by the number of files.
Verified
The browser figures in step 2 come from one Chrome DevTools capture of https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS on 2026-09-11, on one machine, with no CPU and no network throttling. The command in step 1 was run against the same URL on the same day. Read your own Chrome build from chrome://version and record it with your own numbers.
Verified by Maks Vernynode 22.23.2
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
intermediate8 minpublished updated Maks Verny