How to Get a 95+ PageSpeed Score Without Sacrificing Functionality
Page speed impacts rankings, user experience, and conversion rates. Here's the optimization playbook that works for complex SaaS sites.Complete methodology with examples, tools, and measurement app...
The conventional wisdom about page speed optimization goes something like this: remove JavaScript, strip out features, eliminate third-party scripts, and serve a static HTML page. Your PageSpeed score hits 100 and you celebrate. But then someone asks why the site has no analytics, no chat widget, no conversion tracking, no dynamic content, and no interactivity. You have achieved a perfect score by building a site that cannot actually perform the functions a modern business website needs to perform. This is the fundamental tension of page speed optimization: the features that make a website useful are the same features that make it slow.
This guide takes a different approach. Instead of telling you to remove features, it shows you how to keep every feature your site needs while hitting a 95+ PageSpeed score on both mobile and desktop. The techniques are not theoretical. They are the specific optimizations that separate a 45-score site loaded with marketing tools from a 95-score site loaded with the same marketing tools. The difference is not what is on the page. The difference is how it is loaded, when it is loaded, and how the browser processes it.
- A 95+ PageSpeed score is achievable without removing functionality. The key is controlling when and how resources load, not whether they load.
- Core Web Vitals (LCP, INP, CLS) are the metrics that actually affect search rankings. Focus on these three rather than chasing a perfect overall score.
- The biggest wins come from image optimization (30-50% of most pages' weight), JavaScript defer/async strategies, and font loading optimization.
- Third-party scripts (analytics, chat, ads) are the most common score killers. Load them after the page is interactive using requestIdleCallback or intersection observer patterns.
- Test on real devices and real connections. Lab scores (Lighthouse) and field data (CrUX) often tell different stories. Optimize for field data because that is what Google uses for rankings.
Understanding What PageSpeed Actually Measures
Before optimizing, you need to understand what you are optimizing for. Google PageSpeed Insights (and Lighthouse, which powers it) measures six metrics, but only three of them directly affect search rankings. Those three are the Core Web Vitals: Largest Contentful Paint (LCP), Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS). The other metrics (First Contentful Paint, Speed Index, Total Blocking Time) contribute to the overall score but do not independently affect rankings. This distinction matters because it tells you where to focus your effort for maximum impact.
Largest Contentful Paint (LCP). LCP measures how long it takes for the largest visible content element to render. This is typically a hero image, a large heading, or a background image. Google considers an LCP of 2.5 seconds or faster to be good, 2.5 to 4.0 seconds as needing improvement, and over 4.0 seconds as poor. LCP is affected by server response time, render-blocking resources (CSS and JavaScript that must be downloaded and parsed before the page can render), resource load times (how long images and fonts take to download), and client-side rendering (JavaScript that must execute before the largest element is displayed).
Interaction to Next Paint (INP). INP replaced First Input Delay (FID) as a Core Web Vital in 2024. It measures the responsiveness of the page to user interactions throughout the entire page lifetime, not just the first interaction. An INP of 200 milliseconds or less is good, 200 to 500 milliseconds needs improvement, and over 500 milliseconds is poor. INP is primarily affected by JavaScript execution: long tasks that block the main thread prevent the browser from responding to user input. Heavy event handlers, complex DOM updates, and large JavaScript bundles all contribute to poor INP.
Cumulative Layout Shift (CLS). CLS measures visual stability: how much the page layout shifts during loading. When elements move around as the page loads (text jumping down when a font loads, content shifting when an ad appears, images pushing content down as they load), each shift is measured and summed. A CLS of 0.1 or less is good, 0.1 to 0.25 needs improvement, and over 0.25 is poor. CLS is caused by images without dimensions, dynamically injected content, web fonts that swap after rendering, and late-loading ads or embeds.
Core Web Vitals thresholds for 'good' classification (Google, 2026)
Image Optimization: The Biggest Quick Win
Images typically account for 30 to 70 percent of a page's total weight. Optimizing images is almost always the single highest-impact optimization you can make. The approach has three parts: format selection, sizing, and loading strategy.
Format selection. The days of JPEG and PNG as the default image formats are over. Modern formats offer dramatically better compression at the same visual quality. WebP reduces file sizes by 25 to 35 percent compared to JPEG at equivalent quality. AVIF reduces file sizes by 40 to 50 percent compared to JPEG. Both formats are supported by all modern browsers (WebP support is at 97+ percent, AVIF at 93+ percent as of early 2026). Use AVIF as the primary format with WebP as a fallback and JPEG/PNG as the final fallback for the remaining browsers that support neither. In HTML, the picture element with source elements lets you specify all three formats, and the browser automatically selects the best one it supports.
Responsive sizing. Serving a 2000-pixel-wide hero image to a phone with a 375-pixel-wide screen is one of the most common performance mistakes. The browser downloads a file that is five to ten times larger than needed, wasting bandwidth and slowing down LCP. Use the srcset attribute to provide multiple image sizes and let the browser choose the appropriate one based on screen width and pixel density. A typical srcset for a hero image includes versions at 400, 800, 1200, and 1600 pixels wide. The browser selects the smallest version that fills the display area at the device's pixel density. For a phone in portrait mode, that might be the 400-pixel version at about 30KB instead of the 1600-pixel version at 200KB.
Lazy loading. Images that are not visible in the initial viewport (below the fold) should be lazy loaded. The loading="lazy" attribute tells the browser to defer loading the image until it is about to scroll into view. This reduces the initial page load by removing below-the-fold images from the critical loading path. Important: do not lazy load the LCP image (the hero image or the largest above-the-fold image). Lazy loading the LCP element delays it, which directly hurts your LCP score. Instead, use loading="eager" (the default) for above-the-fold images and loading="lazy" for everything below.
Preloading the LCP image. For the LCP image specifically, add a preload link in the HTML head. This tells the browser to start downloading the image as early as possible, before the browser has parsed the HTML far enough to discover the image element. A preload link like link rel="preload" as="image" href="hero.avif" type="image/avif" can reduce LCP by 200 to 500 milliseconds because the browser starts the download during the HTML parsing phase rather than after it.
Image CDN. If you serve images from your own server, consider using an image CDN like Cloudinary, imgix, or Vercel's built-in image optimization. Image CDNs automatically convert images to optimal formats, resize images on-the-fly based on the requesting device, cache images at edge locations worldwide for faster delivery, and apply quality optimization that reduces file size without visible quality loss. The performance improvement from an image CDN is significant for sites with many images because you get format conversion, sizing, and edge caching without any manual optimization work.
JavaScript Loading Strategies
JavaScript is the second biggest factor in page speed after images. But unlike images, JavaScript does not just consume bandwidth. It also consumes CPU time, because the browser must parse, compile, and execute JavaScript before the page becomes fully interactive. A 500KB JavaScript bundle does not just take time to download. It takes time to process on the user's device, and on a mid-range phone, that processing time can be several hundred milliseconds.
Defer versus async. The script tag's defer and async attributes control when JavaScript is downloaded and executed relative to HTML parsing. A script without either attribute blocks HTML parsing while the script downloads and executes (render-blocking). A script with async downloads in parallel with HTML parsing and executes immediately when the download completes, which still interrupts parsing briefly. A script with defer downloads in parallel with HTML parsing and executes after the HTML is fully parsed. For most scripts, defer is the correct choice because it eliminates render-blocking without changing execution order. Use async only for scripts that are completely independent and do not depend on the DOM or other scripts (analytics snippets, for example).
Code splitting. Modern JavaScript bundlers (webpack, Vite, esbuild, Turbopack) support code splitting, which breaks your JavaScript into smaller chunks that are loaded on demand rather than upfront. The idea is simple: the homepage does not need the code for the pricing calculator, and the blog does not need the code for the checkout flow. Code splitting ensures that each page only loads the JavaScript it actually uses. If you are using a framework like Next.js, code splitting is automatic at the route level. For additional splitting, use dynamic imports to load heavy components only when they are needed (for example, loading a chart library only when the user scrolls to the analytics section).
Tree shaking. Tree shaking removes unused code from JavaScript bundles. If you import a utility library but only use three of its fifty functions, tree shaking eliminates the other forty-seven functions from your bundle. Tree shaking requires ES module syntax (import/export) and a bundler that supports it (all modern bundlers do). The most common tree-shaking failures come from importing entire libraries instead of individual modules. Import the specific function you need rather than the entire library to ensure tree shaking can do its job.
Third-party script management. Third-party scripts (analytics, chat widgets, A/B testing tools, advertising pixels, social media embeds) are the most common cause of poor PageSpeed scores on business websites. Each script adds download time, parse time, and execution time. Many also add additional network requests for their own resources (fonts, stylesheets, tracking pixels). The solution is not to remove these scripts. It is to control when they load. The strategy is to classify each third-party script by urgency. Critical scripts (consent management, core analytics) load with the page using async. Important scripts (chat widget, conversion tracking) load after the page is interactive using requestIdleCallback. Nice-to-have scripts (social sharing buttons, secondary analytics) load on user interaction or after a delay.
Third-Party Script Loading Strategy
List every third-party script on your site. For each one, document what it does, which pages it loads on, its file size, and how many additional requests it triggers. Use Chrome DevTools Network tab for this audit.
Critical: must load immediately (consent management, core analytics). Important: needed soon but not for initial render (chat, conversion tracking). Deferred: can wait until the page is fully idle (social buttons, surveys, secondary pixels).
Critical scripts get async attribute. Important scripts load via requestIdleCallback or setTimeout with a 3-5 second delay. Deferred scripts load on user interaction (scroll, click) or via Intersection Observer when relevant elements come into view.
If a script has not been reviewed or used in the last 90 days, remove it. Abandoned scripts (from discontinued tools, past campaigns, or old experiments) add load time without providing value.
After implementing loading strategies, monitor CWV metrics in the field (CrUX data in Search Console). Lab scores may not fully reflect the improvement because Lighthouse does not simulate idle-time loading the same way real browsers do.
CSS Optimization
CSS is render-blocking by default. The browser will not display any content until it has downloaded and parsed all linked CSS files. A single large CSS file or multiple CSS files loaded from different domains can add seconds to the time before the user sees anything on the page. CSS optimization focuses on reducing what needs to load before the first render and deferring what can wait.
Critical CSS extraction. Critical CSS is the minimum CSS required to render the above-the-fold content. By inlining this CSS directly in the HTML (in a style tag in the head), the browser can render the visible content without waiting for external CSS files to download. The remaining CSS loads asynchronously and applies after the initial render. Tools like Critical (by Addy Osmani), critters (for webpack), and PurgeCSS can extract critical CSS automatically. If you use a framework like Next.js, critical CSS extraction is handled automatically in production builds.
Removing unused CSS. Most websites load far more CSS than they use on any given page. A site using a CSS framework like Bootstrap or Tailwind CSS might ship 200KB of CSS but only use 20KB on a specific page. PurgeCSS scans your HTML, JavaScript, and templates to identify which CSS selectors are actually used and removes the rest. For Tailwind CSS specifically, the framework's built-in content scanning does this automatically in production builds, but verify that your content configuration includes all paths where Tailwind classes are used.
CSS containment. CSS containment (the contain property) tells the browser that a specific element's layout, style, and paint are independent of the rest of the page. This allows the browser to optimize rendering by not recalculating the entire page layout when something inside the contained element changes. For elements like cards, widgets, or below-the-fold sections, adding contain: content reduces the rendering work the browser does during page load and during interactions, improving both LCP and INP.
Font Loading Optimization
Custom fonts are a common source of both LCP delays and CLS issues. The browser needs to download the font file before it can render text in that font, and the behavior during the download depends on how font-display is configured. Optimizing font loading is about getting the right font to the browser as fast as possible while preventing layout shifts if the font takes time to arrive.
Font-display: swap versus optional. The font-display property controls what happens while the font is downloading. swap shows text immediately in a fallback font and swaps to the custom font when it loads. This prevents invisible text (FOIT) but causes visible text reflow (FOUT), which contributes to CLS. optional shows text in the fallback font and only swaps to the custom font if it loads within a very short window (typically 100 milliseconds). If the font does not load in time, the fallback is used for the entire page load, and the custom font is cached for the next page visit. optional produces the best CLS scores because it eliminates font swap shifts entirely. swap is better for brand-critical fonts where visual consistency matters more than CLS optimization.
Preloading fonts. Like images, fonts benefit from preloading. Add a preload link for your primary font files (the ones used in above-the-fold text) to tell the browser to start downloading them early. Use link rel="preload" as="font" href="font.woff2" type="font/woff2" crossorigin. The crossorigin attribute is required for font preloads even if the font is served from the same domain. Only preload the font files used on the current page (typically one or two weights of one font family). Preloading too many fonts defeats the purpose by competing for bandwidth with other critical resources.
Self-hosting versus Google Fonts. Self-hosting your fonts is faster than loading them from Google Fonts because it eliminates the DNS lookup and connection setup to fonts.googleapis.com and fonts.gstatic.com. Download the font files in WOFF2 format, host them on your own domain (or CDN), and reference them in your CSS. This saves 100 to 300 milliseconds compared to loading from Google Fonts, especially on mobile connections where additional DNS lookups and TLS handshakes are more expensive.
Font subsetting. If you only use Latin characters, there is no reason to download the full font file that includes Cyrillic, Greek, Vietnamese, and other character sets. Font subsetting removes unused characters from the font file, reducing its size by 50 to 80 percent. Tools like glyphhanger or fonttools can create subsets based on the characters actually used in your content. Google Fonts does this automatically with the text parameter, but self-hosted fonts require manual subsetting.
Server and Infrastructure Optimization
Client-side optimizations (images, JavaScript, CSS, fonts) are where most guides focus, but server-side performance sets the baseline. A perfect client-side optimization cannot compensate for a server that takes two seconds to respond to the initial HTML request. The time from the browser's request to the first byte of the response (Time to First Byte, or TTFB) directly impacts every other metric because nothing else can start until the HTML begins arriving.
Edge caching and CDN. Serving your pages from a CDN (Content Delivery Network) ensures that users receive content from a server geographically close to them rather than from your origin server, which might be on a different continent. For static sites and statically generated pages, the CDN serves the entire page from cache with a TTFB of 20 to 50 milliseconds regardless of where the user is located. For dynamic pages, the CDN can cache the page shell and serve it from the edge while fetching dynamic content from the origin. Modern platforms like Vercel, Cloudflare, and Netlify include CDN infrastructure by default.
Static generation versus server rendering. Static site generation (SSG) pre-builds HTML pages at deploy time and serves them from cache. Server-side rendering (SSR) generates HTML on each request. SSG produces the fastest TTFB because there is no server-side computation per request. SSR produces slower TTFB but allows dynamic, personalized content. For most marketing pages (homepage, blog posts, landing pages, product pages), static generation is the correct choice because the content does not change between requests. Reserve SSR for pages that genuinely need per-request personalization (logged-in dashboards, user-specific content). Hybrid approaches like Incremental Static Regeneration (ISR) let you statically generate pages while periodically refreshing them in the background, giving you near-static performance with the ability to update content without redeploying.
Compression. Enable Brotli compression for all text-based resources (HTML, CSS, JavaScript, JSON, SVG). Brotli compresses 15 to 25 percent better than Gzip, which translates directly to smaller file downloads and faster load times. Most modern hosting platforms and CDNs support Brotli automatically. Verify that your server is sending Content-Encoding: br headers for text resources using the Chrome DevTools Network tab.
HTTP/2 and HTTP/3. HTTP/2 (and HTTP/3, which is increasingly supported) allows multiple resources to be downloaded simultaneously over a single connection, eliminating the head-of-line blocking problem from HTTP/1.1. With HTTP/2, the browser can download your CSS, JavaScript, images, and fonts in parallel rather than sequentially. Most CDNs and hosting platforms support HTTP/2 by default. HTTP/3, which uses QUIC instead of TCP, further improves performance on unreliable connections (mobile networks) by eliminating TCP's head-of-line blocking at the transport layer.
Infrastructure performance benchmarks for high-score sites
Measuring and Monitoring Performance
Optimizing without measuring is guessing. But measuring incorrectly is worse than not measuring, because it leads to optimizing the wrong things. The critical distinction in performance measurement is between lab data and field data.
Lab data versus field data. Lab data comes from tools like Lighthouse, PageSpeed Insights (the lab section), and WebPageTest. These tools run your page on a simulated device with a simulated network connection and measure the results. Lab data is consistent, reproducible, and useful for diagnosing specific issues. But it does not represent real user experience because real users have different devices, different connections, different browser extensions, and different interaction patterns. Field data (also called Real User Monitoring or RUM) comes from actual users visiting your site. Google's Chrome User Experience Report (CrUX) collects field data from Chrome users who have opted in to usage statistics. This is the data Google uses for search ranking signals, not lab data. PageSpeed Insights shows both lab and field data. Focus on the field data section for SEO-relevant metrics and use lab data for debugging specific issues.
Google Search Console Core Web Vitals report. Search Console provides the most authoritative view of your site's field performance because it shows the same CrUX data that Google uses for ranking decisions. The Core Web Vitals report groups your pages into "Good," "Needs Improvement," and "Poor" categories for each metric. It also groups similar pages (like all blog posts that share a template) so you can identify systemic issues that affect entire page types rather than individual pages. Check this report weekly and investigate any pages that move from "Good" to "Needs Improvement."
Performance budgets. A performance budget sets maximum limits on metrics that you commit to staying within. Common budget items include total page weight (target: under 1.5MB), JavaScript size (target: under 300KB compressed), LCP (target: under 2.0 seconds, giving headroom below the 2.5 second threshold), CLS (target: under 0.05, giving headroom below the 0.1 threshold), and number of requests (target: under 50). Configure your build tools to warn or fail when a budget is exceeded. This prevents performance regressions from being deployed without notice. Most bundlers support performance budget configuration, and CI/CD platforms can run Lighthouse as a build step to catch regressions before they reach production.
Continuous monitoring. Performance is not something you optimize once and forget. New features, content changes, third-party script updates, and dependency updates can all introduce regressions. Set up continuous monitoring using a tool that runs Lighthouse on your key pages daily (or on every deployment) and alerts you when scores drop. Options include SpeedCurve, Calibre, DebugBear, or a custom setup using Lighthouse CI in your deployment pipeline. The goal is to catch regressions within 24 hours rather than discovering them weeks later when organic traffic has already been impacted.
Advanced Techniques for Complex Sites
The optimizations covered so far will get most sites to a 90+ score. But sites with complex requirements, heavy dynamic content, or extensive third-party integrations need additional techniques to close the gap to 95+.
Speculation Rules API. The Speculation Rules API (supported in Chrome and Edge) lets you tell the browser to prefetch or prerender pages that the user is likely to navigate to next. When the user clicks a link to a prerendered page, it loads instantly because the browser has already fetched and rendered it in the background. This dramatically improves perceived performance for multi-page navigation. Use speculation rules conservatively: prerender only the most likely next pages (like the top three navigation links or the "read more" link in a blog listing) to avoid wasting bandwidth on pages the user never visits.
Partial hydration and islands architecture. If your site is built with a JavaScript framework (React, Vue, Svelte), full-page hydration (where the framework takes over the entire page for interactivity) is expensive. Partial hydration and islands architecture (supported natively by Astro and implementable in React via React Server Components) allow you to hydrate only the interactive parts of the page (a form, a dropdown, a carousel) while leaving static content as plain HTML that does not require JavaScript processing. This reduces JavaScript execution time and improves INP because less JavaScript is competing for the main thread.
Content visibility and containment. The CSS content-visibility: auto property tells the browser to skip rendering for off-screen elements until they scroll into view. For long pages with many sections (a blog post with dozens of images and components), this can reduce initial rendering time by 30 to 50 percent because the browser only renders what is visible. Combined with contain-intrinsic-size (which tells the browser the expected dimensions of the deferred element so scrollbar calculations remain accurate), this is a low-effort optimization with significant impact on long-form content pages.
Service workers for caching. A service worker can cache your site's critical resources (HTML shell, CSS, JavaScript, fonts) after the first visit. On subsequent visits, these resources are served from the local cache with zero network latency. This makes repeat visits extremely fast and provides resilience against network issues. The service worker can use different caching strategies for different resource types: cache-first for static assets (CSS, JS, fonts), network-first for HTML (to get fresh content), and stale-while-revalidate for images (serve cached version immediately while fetching an updated version in the background).
Resource hints. Beyond preloading, several resource hints help the browser prepare for future resource needs. dns-prefetch resolves the DNS for a third-party domain before it is needed, saving 20 to 120 milliseconds per domain. preconnect establishes a full connection (DNS + TCP + TLS) to a third-party domain, saving even more time. prefetch downloads a resource that will be needed for a future navigation. Use preconnect for third-party domains that you know will be needed on the current page (your CDN, analytics endpoint, font provider) and prefetch for resources needed on the next likely page.
Monitor your site speed with OSCOM
OSCOM's SEO module includes Core Web Vitals monitoring, PageSpeed auditing, and performance regression alerts. Connect your site and get optimization recommendations based on real field data.
Check Your PageSpeedThe Optimization Priority Checklist
If you are starting from a low score and want the fastest path to 95+, prioritize optimizations in this order. Each item is ordered by typical impact, so the first items produce the largest score improvements with the least effort.
First, convert images to WebP or AVIF and add width/height attributes. This typically improves the score by 10 to 20 points and fixes both LCP (smaller images load faster) and CLS (dimensions prevent layout shifts). Second, implement responsive images with srcset so mobile devices download appropriately sized images. This can save 50 to 80 percent of image bandwidth on mobile. Third, defer third-party scripts using requestIdleCallback or setTimeout. This improves Total Blocking Time and INP by moving script execution off the critical path. Fourth, preload the LCP image and critical fonts. This can improve LCP by 200 to 500 milliseconds by starting critical downloads earlier. Fifth, implement critical CSS inlining and defer non-critical CSS. This improves FCP and LCP by allowing the browser to render above-the-fold content without waiting for the full stylesheet.
Sixth, enable Brotli compression and verify HTTP/2 support. These are typically server configuration changes that take minutes to implement. Seventh, self-host fonts and configure font-display: optional with font metric overrides. This eliminates font-swap CLS and reduces LCP if fonts were previously loaded from Google Fonts. Eighth, implement lazy loading for below-the-fold images and iframes. Ninth, audit and remove unused CSS and JavaScript. Tenth, configure content-visibility: auto for long-form pages.
The first five items will typically take a site from the 40 to 60 range to the 80 to 90 range. Items six through ten push from 90 to 95+. The advanced techniques (speculation rules, partial hydration, service workers) are for sites that need to squeeze out the last few points or that have specific requirements that make the standard optimizations insufficient.
Key Takeaways
- 1Focus on Core Web Vitals (LCP, INP, CLS) because these are the metrics Google uses for search rankings. The overall PageSpeed score is a composite that includes non-ranking metrics.
- 2Image optimization is the highest-impact starting point. Convert to AVIF/WebP, use responsive srcset, lazy load below-the-fold images, and preload the LCP image.
- 3Control third-party script loading timing rather than removing scripts. Use requestIdleCallback for important-but-not-critical scripts and interaction-triggered loading for deferred scripts.
- 4Inline critical CSS and defer the rest. This eliminates the render-blocking behavior of external CSS files and lets the browser paint above-the-fold content immediately.
- 5Self-host fonts, use font-display: optional for best CLS scores, and apply font metric overrides to minimize layout shift during font swaps.
- 6Distinguish between lab data (Lighthouse) and field data (CrUX). Optimize for field data because that is what Google uses. Use lab data for debugging specific issues.
- 7Set performance budgets and monitor continuously. Performance regressions from new features, dependency updates, and content changes are the leading cause of score degradation over time.
- 8A 95+ score with full functionality is achievable. The key is not removing features but controlling when and how each resource loads relative to the user's initial interaction with the page.
Performance optimization and technical SEO
Core Web Vitals strategies, page speed optimization techniques, and technical SEO frameworks for marketing teams that care about both user experience and search rankings. Delivered weekly.
Page speed optimization is ultimately about respect for the user's time and device. A two-second load time on a five-year-old phone on a 3G connection is not the same as a two-second load time on a new laptop on fiber internet, but both users deserve a functional, fast experience. The optimizations in this guide are designed to provide that experience across the full range of devices and connections your visitors use. They do not require removing the tools and features that make your website effective. They require loading those tools and features intelligently, so the user sees a fast, stable page that becomes fully functional within seconds rather than a blank screen that takes five seconds to show anything at all. That is the difference between a 45 and a 95. Not fewer features. Better loading.
Find where you're losing traffic and what to fix first
Oscom SEO scores every keyword across 6 dimensions and shows you the highest-value opportunities you're missing right now.