Render-blocking JS checker
Find JavaScript files that block page rendering and slow down display
Check results
This check only covers render-blocking JS. For a full picture of your page, run a page audit.
For issues across your whole site — duplicate titles, orphan pages, broken internal links — run a site audit.
Want us to fix what we found? Our team can help.
What are render-blocking resources and why they matter
Render-blocking resources are scripts (and stylesheets) that pause the browser's HTML parser until they download and execute. A <script src="..."> tag without async, defer, or type="module" tells the browser: "stop parsing, get this file, run it, then continue." During that pause, nothing further renders. The visible effect is a blank (or half-rendered) page for longer than necessary. Measurable impact: slower First Contentful Paint (FCP) and Largest Contentful Paint (LCP) — both Core Web Vitals metrics that Google uses as ranking signals. Rendering-blocking scripts are one of the top issues flagged by PageSpeed Insights.
What this tool checks
- External scripts — every
<script src="...">on the page - Placement analysis — scripts in
<head>are classified as critical (blocks first paint); scripts in the middle of<body>block subsequent content; scripts at the end of<body>are acceptable - async / defer / type="module" — these attributes remove the blocking behaviour and get a pass
- Large inline scripts in
<head>— inline code over ~3 KB runs synchronously and blocks parsing just like external scripts
Difference between async and defer
- No attributes — browser pauses HTML parsing, downloads the script, executes it, then continues
- async — script downloads in parallel with parsing but executes as soon as it arrives (pauses parsing briefly). Order not guaranteed.
- defer — script downloads in parallel and executes only after parsing is complete, in document order
- type="module" — ES modules are deferred by default; no need to add
deferexplicitly - When to use which — defer for DOM-dependent scripts; async for independent ones (analytics, ads, widgets); module for modern JS
Good vs bad examples
Good — defer in head for DOM-aware code:
<head>
<script src="/app.js" defer></script>
</head>
Good — async for independent analytics:
<head>
<script src="/analytics.js" async></script>
</head>
Good — classic "at end of body" pattern (rendering is done, blocking effect is minimal):
<body>
<main>...</main>
<script src="/app.js"></script>
</body>
Bad — sync script in head blocks the first paint:
<head>
<script src="/app.js"></script> <!-- blocks FCP -->
</head>
Bad — sync script mid-body pauses rendering of subsequent content:
<main>
<h1>Hero</h1>
<script src="/ad.js"></script> <!-- blocks everything below -->
<article>...</article>
</main>
Bad — large inline script in head (same blocking effect as external, but you can't even cache it):
<head>
<script>
// 5 KB of application initialization inlined here
</script>
</head>
Common mistakes
- Analytics in
<head>without async — the classic FCP killer. Analytics scripts should almost always be async. - Third-party widgets inline in body — chat widgets, ad scripts, social embeds dropped in the middle of
<body>pause rendering of everything below. Use async or load on user interaction. - Copy-pasting vendor snippets without async/defer — many vendor integration docs still show blocking snippets. Always add
asyncunless the documentation explicitly requires otherwise. - Using
asyncfor ordered scripts — async doesn't preserve execution order. If script A depends on script B, usedeferon both instead. - Large inline scripts in head — same blocking effect as external scripts, but inlined code can't be cached across pages and bloats every HTML response.
- Assuming "end of body" is always fine — it's better than
<head>without async/defer, butdeferis still safer (executes after DOMContentLoaded, guaranteed order).
Frequently asked questions
rel="preload" or media queries.<head> blocks the browser from parsing and rendering any content — the user sees a blank page during download + execution. A script at the very end of <body> blocks parsing of whatever comes after it, which is nothing — so the visible effect is minimal. It's the old-school pre-async technique (2010-2015) and still works, just slightly worse than using defer (which downloads in parallel).preload.