⚡ What is site speed optimisation and why does it matter for SEO? (Direct answer)
Site speed optimisation covers everything that affects how quickly a web page loads, renders, and becomes interactive — from the server's initial response time (TTFB) through to how the browser handles your CSS, JavaScript, images, and fonts. It matters for SEO because Google's Core Web Vitals are a direct ranking signal, and slow pages quietly kill the engagement metrics — bounce rate, session depth, conversions — that reinforce rankings indirectly. According to Deloitte Digital's Milliseconds Make Millions study, a 0.1-second improvement in mobile load time increases retail conversion rates by 8.4% — and the Yottaa 2025 Web Performance Index, analysing over 500 million visits, found that 63% of shoppers bounce from pages taking over 4 seconds to load. This guide covers every layer of the speed stack with implementation code, in priority order from highest impact to lowest.
This guide owns the engineering implementation of every speed improvement technique. Adjacent guides cover what this one explicitly excludes:
- Core Web Vitals as Google ranking signals — LCP, INP, CLS metric definitions, Good/Needs Improvement/Poor thresholds, and the Page Experience ranking factor: Core Web Vitals Guide →
- Reading the GSC Core Web Vitals field data report — URL groups, status interpretation, monitoring workflow: Google Search Console Guide →
- Image alt text, filename conventions, and CLS-preventing width/height attributes as on-page elements: On-Page SEO Guide →
- Robots.txt, crawl budget, canonical tags, and redirect chain management: Technical SEO Guide →
Why You Can Trust This Site Speed Guide
1. How Site Speed Affects SEO and the Five-Layer Stack
Site speed affects SEO on two fronts: directly through Core Web Vitals as a ranking signal, and indirectly because slow pages push users away before they engage, which suppresses the behavioural signals Google also factors in. Google confirmed Core Web Vitals as a ranking signal with the Page Experience update in June 2021, documented in Google's Page Experience documentation. The commercial case is equally clear: according to a Portent research study analysing over 100 million page views across 20 B2B and B2C sites, a site that loads in 1 second has a conversion rate 3× higher than one that loads in 5 seconds — and 5× higher than a 10-second site. The Yottaa 2025 Web Performance Index, analysing more than 500 million visits from over 1,300 e-commerce sites, found that each 1-second saved can increase mobile conversions by 3% on average.
The speed stack spans five distinct layers. Understanding which layer a problem originates in is the prerequisite for selecting the right fix — treating a TTFB problem with JavaScript minification produces no improvement, just as treating a render-blocking problem with a CDN does nothing. I have seen teams spend weeks optimising JavaScript bundles on sites running on shared hosting with 900ms TTFB. The infrastructure layer must come first.
📊 Optimisation Technique Impact on PageSpeed Insights Scores
Impact ratings reflect typical PageSpeed Insights score improvements for sites starting from average optimisation, drawn from patterns observed across 150+ client audits at IndexCraft (2019–2026). Actual gains vary widely by baseline. Independent corroboration from HTTP Archive Web Almanac 2024 and Yottaa 2025 Web Performance Index.
2. Speed Testing Tools: PageSpeed Insights, Lighthouse, WebPageTest and GTmetrix
Before you start optimising, it's worth understanding what each tool is actually measuring. The most common mistake I see is treating a strong Lighthouse score as proof the site is fast for real users — those are very different things, and confusing them sends your effort in the wrong direction.
| Tool | Data Type | Best Used For | Key Limitation |
|---|---|---|---|
| PageSpeed Insights pagespeed.web.dev | Lab data (Lighthouse) + Field data (Chrome UX Report) for the same URL | Primary tool for CWV monitoring — shows both the simulated Lighthouse score AND real Chrome user field data for LCP, INP, CLS on the same page. The field data section is Google's actual assessment of how real users experience your page. Start every audit here. | Field data requires sufficient traffic — low-traffic pages show no field data. Lab score is a single throttled mobile simulation and varies between runs. |
| Chrome DevTools Lighthouse DevTools → Lighthouse tab | Lab data — controlled local simulation | Detailed diagnostics during development. The Opportunities and Diagnostics sections list specific actionable findings: exact render-blocking files, precise image savings by file, specific unused JavaScript by bundle name. | Lab only — results vary between runs and do not represent real-user experience. Running on a fast desktop machine produces scores far higher than the throttled mobile simulation in PageSpeed Insights. |
| WebPageTest webpagetest.org | Lab data from real browsers at globally distributed test locations | Waterfall chart analysis — the most detailed view of how every resource loads, in what order, and what is blocking what. Essential for diagnosing complex render-blocking chains, third-party request waterfalls, and geographic TTFB variance. | More complex to interpret than PageSpeed Insights; requires understanding of HTTP waterfall charts. Free tier has rate limits for API access. |
| GTmetrix gtmetrix.com | Lab data with Lighthouse integration and historical tracking | Before/after comparisons when validating specific optimisations. The free tier stores test history and can alert on performance regressions — useful for monitoring that a deployment hasn't introduced a speed regression. | Free tier tests from a single location. Not a substitute for PageSpeed Insights field data for SEO ranking decisions. |
A client came to me with a Lighthouse mobile score in the high 80s — a number their internal team considered acceptable. The actual issue was that their field data in Chrome User Experience Report told a completely different story. LCP in real-user data was sitting at 4.8 seconds on mobile. They had no idea, because nobody had looked at the CrUX tab in Search Console.
Lab scores simulate a controlled network and device. Field data captures what real users on real devices in real network conditions actually experience. The two can diverge dramatically, and for ranking purposes it's field data that counts. Before I look at anything else on a site speed engagement, I open the Core Web Vitals report in Search Console and the field data section of PageSpeed Insights. Lab scores come after. — Rohit Sharma, IndexCraft
3. The Optimisation Priority Framework — Highest Impact First
Not all speed improvements are equal — some move the needle by 30+ points, others by two. The order below comes from what I've consistently seen work first across 150+ audits at IndexCraft, backed by data from the HTTP Archive Web Almanac 2024. The Web Almanac dataset covers nearly 17 million websites tested monthly via WebPageTest and Lighthouse — the most comprehensive annual state-of-the-web report available.
🏗️ Priority 1: Infrastructure
If your server is slow to respond, nothing else matters much. A 600ms TTFB on shared hosting will drag your LCP into "Poor" territory no matter how well your images are compressed. Get your hosting, caching, and CDN sorted before touching anything else.
🖼️ Priority 2: Images
Images account for 60–70% of total page weight on the average website, per HTTP Archive 2024 Page Weight data . Format conversion produces the largest byte savings per hour of effort.
🚧 Priority 3: Render-Blocking
Nothing frustrates users like staring at a blank screen while the browser waits on a JavaScript file or stylesheet to finish downloading. Eliminating render-blocking resources is often the single most visible improvement you can make, and it directly lifts LCP scores, per Google's render-blocking resources guide .
📦 Priority 4: JavaScript
Heavy JavaScript is the most common reason sites feel sluggish even after everything else is optimised. Every kilobyte of JS has to be parsed and executed, which ties up the main thread and kills your INP score — especially on mid-range Android devices that most of your users are actually on.
💾 Priority 5: Compression & Cache
Compression cuts how much data travels over the wire on first visits; caching means returning users skip the download entirely. For any site with a loyal audience, getting these two right makes repeat visits feel almost instant.
🔠 Priority 6: Fonts & Third Parties
This layer's impact varies a lot by site. A site loading four Google Fonts families and eight third-party marketing scripts has massive gains available here. A site with one self-hosted font and clean scripts? Much less so. Audit what you actually have before deciding how deep to go.
4. TTFB Optimisation: Server Response Time, OPcache, Redis and Full-Page Caching
Time to First Byte (TTFB) is the time elapsed between a browser sending an HTTP request and receiving the first byte of the HTML response. It is the universal prerequisite for all subsequent page loading — the browser cannot begin parsing HTML, requesting assets, or rendering content until that first byte arrives. Google recommends targeting server TTFB under 800ms, with an ideal target under 200ms, as documented in web.dev's TTFB guidance . A slow TTFB cascades through every downstream metric.
Three things account for most slow TTFB: server-side processing time, geographic distance, and hosting quality. For dynamic CMS sites like WordPress or Magento, the server has to execute PHP, run database queries, and assemble the HTML before sending a single byte — without caching, this happens fresh on every request, even for pages that haven't changed in weeks. Geographic distance adds latency that's simply physics: a server in Frankfurt responding to a user in Sydney faces 250–300ms of round-trip overhead before any processing even begins, which WebPageTest's geographic test locations will show you clearly. And on shared hosting, your CPU and memory get carved up across hundreds of other sites — any spike from a neighbour slows your response unpredictably.
PHP OPcache is a built-in PHP extension that caches compiled PHP bytecode in shared memory, eliminating the need to parse and compile PHP source files on every request. Without OPcache, every page request requires reading PHP files from disk, parsing them to an Abstract Syntax Tree, and compiling to executable bytecode — 10–50ms of overhead on typical production hardware per request. With OPcache properly configured, this entire cycle is eliminated for cached scripts, reducing PHP execution time by 30–70% for typical CMS workloads. Key production settings:
opcache.memory_consumption=256
,
opcache.max_accelerated_files=20000
,
opcache.validate_timestamps=0
(disable disk checks; invalidate manually after deployments). PHP's official OPcache documentation is at php.net/manual/en/book.opcache.php .
Object caching stores the results of expensive database queries in Redis (an in-memory key-value store), serving subsequent requests for the same data from RAM rather than re-executing the database query. For a typical WordPress site, WP_Query calls for nav menus, widget areas, post metadata, and option values number in the dozens per page request. With Redis object caching, these results are cached after the first request and served in microseconds on all subsequent calls. Redis typically reduces TTFB by 40–150ms on database-heavy sites and reduces database server load substantially — Automattic's own infrastructure relies on Redis for WordPress.com's scale. See the Redis official documentation for configuration reference.
Full-page caching stores the complete assembled HTML response and serves it directly from memory or disk on subsequent requests — bypassing the entire application stack (PHP execution, database queries, template rendering). For a WordPress site without caching, a page request takes 400–800ms TTFB on a well-provisioned server. The same page served from a full-page cache takes 15–60ms. Implementation options: WP Rocket or W3 Total Cache at application layer; Varnish Cache at server layer; Cloudflare APO (Automatic Platform Optimisation) at edge — the last caches WordPress HTML at Cloudflare's global edge network for approximately $5/month, reducing TTFB from 300–600ms to 20–60ms for cached pages as benchmarked by Kinsta's Cloudflare APO benchmark analysis .
The fastest TTFB improvement I've achieved came from a hosting migration rather than any code change. A publisher on shared hosting had TTFB ranging from 1.8 to 3.4 seconds depending on server load — spiking during publication times when their own traffic peaked. The entire site rendered slowly as a result, and no front-end optimisation was going to overcome the bottleneck at origin.
Moving to a managed hosting environment with proper caching configuration dropped TTFB to a consistent 160–220ms. No template changes, no image optimisation, no script deferral — just a better origin. The full benefit compounded once we added the other fixes on top, but the hosting change alone cut total page load by over a second for the median user. Recommending a hosting migration is a difficult conversation because it involves cost and technical effort. The data usually makes it straightforward to justify. — Rohit Sharma
5. Hosting Tier Comparison for Page Speed Performance
Your hosting tier sets the floor for everything else. The comparison below shows realistic TTFB ranges with no caching applied — raw baseline performance before any plugins or configuration changes. TTFB ranges are based on measurements from WebPageTest benchmark tests and published performance data from Kinsta's WordPress hosting benchmark and Bitcatcha hosting speed research .
Shared Hosting
TTFB: 400–1,200msCPU, memory, and I/O shared across hundreds of sites on one server. Performance degrades unpredictably under traffic spikes from other tenants. No server configuration control. Adequate only for low-traffic static HTML sites. For any dynamic CMS with organic traffic goals: migrate immediately. Typical PageSpeed Insights mobile score on a standard WordPress install: 25–55.
Managed WordPress / Cloud Shared
TTFB: 150–400msProviders: Kinsta, WP Engine, Cloudways, SiteGround cloud tier. Pre-configured NGINX, PHP-FPM, Redis, and edge caching included. A practical step up for small-to-medium WordPress sites without server management overhead. Typical PageSpeed Insights mobile score: 60–80 with basic plugin optimisation.
VPS / Cloud Self-Managed
TTFB: 80–200msDigitalOcean, Linode, Vultr, AWS EC2, GCP Compute Engine. Full control to configure NGINX, PHP-FPM, OPcache, Redis, Brotli, HTTP/2, HTTP/3, and Varnish Cache. Best performance-per-dollar for technically capable teams. Typical PageSpeed Insights mobile score: 70–95 with full optimisation stack applied.
Edge / Serverless
TTFB: 20–80msCloudflare Workers, Vercel Edge, Netlify Edge Functions, AWS Lambda@Edge. Application code executes at the CDN edge node nearest to the user, near-eliminating geographic round-trip latency. Best-in-class for JAMstack, Next.js, and API-driven architectures. Cloudflare APO approximates edge-level TTFB for WordPress via aggressive HTML edge caching.
Recommending a hosting migration is the most contentious part of any speed engagement. Clients have usually been with their host for years, the IT or development team has a relationship with the provider, and moving feels risky. My approach is always to present the origin response time data first — raw TTFB numbers from WebPageTest across three or four geographic locations — and let the data make the argument.
When a client can see that their server is taking 2.1 seconds to respond before a single byte of content loads, the hosting conversation becomes easier. The emotional resistance to migrating evaporates when you can show that no amount of front-end optimisation can fix a slow origin. I always run origin-only TTFB tests first, separate from any CDN layer, so the actual hosting performance is visible without the cache masking it. — Rohit Sharma
6. HTTP/2 and HTTP/3: Protocol Upgrades That Speed Up Every Request
HTTP/1.1 can only handle one request per TCP connection at a time. On a modern page with dozens of assets, browsers work around this by opening up to 6 parallel connections per domain — but each connection adds handshake overhead, and you still hit serialisation limits. Upgrading protocols costs you nothing in code changes and makes every other optimisation you've done travel faster.
HTTP/2 addresses HTTP/1.1's concurrency limitation through request multiplexing — sending all requests simultaneously over a single TCP connection without head-of-line blocking between streams. HPACK header compression reduces the overhead of repeated headers across many requests. HTTP/2 is supported by all modern browsers and virtually all major hosting providers and CDNs. Verify with:
curl -I --http2 https://yourdomain.com
— the response first line should show HTTP/2. The HTTP/2 specification and HTTP/2 performance guide cover the full protocol details. HTTP/2 typically improves load time by 15–40% for resource-heavy pages compared to HTTP/1.1, per web.dev benchmarks.
HTTP/3 replaces TCP with QUIC — a UDP-based transport protocol originally developed by Google and standardised as RFC 9114 — as its transport layer. HTTP/2 over TCP has a fundamental weakness: when a single TCP packet is lost, all multiplexed streams on the connection wait for retransmission. QUIC handles packet loss per-stream — a dropped packet only blocks the stream that needed it. HTTP/3 produces the most significant improvements on high-latency or lossy connections: mobile networks, cross-continental connections, WiFi with interference. Supported by Chrome, Firefox, Safari, and Edge — and by NGINX (with quiche patches), Caddy, LiteSpeed, and Cloudflare. Cloudflare reports that HTTP/3 reduces connection time by 12–15% on average, with larger gains on high-latency connections, per their HTTP/3 performance analysis .
7. CDN Configuration: Edge Delivery, Cache Rules and Cache Invalidation
A Content Delivery Network distributes copies of your static assets across a global network of edge servers, serving each user from the node geographically closest to them. Round-trip latency from a user's browser to an origin server might be 180ms for an international request; from the nearest CDN edge node it drops to under 10ms. Cloudflare reports that their network covers over 320 cities globally as of 2026, per Cloudflare's network page .
Standard CDN configurations cache static assets: images, CSS, JavaScript, font files, video, PDFs, and other binary content identical for all users. Standard configurations do not cache dynamically generated HTML pages — a CMS page personalised by login state or cart contents requires per-user generation. Advanced CDN products extend caching to dynamic HTML: Cloudflare APO for WordPress caches HTML at edge nodes with intelligent cache-bypass rules for logged-in users and cart/checkout pages. Configure explicit cache rules for all static asset types with long TTLs, and verify your origin sets appropriate Cache-Control headers so the CDN knows what to store and for how long.
Cloudflare free tier provides global edge delivery, DDoS protection, automatic HTTPS, HTTP/2 and HTTP/3, and Brotli compression — making it the most accessible starting point for any site. Cloudflare APO for WordPress ($5/month) adds HTML edge caching, reducing TTFB by 50–80% for cached pages. AWS CloudFront integrates natively with AWS infrastructure for custom per-path cache behaviours. Bunny.net offers excellent performance-per-dollar with a large global PoP count and straightforward pricing. Fastly supports real-time cache purge APIs and programmable VCL edge logic for complex caching requirements. For Indian-audience-heavy sites, Cloudflare and Akamai have particularly dense edge networks across Tier-2 Indian cities — measurably lower TTFB than CDNs with fewer Indian PoPs.
The correct approach for long-duration caching is filename-based cache busting: include a content hash in each asset's filename (
main.a3f9d2.css
rather than
main.css
). When the file changes, its filename changes — making it a new URL the CDN fetches fresh from origin, while unchanged files continue serving from edge cache. Modern build tools (webpack, Vite, Parcel) generate content-hashed filenames automatically. For HTML pages without filename hashing, use the CDN's instant cache purge API to push updates when content changes. Cloudflare's Cache Purge API documentation is at developers.cloudflare.com/cache/how-to/purge-cache .
8. Gzip vs Brotli Compression: Reducing Transfer Size for All Text Assets
HTTP compression reduces the byte size of text-based assets transferred from server to browser. A 200KB JavaScript bundle compressed to 55KB with Brotli saves 145KB of transfer per page load — which at a typical mobile connection translates to 500ms–1 second of saved transfer time. Enabling compression is a single server configuration change requiring zero code modifications and zero content changes.
✅ Brotli (br) — use this first
15–26% smaller than Gzip for typical web assets; 60–80% smaller than uncompressed text, per Google's original Brotli publication . Supported by all modern browsers (~97% global coverage in 2026 per Can I Use ). Use compression level 4–6 for dynamic on-the-fly compression; pre-compress static assets at level 11 during your build process for maximum savings with zero runtime CPU cost.
↩️ Gzip — keep it enabled as fallback
55–75% smaller than uncompressed text. Universal support across 100% of browsers, CDNs, and proxy servers. Keep enabled as fallback — the browser's
Accept-Encoding
request header tells the server which algorithms it supports; the server returns the best available option automatically. Never disable Gzip when enabling Brotli — older proxy servers and some enterprise firewalls may strip Brotli encoding.
# Requires ngx_brotli module (bundled on NGINX for most managed hosts)brotlion; brotli_comp_level6; # 4–6 dynamic; pre-compress statics at level 11brotli_typestext/html text/css application/javascript application/json image/svg+xml font/woff2 text/xml application/xml; # Gzip as universal fallbackgzipon; gzip_comp_level6; gzip_typestext/html text/css application/javascript application/json image/svg+xml text/xml; gzip_varyon; # Adds Vary: Accept-Encoding — required for correct CDN caching
text/html
,
text/css
,
application/javascript
,
application/json
,
text/xml
, and
image/svg+xml
.9. Eliminating Render-Blocking Resources: CSS and JavaScript Deferral
Render-blocking resources are CSS and JavaScript files that force the browser to pause page construction until they are fully downloaded and processed. A page with three render-blocking scripts and two render-blocking stylesheets, each taking 200ms to download, shows the user a blank white screen for over 1 second before any content appears — regardless of TTFB or image optimisation quality. Google's render-blocking resources guide identifies this as one of the highest-impact improvements available on most real-world sites.
🚧 Why CSS is render-blocking
The browser must construct the complete CSS Object Model (CSSOM) before painting anything — rendering without CSS would cause a Flash of Unstyled Content as elements appear then jump to their styled positions. Any
<link rel="stylesheet">
in the document head blocks all rendering until that stylesheet downloads and parses.
Fix: Inline critical above-the-fold CSS directly in the HTML head. Load the full stylesheet asynchronously using
rel="preload" as="style"
with an
onload
handler that switches it to a stylesheet.
🚧 Why JavaScript is render-blocking
Scripts without
async
or
defer
encountered in the document head force the HTML parser to stop, download the script, execute it, then continue. This is because scripts can modify the DOM — the parser cannot safely continue building the document tree while a script might be about to change it.
Fix: Add
defer
to first-party scripts that can run after parsing. Add
async
to independent third-party scripts. Move non-critical scripts to the end of
<body>
.
<!-- In <head>: inline critical CSS, async-load full stylesheet --><style>/* Critical CSS — only styles needed to render above-the-fold content */ body{font-family:sans-serif;margin:0} .hero{background:#0f2744;color:#fff;padding:60px 0} </style><!-- Async-load full stylesheet — page renders immediately, CSS loads in background --><linkrel="preload"href="/styles/main.css"as="style"onload="this.onload=null;this.rel='stylesheet'"><noscript><linkrel="stylesheet"href="/styles/main.css"></noscript><!-- Render-blocking ❌ --><scriptsrc="/js/app.js"></script><!-- Deferred ✅ — downloads in background, executes after HTML is parsed --><scriptsrc="/js/app.js"defer></script><!-- Async ✅ — for independent third-party scripts with no dependencies --><scriptsrc="https://3rdparty.com/widget.js"async></script>
On a content site I audited in early 2024, mobile PageSpeed Insights was reporting a Performance score around 62 — poor but not catastrophic. When I looked at the specific opportunities, render-blocking resources were listed as the second item. Two third-party scripts and one custom font loaded synchronously in the <head> before any above-the-fold content could paint.
Deferring the third-party scripts and converting the font to a font-display: swap implementation with a preload hint moved the Performance score to 81 in a single pass. More importantly, LCP dropped from 4.1s to 2.7s in lab data and eventually reflected in field data about five weeks later. The fixes took about two hours to implement. I've found render-blocking elimination to be one of the highest-return low-effort interventions available on most sites — it's consistently overlooked because it requires touching the <head> rather than the visible page. — Rohit Sharma
10. Critical CSS: Inlining Above-the-Fold Styles for Instant First Paint
Critical CSS is the subset of CSS rules required to style the content visible without scrolling on initial load. Inlining it directly in the HTML
<head>
allows the browser to begin rendering immediately upon receiving the HTML response, without waiting for any external stylesheet to download. This technique is recommended by Google in their Extract Critical CSS guide on web.dev as a primary method to eliminate render-blocking and improve First Contentful Paint.
Method 1 — Automated npm tooling: The
critical
npm package automatically extracts above-the-fold CSS for a given URL and viewport size and inlines it in the output HTML. Run as part of your build process:
npx critical src/index.html --inline --width 1300 --height 900 --dest dist/index.html
. Method 2 — Chrome DevTools Coverage tab: Open DevTools → More Tools → Coverage → reload the page. CSS lines highlighted in red are unused on initial load; green lines are critical CSS candidates. Export and filter manually — useful for understanding which rules are truly above-the-fold before automating. Method 3 — Lighthouse Opportunities section: The "Eliminate render-blocking resources" opportunity in Lighthouse identifies which stylesheets are blocking and how much time each adds — use this to prioritise which files to target first before investing in full critical CSS extraction.
11. JavaScript Optimisation: Bundle Splitting, Tree Shaking, Minification and Long Tasks
JavaScript is the heaviest optimisation challenge in modern web performance because every kilobyte must be parsed, compiled, and executed by the browser's JavaScript engine — blocking the main thread from responding to user input during execution. According to the HTTP Archive Web Almanac 2024 JavaScript chapter, the median mobile page loads 570KB of JavaScript (uncompressed), with the 90th percentile exceeding 1.4MB — and the median mobile page is making 22 separate JavaScript requests. That JavaScript volume has increased year-over-year since the Web Almanac began tracking in 2019, with no signs of plateauing. A 500KB JavaScript bundle on a mid-range mobile device can block the main thread for 2–4 seconds, directly causing Poor INP scores regardless of TTFB or image quality.
Without splitting, a page using 10% of your application's total JavaScript still downloads and parses the entire bundle on every load. With code splitting via dynamic
import()
(supported natively by webpack, Vite, and Rollup), route-specific components load only when that route is navigated to, and large third-party libraries (charting tools, rich text editors) load only when the component needing them is rendered. This is the most impactful JavaScript optimisation for React, Vue, Angular, or similar component-based applications — it commonly reduces initial bundle size by 40–60%, per Vite's own code splitting documentation .
Tree shaking statically analyses JavaScript imports and removes exported code not used anywhere in your application. When you import only
{ debounce }
from lodash using ES module syntax, tree shaking ensures only the debounce function and its dependencies are included — not all 300+ lodash utilities. Tree shaking requires ES module syntax (
import/export
, not CommonJS
require()
) and is performed automatically by webpack in production mode, Vite, Rollup, and esbuild. Verify with
webpack-bundle-analyzer
or
vite-bundle-visualizer
— large libraries appearing in full despite partial imports indicate missing ES module support or tree shaking configuration issues.
Minification removes whitespace, line breaks, comments, and long variable names (replaced with single-character equivalents). Modern minifiers (Terser, esbuild, SWC) also perform constant expression evaluation and dead code elimination. Minification typically reduces JavaScript size by 20–40% before compression — combined with Brotli, production JavaScript is commonly 70–85% smaller than the development source. Running un-minified JavaScript in production is never appropriate and immediately identifiable in any Lighthouse or PageSpeed Insights audit.
Any JavaScript task running over 50ms is a "long task" — it blocks the main thread from responding to user input for its entire duration, directly causing Poor INP scores. Diagnose with Chrome DevTools Performance panel: record a page load and examine the Main thread row for red-capped tasks over 50ms. Common sources: large synchronous execution during initial page load, heavy third-party scripts, non-virtualised long lists rendering thousands of DOM nodes, synchronous JSON parsing of large payloads. Fixes: break long tasks using
scheduler.yield()
(Chrome 115+) or
setTimeout(resolve, 0)
to yield between work chunks; implement virtual list rendering (react-virtual, TanStack Virtual); move heavy computation to Web Workers to run off the main thread entirely. The Chrome team's Optimize Long Tasks guide on web.dev is the authoritative reference.
While auditing a software marketing site, I ran the Chrome DevTools Coverage report and found a charting library loading on every page — including pages that had no charts. The library was around 220KB minified. It had been added months earlier for a single data visualisation on one page and included in the main bundle without condition.
Lazy-loading it on the one page that needed it and removing it from the global bundle dropped the main bundle size by 31%. Initial page load time improved measurably, and the LCP on non-chart pages improved by around 0.4 seconds in field data over the following four weeks. The Coverage report is the fastest way to find this kind of waste — it shows exactly which JavaScript bytes execute on a given page and which don't. It takes about ten minutes to run and almost always surfaces something worth removing. — Rohit Sharma, IndexCraft
12. CSS Optimisation: Minification and Unused CSS Removal with PurgeCSS
CSS minification removes all whitespace, comments, and redundant syntax from CSS files without changing behaviour. A typical stylesheet minifies to 60–75% of its original size. PostCSS with cssnano, Vite, and webpack's css-minimizer-webpack-plugin all perform CSS minification automatically in production mode. Enable the production build flag and minification happens automatically — ensure development-mode unminified stylesheets are never deployed to production. This is a zero-effort, zero-risk optimisation that should be part of every build pipeline.
CSS frameworks like Bootstrap and Bulma ship complete component libraries. A site using 20% of Bootstrap components ships a 140KB minified stylesheet without PurgeCSS and a 12–20KB stylesheet after — an 85–90% size reduction for that file, per PurgeCSS documentation benchmarks . PurgeCSS analyses your HTML, JavaScript, and template files to determine which CSS selectors are actually used, then removes all others from the output. Integrate via the PostCSS plugin or webpack plugin. For Tailwind CSS, the built-in
content
configuration in
tailwind.config.js
performs the same tree-shaking automatically on every production build — no additional tool needed. The Tailwind CSS production optimisation documentation explains the built-in purge configuration in detail.
13. Image Optimisation: Format Selection, Compression, srcset, Lazy Loading and Image CDN
Images typically represent 60–70% of total page weight and are the most frequently under-optimised asset on the web, per the HTTP Archive 2024 Page Weight chapter, which found the median desktop site at 2,652KB and the median mobile site at 2,311KB total page weight. The HTTP Archive also found that images make up nearly a third of a typical page's total byte weight. Format selection, compression, responsive delivery, and loading strategy together can reduce image payload by 70–85% with no visible quality reduction — consistently the highest-ROI optimisation layer for content-heavy sites.
Relative file size for a typical 800×600 photograph at equivalent visual quality (JPEG = 100% baseline). Source: Google AVIF compression research, web.dev and Google WebP technical study .
| Format | Use For | Browser Support (2026) | Decision Rule |
|---|---|---|---|
| WebP | All photographs, screenshots, complex images | ~97% globally — near universal, per Can I Use | Default format for all photographic content. Replace every JPEG and PNG used for photos. |
| AVIF | Photographs where maximum compression matters | ~92% globally, per Can I Use | Serve via
<picture>
element with WebP fallback. Do not serve as the only format. |
| SVG | All logos, icons, illustrations, line art | Universal | Resolution-independent, CSS-styleable. Inline simple SVGs to eliminate the network request. |
| PNG | Screenshots requiring pixel-perfect fidelity only | Universal | Avoid for photographs — files are 2–3× larger than JPEG. Use WebP with alpha channel for transparency instead. |
<!-- Above-fold LCP hero image — eager + high priority --><picture><sourcetype="image/avif"srcset="hero.avif 1x, [email protected] 2x"><sourcetype="image/webp"srcset="hero.webp 1x, [email protected] 2x"><imgsrc="hero.jpg"srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1200.jpg 1200w"sizes="(max-width:600px) 400px, (max-width:1024px) 800px, 1200px"width="1200" height="630"alt="[Descriptive alt text]"loading="eager"fetchpriority="high"></picture><!-- Below-fold images — lazy load to defer network requests --><imgsrc="article-image.webp"width="800" height="450"alt="..."loading="lazy">
Image CDN services (Cloudinary, Imgix, Bunny.net Optimizer, Cloudflare Images) perform format conversion, compression, and responsive resizing automatically on request. You upload original high-resolution images; the image CDN serves each request with the optimal format (AVIF for supporting browsers, WebP for others), the correct dimensions for the requesting device, and the best compression level for the configured quality setting. URL parameter-based transformation syntax makes responsive image generation trivial:
?w=800&fm=webp&q=80
requests an 800px WebP at quality 80. Cloudinary's free tier allows 25 monthly credits for transformations — sufficient for most small-to-medium sites. For sites with large image libraries or frequent content updates, image CDN services eliminate the operational overhead of manual image optimisation pipelines entirely.
An image audit I ran on a content-heavy website found hero images on key landing pages that ranged from 2MB to 8MB each — served as original PNGs from a media library that had no automatic compression. The site had good performance on its article pages, which used CMS-generated thumbnails with sensible sizing. The landing pages had been built by a design agency that uploaded original assets without any size consideration.
Converting the hero images to WebP with appropriate dimensions and compression settings reduced their file sizes by 84–91% on average. Combined with adding explicit width and height attributes to prevent layout shift, the visual experience improved noticeably. LCP on the affected landing pages dropped from 5.8s to 2.2s on mobile. The images were the entire problem. Every other metric on those pages was fine. — Rohit Sharma
14. Font Loading Optimisation: font-display, Preconnect, Subsetting and Self-Hosting
Web fonts cause invisible text during page load (FOIT — Flash of Invisible Text) and, for third-party font CDNs, an additional cross-origin connection that adds latency before the font request can even begin. The HTTP Archive Web Almanac 2024 Fonts chapter reports that 82% of desktop pages and 80% of mobile pages use web fonts — making font loading optimisation one of the most widely applicable performance improvements available.
The
font-display: swap
declaration in
@font-face
rules instructs the browser to immediately render text using a system font fallback while the web font downloads, then swap the web font in when it arrives. This prevents the FOIT period where text exists in the DOM but the browser refuses to paint it while waiting for the custom font. The trade-off is a brief Flash of Unstyled Text (FOUT) — text appears in the system fallback then shifts to the web font — which is visually preferable to invisible text and significantly better for perceived load speed. For Google Fonts, append
&display=swap
to the font URL parameter. The full font-display specification is documented on MDN Web Docs .
rel="preconnect"
link hints establish the TCP connection, TLS handshake, and DNS lookup to a third-party domain before any request from that domain has been made. For Google Fonts, add these two tags in your HTML
<head>
before the Fonts link tag:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
This eliminates 100–300ms of connection setup overhead from the critical path of the font request, per Google's font best practices guide on web.dev .
Hosting web fonts on your own domain or CDN eliminates the cross-origin connection overhead of third-party font CDNs entirely and gives you full control over Cache-Control headers. Download WOFF2 files from google-webfonts-helper or similar tools, place them in your static assets directory, and reference them via
@font-face
declarations in CSS. Self-hosted fonts benefit from your CDN's edge caching — returning users receive fonts from the same CDN edge as all other static assets. WOFF2 is the correct default format: universal support across all modern browsers and the most compact font format available — typically 30% smaller than WOFF for the same typeface.
A full Unicode web font covers thousands of characters across dozens of scripts. An English-language site needs only the Basic Latin subset: A–Z, a–z, numerals, and common punctuation. The Latin subset of a typical web font is 20–40KB versus 150–300KB for the full Unicode version — a 75–85% size reduction. Google Fonts delivers the Latin subset by default for most fonts; append
⊂=latin
to confirm. For self-hosted fonts, use pyftsubset (part of fonttools) or the online glyphhanger tool to generate a custom WOFF2 subset containing only the Unicode ranges present in your site's actual content.
15. Browser Caching: Cache-Control Headers, ETags and Cache Busting
Browser caching tells the user's browser to store copies of your resources locally, so on their next visit those files load from disk in milliseconds instead of travelling across the network again. For returning users this is one of the easiest performance wins available — and it's entirely in your control through HTTP headers. The MDN HTTP Caching reference provides the authoritative specification for all Cache-Control directives.
✅ Correct caching configuration
- Versioned static assets (CSS, JS, fonts, images):
Cache-Control: public, max-age=31536000, immutable— 1 year;immutabletells browsers the file will never change at this URL - HTML pages:
Cache-Control: no-cache— browser must revalidate with server before using cached copy - Filename content hashing for all versioned assets via build tooling
Vary: Accept-Encodingheader alongside all compressed responses- ETag enabled on HTML — produces 304 Not Modified responses for unchanged content, saving re-download bandwidth
❌ Common caching mistakes
- No Cache-Control headers — browser uses heuristic caching (typically minutes)
- Short max-age on static assets (max-age=3600) — returning users re-download every hour
- Long max-age on HTML — users receive stale page content after site updates until cache expires
- Updating CSS/JS files without changing their filename — cached files serve old code regardless of server changes
- Missing
Vary: Accept-Encoding— CDN serves uncompressed content to browsers that requested compressed
16. Resource Hints: Preload, Prefetch, Preconnect and dns-prefetch
Resource hints are HTML link tags that give the browser advance notice about what it'll need next, so it can start fetching before the HTML parser would normally discover it. Done right, they close gaps in the critical path. Done wrong, they burn bandwidth on things that weren't urgent and slow down things that were. The full specification is maintained at the W3C Resource Hints specification .
| Hint | What it does | When to use | When NOT to use |
|---|---|---|---|
preload
rel="preload"
| Fetches the specified resource immediately at high priority, before the HTML parser would normally discover it, and stores it in cache ready for use. | Critical above-fold resources discovered late: the LCP hero image referenced in CSS, the primary web font for above-fold text, a critical script loaded via JavaScript. Use
as=
to specify the resource type. | Do not preload every image on the page — only the LCP element and above-fold images. Unused preloads waste bandwidth and trigger browser console warnings. |
prefetch
rel="prefetch"
| Fetches a resource at low priority for use on a future navigation, storing it in the browser cache for the next page. | Resources the user is likely to need on the next navigation — the JS bundle for the most common next page, or a hero image the user will encounter on clicking a prominent CTA. | Do not use for resources needed on the current page — use preload instead. Prefetch is strictly for future navigations. |
preconnect
rel="preconnect"
| Performs DNS lookup, TCP handshake, and TLS negotiation for the specified origin in advance — establishing the full connection before any request from that origin. | Third-party origins from which the page requests resources early in load: font CDN, analytics CDN, your image CDN. Reduces connection setup overhead by 100–300ms per origin. | Limit to 2–3 most critical origins. Opening preconnections to many origins simultaneously consumes socket pool slots and can delay higher-priority connections. |
dns-prefetch
rel="dns-prefetch"
| Performs only DNS resolution for the specified origin — lighter-weight than preconnect, with no TCP or TLS establishment. | Third-party origins from which resources will be requested later in the page or on user interaction. Use as fallback alongside preconnect for older browser support. | Do not use as a substitute for preconnect on origins you will request resources from in the first 500ms of page load — those warrant the full preconnect. |
17. Third-Party Script Management: Audit, Async Loading and Facade Patterns
Third-party scripts — chat widgets, analytics, advertising pixels, social sharing embeds, heatmap tools — are one of the most common causes of poor page speed on otherwise well-optimised sites. They add uncontrollable network requests, CPU execution, and frequently render-blocking behaviour. According to the HTTP Archive Web Almanac 2024 Third Parties chapter , the median mobile page makes requests to 17 third-party origins — each adding DNS lookup, connection, and download overhead that falls entirely outside your control as the site owner.
Use WebPageTest's Filmstrip View or Chrome DevTools Network panel filtered to third-party domains to enumerate every external request your pages make. For each script: Is it actively used? Does it contribute to a measurable business outcome? Has its value been validated in the last 6 months? Scripts that cannot be justified should be removed. Common candidates: abandoned analytics tags from previous tools, social sharing buttons with near-zero click rates, marketing pixel duplicates from the same vendor, outdated chat widgets for products no longer in use. Every removed script is an unconditional performance improvement — no configuration can make it as fast as not loading it at all.
Every third-party script tag should have either
async
or
defer
attribute. Use
async
for independent scripts (analytics pixels, advertising tags) that have no dependencies on other scripts. Use
defer
for scripts that interact with the DOM. Never include third-party scripts synchronously in the document
<head>
— this is the most egregious performance anti-pattern and the most common cause of Total Blocking Time scores over 500ms, per Lighthouse's TBT diagnostic methodology documented at web.dev/tbt .
For scripts that don't need to be ready on initial page load — live chat widgets, social comment systems, video embeds — delay loading entirely until the first user interaction. Listen for a
scroll
,
click
, or
mousemove
event to trigger script injection via a once-fired event listener. This removes these scripts from the critical loading path entirely, allowing the page to reach interactive state faster and deferring their performance cost until the user is actively engaged. The pattern is well-established and documented in Google's efficient third-party loading guide on web.dev .
The facade pattern replaces a heavyweight third-party embed (YouTube player, Google Maps, Intercom chat widget) with a lightweight static placeholder — a screenshot or thumbnail image — that loads instantly. The real embed only loads when the user clicks the placeholder. YouTube embeds can add 400–600KB of JavaScript and multiple DNS connections per page; replacing them with a thumbnail image and click-to-load interaction reduces the associated load time from 1–2 seconds to under 50ms. The
lite-youtube-embed
npm package implements this for YouTube with built-in accessibility support. For chat widgets, display a styled "Start a chat" button that injects the widget script only on click — a pattern recommended by both Lighthouse and Google's Third-party facades guide on web.dev .
A client came to me specifically because their page performance felt slow despite acceptable Lighthouse scores. When I opened WebPageTest and looked at the waterfall, the issue was immediately visible: six third-party scripts loading sequentially in the first two seconds of page load, with the largest one — a chatbot widget — blocking the main thread for over 900ms.
An audit of all loaded third-party scripts showed that two of the six were from decommissioned tools that the team had simply never removed. Removing those two and deferring the chatbot load until after the user's first interaction dropped the main-thread blocking time by more than a second. LCP improved by about 1.3 seconds in field data over four weeks. The chatbot vendor had documentation for deferred loading — the team just hadn't implemented it. Third-party scripts are the easiest category of performance problem to overlook because each one seems small in isolation. The cumulative effect is usually the most impactful single change on audit. — Rohit Sharma
18. Service Workers: Offline Caching and Repeat-Visit Performance
A service worker is a JavaScript file that runs in the background, separate from your main page, and intercepts network requests before they go out. For returning visitors, this means frequently-used assets can be served from a local cache almost instantly — even on a poor mobile connection. Service workers require HTTPS and same-origin hosting, as specified in the MDN Service Worker API documentation .
A cache-first service worker strategy serves assets from the local cache if available and falls back to the network only for uncached assets. For static assets that change rarely (CSS, fonts, icons, library JavaScript), this produces instant delivery from local filesystem in microseconds. The Workbox library (by Google, documented at developer.chrome.com/docs/workbox ) simplifies service worker implementation — it provides pre-built strategies (cache-first, stale-while-revalidate, network-first) and handles cache versioning, precaching, and cache size management automatically. For most sites, a service worker implementing cache-first for static assets and stale-while-revalidate for HTML pages provides the best balance of performance and content freshness.
19. Database and Query Optimisation for CMS Sites
On most CMS sites, when the full-page cache can't serve a request — first visits, logged-in users, freshly-cleared pages — the database becomes the bottleneck. How quickly your queries run determines how quickly the server can build the HTML response. It's worth understanding what's happening at the database level before assuming the fix is elsewhere.
Install the Query Monitor plugin on a staging environment to see every database query executed per page request — including query count, execution time, the calling function, and whether duplicate queries are running. A healthy WordPress page should run under 50 database queries per request. Pages running 200+ queries have significant optimisation opportunity. Common sources: unbounded WP_Query calls with no post limit, plugins querying inside loops without caching results,
get_option()
calls on options not loaded during WordPress bootstrap (triggering individual queries per option), and meta queries using non-indexed meta keys that force full
wp_postmeta
table scans. Implement Redis Object Cache to serve repeated query results from RAM rather than re-executing against the database.
For WordPress sites on self-managed servers, ensure database tables use the InnoDB storage engine (not MyISAM) and that key lookup columns are indexed. The most impactful indexing improvement for most WordPress sites: add an index on
wp_postmeta.meta_key
if post meta queries are flagged as slow by Query Monitor. Run
OPTIMIZE TABLE wp_postmeta, wp_options, wp_posts
monthly or after large content updates to defragment table storage and rebuild query optimiser statistics. Configure
innodb_buffer_pool_size
to 50–70% of available RAM on dedicated database servers — keeping frequently accessed table data in memory eliminates disk I/O for repeated query patterns. The MySQL InnoDB Buffer Pool documentation provides full configuration guidance.
20. WordPress Speed Optimisation: The Complete Plugin and Configuration Stack
WordPress powers approximately 43.4% of all websites globally as of early 2026, per W3Techs CMS market share data (updated monthly) — and holds a 60.8% share among all sites using a detectable CMS. The HTTP Archive Web Almanac 2024 CMS chapter found WordPress powering 64.3% of all CMS-driven sites on mobile. This makes it the most common platform requiring speed optimisation at scale by a significant margin. The plugin and configuration stack below addresses every speed layer from TTFB to asset delivery — applied in the order listed, and configured on staging before production deployment.
WP Rocket
Full-stack caching + deliveryThe most comprehensive single WordPress performance plugin — handles full-page caching, GZIP/Brotli compression, render-blocking JS/CSS deferral, critical CSS generation, lazy loading, database optimisation, and CDN integration in one interface. Premium only (~$59/year as of 2026, per WP Rocket's pricing page ). Replaces most other performance plugins; the practical choice if budget allows.
Redis Object Cache
Database cachingConnects WordPress to a Redis server for persistent object cache. Caches all WP_Query, get_option(), and get_post_meta() results in Redis RAM. Requires Redis server installation (or a host that provides it). Typical TTFB reduction: 40–150ms on query-heavy sites. Free plugin, available at wordpress.org/plugins/redis-cache .
Cloudflare (free + APO)
CDN + edge cachingFree tier provides global CDN for static assets, DDoS protection, and HTTP/2 and HTTP/3. APO ($5/month per Cloudflare's APO product page ) caches HTML at Cloudflare's edge, reducing TTFB from 300–600ms to 20–60ms for cached pages. The most impactful single purchase for WordPress speed on any hosting tier.
Imagify / ShortPixel
Image optimisationBulk-converts the existing WordPress media library to WebP (and AVIF with Imagify), compresses at configurable quality levels, and serves WebP automatically to supporting browsers. Integrates with WordPress's picture element or .htaccess-based format switching. Essential for any site with an un-optimised image library inherited from before WebP was standard practice.
WP-Optimize
Database maintenanceCleans WordPress database tables: removes post revisions (unlimited by default in WordPress core), spam and trashed comments, expired transients, and orphaned postmeta rows. Running a full optimisation on a mature WordPress site commonly reduces wp_posts and wp_postmeta table sizes by 50–80%, improving query performance on cache-miss requests. Free at wordpress.org/plugins/wp-optimize .
Asset CleanUp Pro
Script/style managementDisables specific CSS and JavaScript files on a per-page-type basis — removing Contact Form 7 scripts from non-contact pages, WooCommerce cart scripts from non-shop pages, etc. Addresses the plugin bloat problem where plugins load their assets globally on every page regardless of relevance — the single most effective targeted INP improvement on plugin-heavy WordPress sites.
Early in my consulting work, I ran into a situation where two performance plugins on the same WordPress site were both applying CSS minification and conflicting with each other — producing different output depending on cache state and creating a layout bug that appeared intermittently. The developer had installed the second plugin to fix a problem the first one was causing, without removing the first one.
I've audited WordPress sites with four or five performance plugins active simultaneously — caching, minification, CDN, image optimisation, lazy loading — all with overlapping responsibilities and no documented interaction between them. The performance gains from each plugin individually are real. The interactions between them are not always predictable. My approach now is to audit every active plugin before recommending additions, and to test on a staging environment before touching production. The first plugin audit I run on any WordPress engagement almost always finds at least one conflict or redundancy that's actively hurting performance. — Rohit Sharma
21. Performance Budgets: Setting and Enforcing Load Time Targets
A performance budget is a set of limits your team agrees not to cross — things like "initial JS bundle stays under 150KB" or "mobile PageSpeed score stays above 80." The point isn't the numbers themselves, it's having automated tooling that catches regressions before they ship: a new third-party script, a bloated image, a lazy import that should have been code-split. The concept is documented in Google's Performance Budgets 101 guide on web.dev .
| Metric | Target (Good) | Acceptable | Budget breach action |
|---|---|---|---|
| Total page weight (mobile) | < 500KB | < 1MB | Audit new images and assets added since last passing build; identify largest contributors and optimise or defer |
| JavaScript payload (compressed) | < 150KB | < 300KB | Run bundle analyser; identify new large dependencies; implement code splitting for newly added routes |
| CSS payload (compressed) | < 50KB | < 100KB | Run PurgeCSS; check for newly imported unused CSS framework components |
| Third-party requests | < 5 per page | < 10 | Audit newly added scripts; identify scripts that can be self-hosted, consolidated, or removed |
| TTFB (server response) | < 200ms | < 500ms | Check server-side cache hit rate; inspect new database queries added by recent code changes |
| PageSpeed Insights mobile score | > 80 | > 65 | Run Lighthouse to identify top opportunities; address the highest-impact item before deployment |
Budget thresholds informed by Google's Performance Budgets 101 guidance, practitioner benchmarks from 150+ site audits at IndexCraft (2019–2026), and the HTTP Archive 2024 Page Weight data. Adjust based on your site's specific audience device profile and content requirements.
Integrate Lighthouse CI (
lhci
npm package, documented at github.com/GoogleChrome/lighthouse-ci ) into your GitHub Actions, GitLab CI, or Jenkins pipeline. On every pull request, Lighthouse CI runs an audit against the built site, compares results against your configured budget thresholds, and fails the build if any threshold is exceeded. Configure
.lighthouserc.json
with target scores:
"assertions": { "categories:performance": ["error", {"minScore": 0.80}] }
. This transforms performance budgets from aspirational guidelines into mandatory deployment gates — no regression ships to production without detection. Run budget checks against a representative sample of page types (home page, category page, article page) since performance varies significantly between page templates.
22. Site Speed Optimisation Checklist
🏗️ Infrastructure & Protocol
- Hosting tier confirmed as managed cloud or VPS minimum — shared hosting migrated away from
- PHP OPcache enabled and configured: memory_consumption ≥128MB, validate_timestamps=0 in production
- Redis or Memcached object caching active and connected to CMS
- Full-page caching configured: WP Rocket, Varnish, or Cloudflare APO
- HTTP/2 confirmed:
curl -I --http2 https://yourdomain.comreturns HTTP/2 in status line - HTTP/3 enabled if server stack supports it (NGINX with QUIC patch, LiteSpeed, or Cloudflare)
- CDN deployed for all static assets with long-duration Cache-Control headers
📦 Compression & Caching
- Brotli compression enabled for all text MIME types; Gzip enabled as fallback
- Compression confirmed active: response headers show
Content-Encoding: bron CSS/JS files - Static assets: Cache-Control: public, max-age=31536000, immutable
- HTML pages: Cache-Control: no-cache with ETag enabled
- Filename content hashing implemented for all versioned static assets in build pipeline
- Vary: Accept-Encoding header present on all compressed responses
🖼️ Images
- All photographs converted to WebP (minimum) with AVIF served via <picture> element where supported
- All logos, icons, and line art served as SVG
- LCP image served with
fetchpriority="high"andloading="eager" - All below-fold images have
loading="lazy" - Explicit width and height attributes on every image to prevent layout shift
- Responsive srcset and sizes attributes implemented for variable-width images
- Image compression quality validated: visually acceptable at WebP quality 75–85
🚧 Render-Blocking & JavaScript
- Critical CSS inlined in HTML head; full stylesheet loaded asynchronously via rel="preload" + onload
- All first-party JavaScript tags have
deferattribute - All third-party JavaScript tags have
asyncordeferattribute - JavaScript bundle split into route-specific chunks; no single initial bundle over 150KB compressed
- Tree shaking confirmed active in production build; bundle analyser reviewed for unexpected large dependencies
- No long tasks over 200ms in Chrome DevTools Performance panel during typical page load
🔠 Fonts & Third Parties
- font-display: swap applied to all @font-face declarations
- Preconnect hints in HTML head for all font CDN origins
- Font subset confirmed: Latin-only or appropriate minimal range for site's language content
- Third-party script audit completed: every retained script justified against a measurable business outcome
- Heavy embeds (YouTube, Google Maps, chat widgets) implemented with facade pattern
- Non-critical scripts delayed until user interaction event
- PageSpeed Insights field data: check Good/Needs Improvement/Poor status for LCP, INP, CLS in the Chrome UX Report section — metric definitions and ranking signal context covered in the Core Web Vitals Guide
- Never deploy synchronous third-party scripts in the document head without async or defer — this is the single most common source of Total Blocking Time scores over 600ms and is immediately identifiable in any Lighthouse audit
23. Frequently Asked Questions
What is TTFB and what is a good target for SEO?
TTFB is the gap between when the browser sends its request and when the first byte of your server's response arrives — covering both server processing time and network travel time. Under 200ms is the target; Google's guidance treats 800ms as the outer acceptable bound. Once TTFB goes past that, everything downstream suffers — the browser can't even start rendering until that first byte comes in. Improving it comes down to three things: better hosting, aggressive server-side caching (OPcache, Redis, full-page cache), and a CDN to cut the geographic distance between your server and your users.
What are render-blocking resources and how do I eliminate them?
Render-blocking resources are CSS and JavaScript files that force the browser to pause page construction until they are fully downloaded and processed — as documented in Google's render-blocking resources guide . CSS is render-blocking by default because the browser needs a complete style picture before painting anything. JavaScript is render-blocking when it lacks async or defer, since scripts can modify the DOM and the parser can't safely continue without finishing them first. The fixes: inline your critical above-the-fold CSS in the HTML head and load the full stylesheet asynchronously; add defer to first-party scripts and async to standalone third-party scripts; move anything non-critical to the end of the body. These changes directly reduce blank-screen time before content appears and are among the highest-impact speed improvements available on most real-world sites.
What is the difference between Gzip and Brotli compression?
Both are lossless algorithms that reduce transfer size of text-based assets (HTML, CSS, JavaScript, JSON). Brotli achieves 15–26% better compression ratios than Gzip for typical web assets, per Google's original Brotli technical publication , and is supported by all modern browsers (over 97% globally in 2026, per Can I Use ). Enable Brotli as the primary algorithm with Gzip as fallback. Never compress already-compressed binary formats like JPEG, WebP, AVIF, or WOFF2 — this adds CPU overhead with no size benefit.
What image format should I use for best performance in 2026?
Use WebP as the default for all photographs and screenshots — 25–35% smaller than JPEG at equivalent quality with near-universal browser support (~97% globally per Can I Use ), corroborated by Google's WebP technical study . Use AVIF for maximum compression (40–55% smaller than JPEG per Google's AVIF research ) via the HTML picture element with WebP fallback. Use SVG for all logos, icons, and line art. Add loading="lazy" to all below-fold images and fetchpriority="high" to the above-fold LCP hero image.
How do I optimise web font loading for page speed?
The biggest wins come from four changes, roughly in this order of impact (see Google's font best practices guide): add font-display: swap to all @font-face declarations so text renders immediately using a system fallback while the custom font loads; add rel=preconnect hints for font CDN origins so the browser establishes the connection early; self-host fonts on your own domain to cut the cross-origin connection overhead entirely; and subset fonts to just the Unicode ranges your site actually uses, which typically cuts file size by 60–80% for single-language sites.
How should I handle third-party scripts for page speed?
Start by auditing everything (see Google's guide on loading third-party JS efficiently): for each script, ask whether it's actively being used and whether it's contributing something measurable. Remove anything that can't pass that test — no amount of async loading makes a script as fast as not loading it at all. Everything that stays should have async or defer; never let a third-party script load synchronously in the document head. For things like chat widgets, heatmaps, and video embeds, delay them until after the user's first scroll or click — they don't need to be ready on arrival. And for heavy embeds like YouTube or Google Maps, the facade pattern — a lightweight thumbnail that loads the real embed on click — can cut associated load time from over a second to under 50ms.
Does page speed affect rankings in Google AI Overviews and AI search?
Based on Rohit Sharma's analysis of citation patterns across 47 site launches tracked at IndexCraft since Google AI Overviews launched globally in May 2024, pages with "Good" Core Web Vitals field data — especially LCP under 2.5 seconds and TTFB under 200ms — show consistently higher rates of citation in AI Overviews compared to structurally similar content on slower-loading origins. Google's documentation for AI Overviews does not explicitly cite page speed as a ranking signal, but the correlation is consistent: fast, reliable delivery is a signal of a well-maintained, authoritative site. For AI search engines like Perplexity AI and ChatGPT Search, which rely on Bing indexing and crawling, Core Web Vitals performance influences crawl frequency and indexation recency — both of which affect how current a site's content appears in AI-generated answers. The practical guidance: "Good" CWV is table stakes for any site targeting AI search visibility in 2026.
What is the ideal mobile page load time target for 2026?
Google's Core Web Vitals "Good" threshold requires LCP under 2.5 seconds and TTFB under 200ms, as documented in Google's TTFB guidance and web.dev Core Web Vitals. From a conversion perspective, the Portent research study found that pages loading in 1 second convert at the highest rates — roughly 3× higher than 5-second pages. Practically, a mobile PageSpeed Insights score above 80 with "Good" LCP and INP field data is the 2026 benchmark to target. According to the HTTP Archive Web Almanac 2024, only 48% of mobile sites currently pass all three Core Web Vitals — meaning the majority of the web still fails this threshold, and passing it represents a meaningful competitive advantage.
How Site Speed Connects to Your Broader Technical SEO Stack
The companion guide to this one — covering what LCP, INP, and CLS mean as ranking metrics, their Good/Needs Improvement/Poor thresholds, how field data is collected from Chrome users, and how the Page Experience ranking factor weighs them. The techniques in this guide improve those scores; the CWV guide explains the metrics and the ranking context.
Read the Core Web Vitals guide →Reading the Core Web Vitals field data report in GSC — URL group structure, Good/Needs Improvement/Poor status interpretation, and the weekly workflow for catching CWV regressions before they compound into ranking disadvantages.
Read the GSC guide →The broader technical SEO guide covering robots.txt configuration, canonical tags, redirect chains, crawl budget management, and site architecture — the technical infrastructure layer that speed improvements complement but do not replace.
Read the technical SEO guide →Image alt text formulas, SEO filename conventions, and the CLS-preventing width/height attribute implementation this guide hands off — on-page image handling is in the On-Page SEO layer; image compression and format selection are in this guide.
Read the on-page SEO guide →