How to Fix Render-Blocking Resources
Render-blocking resources are CSS and JavaScript files the browser must download and process before it can paint the page. They sit in the critical rendering path and push back First Contentful Paint (FCP) and Largest Contentful Paint (LCP). You fix them by deferring non-critical JavaScript, inlining critical CSS, loading the rest asynchronously, and trimming what the browser has to parse before first render.
What this means
When a browser hits a plain <script src="..."> in the <head> (no defer or async) or a <link rel="stylesheet">, it pauses building the page until that file downloads, parses, and executes. Those files block rendering: nothing paints until they finish.
CSS is render-blocking by default. The browser won't paint until it has the styles, so it avoids showing unstyled content that reflows a moment later. A synchronous <script> is parser-blocking: it stops HTML parsing entirely while it loads and runs, because the script might modify DOM the parser hasn't reached yet.
Our audit flags render_blocking_scripts when it finds scripts or stylesheets in the critical path that delay first paint, typically third-party tags, large CSS bundles, or a framework file loaded synchronously in the head. It's a warning, not an error. The page still works, but visitors stare at a blank screen longer than they need to.
Why it matters
Render-blocking resources inflate two metrics Google measures: First Contentful Paint and Largest Contentful Paint. LCP is a Core Web Vitals signal, and Google's threshold for "good" is under 2.5 seconds. Every blocking file in the head adds work before anything appears, which is one of the most common reasons a page fails LCP.
The impact is worst on mobile and slower connections, where each extra request costs more. A page that paints instantly on office fibre can show a blank screen for several seconds on a mid-range phone over 4G, which is how a large share of real visitors experience it.
For AI answer engines the angle is different but real. Crawlers like GPTBot, PerplexityBot, and ClaudeBot fetch the raw HTML response and do not execute JavaScript. Content that only appears after blocking JavaScript runs may never be seen by those bots. Keeping your core content in the initial HTML and moving non-essential scripts off the critical path makes the page faster for users and more reliably parseable by AI crawlers.
How to fix it
- 1
Add defer or async to your scripts
For any
<script src="...">in the head, adddeferso it downloads in parallel but runs after the HTML is parsed, in document order. Useasyncfor independent third-party tags (analytics, chat widgets) where execution order doesn't matter. Rule of thumb:deferfor your own app code,asyncfor fire-and-forget trackers. Simpler still, move non-critical<script>tags to just before the closing</body>tag. - 2
Inline critical CSS and defer the rest
Identify the minimal CSS needed to style above-the-fold content and inline it in a
<style>block in the head. Then load the full stylesheet without blocking, using themedia="print" onloadswap orrel="preload". Tools like Critical and Penthouse, or the critical-CSS feature in most performance plugins, extract this automatically so you don't hand-maintain it. - 3
Split, minify, and trim your CSS and JS bundles
A single large stylesheet or vendor bundle blocks longer than several small, targeted ones. Minify CSS and JavaScript, remove unused rules with PurgeCSS or Tailwind's built-in purge, and code-split so each page ships only what it needs. Smaller files clear the critical path faster and cut parse time on low-end devices.
- 4
Preload what's genuinely critical, lazy-load the rest
Use
<link rel="preload">for the one or two resources needed for the initial paint, such as a critical font, so the browser fetches them early. For everything below the fold (non-critical scripts, secondary CSS, embeds), load it lazily or on interaction. Don't preload everything; over-preloading just recreates the blocking problem. - 5
Move third-party tags out of the head
Marketing tags, A/B testing scripts, and chat widgets are common offenders because they get pasted synchronously into the head. Load them through a tag manager set to fire async, or self-host and defer them. If a third-party script must run early (for example, an anti-flicker snippet), keep it as small as possible and make everything else async.
- 6
Re-run the audit and verify in Lighthouse
After deploying, re-test in Chrome DevTools Lighthouse or PageSpeed Insights and check the 'Eliminate render-blocking resources' and LCP sections. Confirm FCP and LCP dropped and that no expected content disappeared, a common regression from over-deferring. Test on a throttled mobile profile, not just desktop, since that's where blocking hurts most.
Example
<!-- BEFORE: both block the first paint -->
<head>
<link rel="stylesheet" href="/css/main.css">
<script src="/js/app.js"></script>
</head>
<!-- AFTER: paint immediately, load the rest off the critical path -->
<head>
<!-- Critical above-the-fold CSS inlined -->
<style>
body{margin:0;font-family:system-ui}
.hero{min-height:60vh;background:#0b1220;color:#fff}
</style>
<!-- Full stylesheet loads without blocking, then applies -->
<link rel="preload" href="/css/main.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
<!-- App JS downloads in parallel, runs after HTML is parsed -->
<script src="/js/app.js" defer></script>
<!-- Independent third-party tag: async, order doesn't matter -->
<script src="https://cdn.example.com/analytics.js" async></script>
</head>Before: a blocking script and stylesheet in the head. After: deferred JS, inlined critical CSS, and the full stylesheet loaded off the critical path.
Platform-specific steps
Yoast and Rank Math don't handle render-blocking themselves; use a performance plugin. WP Rocket has 'Optimize CSS delivery' (generates critical CSS) and 'Load JavaScript deferred'; enable both and clear the cache. Free options: LiteSpeed Cache (Page Optimization > CSS/JS), FlyingPress, or Autoptimize ('Inline and Defer CSS' plus 'Defer JavaScript'). After enabling, browse the site logged out and check menus, sliders, and forms, since aggressive deferral occasionally breaks theme JS.
You can't edit the server response, so work in the theme. In theme.liquid, add defer to custom <script> tags and move them before </body>. Move tracking and marketing tags into Settings > Customer events as Custom pixels, which Shopify loads in a sandbox off the main thread, instead of hardcoding them in the head. Audit installed apps too; many inject synchronous scripts you can disable per template, and keep third-party embeds like reviews and chat set to async or lazy-loaded.
These platforms control most of the head and apply their own optimization, so your lever is the code you add. In Wix, use Settings > Custom Code and set injected scripts to load in the body 'End' position, not the head. In Squarespace, put third-party scripts in Code Injection > Footer rather than Header. You can't defer the platform's own bundles, but keeping your added scripts out of the head prevents making it worse.
In hand-coded HTML, add defer to head scripts or move them before </body>, and inline critical CSS in a <style> block. In Next.js, load third-party tags with next/script using strategy="afterInteractive" or "lazyOnload", and let the framework code-split CSS per route. Use next/font to avoid render-blocking font requests. Server-render or statically generate core content so it's in the initial HTML for both users and AI crawlers.
Frequently asked
Both let a script download without blocking HTML parsing. defer runs scripts after the document is fully parsed, in the order they appear, so use it for your own code that depends on the DOM or on other scripts. async runs each script as soon as it downloads, in no guaranteed order, so use it for independent third-party tags like analytics. If a script has dependencies, use defer; if it's standalone, async is fine.
CSS in the head is correct; you don't want a flash of unstyled content. The goal isn't to remove CSS from the critical path entirely, it's to shrink it. Inline the small amount of CSS needed for the first paint and load the rest without blocking. The browser can then render immediately with critical styles and pull in everything else after.
It can, if you defer scripts that inline code expects to be available immediately, or scripts that must run before first paint (like an anti-flicker snippet). Defer your own app bundles and third-party trackers freely, but test after each change. The usual regression is content or interactivity disappearing because a script now runs later than the code depending on it.
Run the page through PageSpeed Insights or Chrome DevTools Lighthouse and read the 'Eliminate render-blocking resources' audit, which lists the exact files and their estimated savings. The DevTools Coverage tab also shows how much of each CSS and JS file actually gets used, which helps you find bloat to trim or split.
Yes, directly. Render-blocking resources delay First Contentful Paint and Largest Contentful Paint, and LCP is a Core Web Vitals ranking factor Google wants under 2.5 seconds. Clearing blocking files from the critical path is one of the highest-leverage fixes for a page failing LCP, especially on mobile.
Does your site have this issue?
Run a free, AI-powered audit and we’ll flag this and 150+ other checks in about a minute. No signup.