Synchronous scripts in <head> block the HTML parser — the browser stops building the DOM and waits for each script to download, parse, and execute before continuing. On slow connections, 8+ blocking scripts can add multiple seconds to Time to First Paint. ISO 25010 performance-efficiency identifies render-blocking as a direct impairment to perceived responsiveness. The fix is attribute-level: adding defer or async costs nothing and eliminates the blocking behavior. Scripts that lack these attributes are typically there by accident — legacy integrations, copy-pasted snippets, or tools that don't set them by default.
Info because the actual impact depends on script count and sizes — a single small inline script is negligible, but this rating reflects the pattern rather than guaranteed high cost.
Add defer to external scripts in <head> that are not critical to initial render. Use async for independent scripts like analytics that do not depend on other scripts:
<!-- Blocks rendering (bad) -->
<script src="/js/app.js"></script>
<!-- Deferred — runs after parsing, preserves order (good) -->
<script src="/js/app.js" defer></script>
<!-- Async — runs when ready, no order guarantee (good for analytics) -->
<script src="https://analytics.example.com/a.js" async></script>
type="module" scripts are deferred by default. For Next.js, the <Script> component's strategy prop controls loading: use strategy="lazyOnload" or strategy="afterInteractive" for non-critical scripts. Move scripts to just before </body> as a fallback if attribute changes are not feasible.
ID: site-health-check.performance-signals.minimal-blocking
Severity: info
What to look for: Count all <script> tags within the <head> section of the HTML. For each script, check whether it has a defer, async, or type="module" attribute. Count the number of synchronous scripts (those lacking all 3 of these non-blocking attributes). Inline scripts (no src) with small content under 1 KB are less impactful but still count.
Pass criteria: Fewer than 8 synchronous (non-deferred, non-async, non-module) <script> tags are present in the <head>. Report the exact count: "Found X synchronous scripts in (threshold: fewer than 8)."
Fail criteria: 8 or more synchronous <script> tags in <head> that lack defer, async, and type="module" attributes.
Skip (N/A) when: The <head> section contains 0 <script> tags (nothing to evaluate for render-blocking).
Error when: SPA detected.
Detail on fail: "Found 12 synchronous script tags in <head> — these block page rendering"
Remediation: Synchronous scripts in the <head> block HTML parsing — the browser stops rendering until each script downloads and executes. Add defer or async to external scripts:
<!-- Before (blocking) -->
<script src="analytics.js"></script>
<!-- After (non-blocking) -->
<script src="analytics.js" defer></script>
defer preserves execution order and runs after parsing. async runs as soon as downloaded (use for independent scripts like analytics). For modern code, type="module" is deferred by default.