What LCP is and why it fails
Largest Contentful Paint is the time, in seconds, at which the biggest visible element finishes rendering inside the viewport on initial load. Google sets the pass mark at 2.5 seconds or less, measured at the 75th percentile of real-user data over a rolling 28-day window. If the slowest quarter of your visitors see the hero appear in under 2.5 seconds, you pass. If not, you fail. See the Core Web Vitals explained chapter for the wider metric context.
LCP fails far more often than the other two Vitals. INP and CLS are both fixable with disciplined front-end engineering. LCP fights against physics: bytes have to travel from a server to a phone, and the first big chunk of bytes is usually a heavy image on a slow connection. That makes LCP the metric that needs the most thoughtful diagnosis. Throwing a faster CDN at a site with render-blocking CSS does nothing. Compressing the hero image on a site with a 1.8-second server response does nothing. The fix has to match the actual root cause.
There is also a measurement problem. Lighthouse, which most people open first, runs a simulated load on a single URL and returns a single LCP number. That number does not match what real users on real connections experience. Google ranks on the field-data number from the Chrome User Experience Report, not the Lighthouse number. We get phone calls every week from people who say "we got Lighthouse to 95 and our ranking did not change". Of course not. The lab and the field are two different things. The Google Search Console chapter has the field-data workflow.
Step 1: Identify your LCP element
You cannot fix LCP without first knowing which element on the page Google is treating as the largest contentful paint. Skip this step and you will spend an afternoon optimising a footer image while the real LCP is a hero video that nobody mentioned in the brief.
Three ways to find it, in order of reliability:
- Lighthouse LCP diagnostic. Open the page in Chrome, run Lighthouse from DevTools, and scroll to the "Largest Contentful Paint element" entry. Lighthouse highlights the element in the rendered HTML preview and tells you the timing breakdown.
- PageSpeed Insights "View Treemap". The treemap on pagespeed.web.dev shows the LCP element and the resources contributing to its render.
- Chrome DevTools Performance panel. Record a page load, open the Timings track, and the LCP marker shows the exact element and the time it painted. This is the most accurate option for tricky cases (carousels, async-loaded heroes, video posters).
The element is usually one of: a hero image, a hero video poster, a hero background image set in CSS, an H1 text block above the fold, or a hero card with a heavy gradient. On local Perth business sites we audit, it is the hero image about 80 percent of the time. On news and editorial sites it is more often the H1 or the lead paragraph.
The four root causes
Every failing LCP score traces back to one of four root causes. Google's own breakdown of LCP into sub-components matches this list almost perfectly.
- Time to first byte (TTFB). The server takes too long to start sending the HTML. Slow CMS, heavy database query, no caching, distant origin.
- Resource load delay. The browser finds out about the LCP resource too late. The image is referenced inside a CSS file, or behind a JavaScript hydration step, or the document head has so much in it that the parser never gets to the image link.
- Resource load time. The LCP resource is too big for the connection. A 4MB JPG, a 12-second video poster pulled from a CDN with no Australian edge, an uncached font file blocking text render.
- Render delay. The bytes arrived in time, but render-blocking resources or client-side framework hydration prevented the browser from actually painting until much later. React, Vue and Angular sites with full client-side rendering see this constantly.
Lighthouse's "Performance" section gives you a percentage breakdown across these four sub-components. If TTFB is 35 percent of LCP and render delay is 50 percent, you have a hosting problem and a JavaScript problem, not an image problem. Match the fix to the breakdown.
Fixing oversized hero images
If the LCP element is an image and the diagnosis shows "resource load time" as the dominant sub-component, you have a heavy image. The fix is layered.
Convert the format. WebP for broad support, AVIF for newer browsers. WebP is typically 25 to 35 percent smaller than JPG at equivalent quality. AVIF is typically 50 percent smaller than JPG. For a 4MB hero JPG, WebP gets you to 2.5MB and AVIF gets you to 1.8MB. Use the <picture> element to serve AVIF with a WebP fallback and a JPG fallback. The image SEO chapter covers the format decision in more depth.
Right-size the image. A hero image displayed at 1200px wide on desktop should not be served at 3000px. Use srcset and sizes attributes to give the browser a menu of resolutions to pick from based on the device. The 400px-wide phone serves a 400px image. The 2880px retina display serves a 1600px image. Cuts payload by 60 to 80 percent on the median device.
Mark the LCP image as high priority. Add fetchpriority="high" to the LCP image tag. This tells Chromium to prioritise the image in the network queue ahead of less-important resources. The attribute shipped in Chrome 102 and is supported across Chromium browsers and Safari. It is one of the highest-impact one-line fixes available.
Lazy-load everything below the fold. Add loading="lazy" to every image that is not in the initial viewport. Native lazy loading frees up bandwidth for the LCP image. Do not lazy-load the LCP image itself: loading="lazy" on the hero adds 200 to 400ms to the LCP because the browser de-prioritises the request.
Killing render-blocking resources
Render-blocking resources are the second most common LCP problem, and they sit upstream of every other fix. If the browser cannot start rendering because it is waiting for a CSS file or a synchronous JavaScript file, none of your image work matters.
Inline critical CSS. Extract the CSS needed to render the above-the-fold content (hero, nav, first paragraph) and inline it into the document head inside a <style> tag. Load the rest of the CSS asynchronously with media="print" then swap to media="all" in onload. Tools like Critical or Penthouse automate this extraction. Knocks 300 to 800ms off LCP on most CSS-heavy sites.
Defer non-critical JavaScript. Every script tag without async or defer blocks the HTML parser. Audit the document head. Anything that does not need to run before first paint should be deferred. Analytics, chat widgets, A/B testing tools, marketing pixels: all defer. Only the critical-path JavaScript (sometimes a small bootstrap script) should be synchronous.
Self-host critical fonts. Google Fonts loaded from fonts.googleapis.com require a separate DNS lookup, a TLS handshake, and a CSS file before the font file itself is requested. Self-host the WOFF2 file in the same origin as your HTML, use font-display: swap, and preload the font file. Eliminates two round trips. The technical SEO pillar covers font self-hosting in depth.
Remove jQuery if you do not need it. Many WordPress themes still ship 90KB of jQuery synchronously in the head. If your custom code does not depend on it, kill the dependency. Modern browsers do not need it. JavaScript SEO has the broader JS-pruning workflow.
Server response and TTFB
If Lighthouse says TTFB is more than 600ms, your hosting layer is the problem and no front-end work will fully fix LCP until you address it.
Server-side cache the HTML. On WordPress, that means a full-page cache plugin (WP Rocket, FlyingPress, LiteSpeed Cache if you are on LiteSpeed). The cache should serve the entire HTML response from disk or memory without ever hitting PHP or the database for anonymous traffic. Brings TTFB from 1.2 seconds to 80ms on a typical shared-hosting WordPress site.
Put a CDN in front. Cloudflare, Bunny, KeyCDN, Fastly. The CDN caches the static assets (and increasingly the HTML) at edge nodes geographically closer to the user. For a Perth-origin site serving Sydney users, a CDN with a Sydney edge cuts 30 to 60ms off every asset request. Compounded across 30 to 50 assets per page, that is half a second saved.
Upgrade the hosting plan. A $5/month shared host with 200 other tenants on the same CPU is a different physics problem than an $80/month managed host with dedicated resources. For SMB sites doing real revenue, the hosting upgrade is often the highest-ROI speed fix available. The speed optimisation service usually starts with a hosting audit.
Preload hints and discovery
The fourth root cause is resource discovery delay: the browser finds out about the LCP resource too late in the parse, so the resource starts downloading later than it could have.
Preload the LCP image. Add a <link rel="preload" as="image"> hint in the document head. The browser starts fetching the image immediately, in parallel with parsing the rest of the HTML. Combine with imagesrcset and imagesizes to preload the right resolution.
Eliminate hero images set via CSS background. A background image declared in an external stylesheet is only discovered after the stylesheet downloads and parses. If your hero is a background image, the browser cannot start fetching it until well into the parse. Move the image to an <img> tag in the markup, or preload the background image explicitly.
Preconnect to critical origins. If your LCP image lives on a CDN at a different origin, add a <link rel="preconnect"> for that origin in the head. The browser opens the connection (DNS, TCP, TLS) in parallel with parsing, so when the image request fires the connection is already warm. Saves 100 to 300ms on the median connection.
Do
- Identify the LCP element before touching code
- Match the fix to the Lighthouse sub-component breakdown
- Use
fetchpriority="high"on the LCP image - Preload critical fonts and the LCP image from the document head
- Wait 28 days for field data to reflect the fix
Don't
- Lazy-load the LCP image (adds 200ms minimum)
- Chase a Lighthouse score of 100 on a single URL
- Set the hero as a CSS background image
- Use a third-party hosted font for above-the-fold text
- Ship a fix on Friday and declare victory on Monday
Common mistakes
Optimising the wrong page. Sites with thousands of URLs cannot have every page hand-optimised. The fix has to be at the template level. If your blog template has a slow LCP, every blog post fails. Find the template, fix the template, ship once.
Compressing the hero into oblivion. A 50KB JPG at quality 40 looks terrible on a retina display. The goal is not the smallest possible file, it is the smallest acceptable file at the right resolution. Quality 75 to 80 on a WebP is the typical sweet spot for hero imagery.
Treating Lighthouse as the ranking signal. It is not. Field data is. A Lighthouse score of 95 with failing CrUX is a worse outcome than a Lighthouse score of 70 with passing CrUX. The lab is a diagnostic tool, not a ranking signal. The Lighthouse explained chapter unpacks this misconception in depth.
Forgetting mobile. Google's CrUX data weights mobile separately from desktop. A site that passes desktop but fails mobile fails the metric. Always test with mobile throttling (4x CPU slowdown, Slow 4G network preset in DevTools) before declaring a fix shipped.
Treating CWV as a tiebreaker boost. It is not. Google has been clear: Core Web Vitals are table stakes for ranking, not a tiebreaker boost. Great content with weak Vitals beats weak content with great Vitals. Pass the threshold. Then go back to making the site genuinely useful.
Tools and checklist
Free tools for the full workflow:
- PageSpeed Insights (pagespeed.web.dev). Field data plus a Lighthouse lab run in one view. Start here for every URL.
- Chrome DevTools Lighthouse. Run from the Lighthouse panel for the full audit. Use mobile preset with 4x CPU throttling.
- Chrome DevTools Performance panel. For deeper traces. The Timings track shows LCP, FCP and the layout shift markers in context.
- WebPageTest (webpagetest.org). Run from a server in Sydney or Singapore to simulate the network path your real users hit.
- Google Search Console Core Web Vitals report. The official field-data view. URL group level, mobile and desktop separated, 28-day rolling window.
- Treo or DebugBear. Paid options for continuous CrUX monitoring with alerts.
Pre-launch checklist:
- LCP element identified and its sub-component breakdown understood
- Hero image converted to WebP or AVIF, right-sized with
srcset,fetchpriority="high" - Below-fold images set to
loading="lazy" - Critical CSS inlined, non-critical CSS async-loaded
- Non-critical JavaScript deferred or async
- Critical fonts self-hosted with preload and
font-display: swap - Server-side cache returning cached HTML in under 200ms for anonymous users
- CDN configured with at least one Australian edge
- Preload hint for the LCP image and any critical font files
- Mobile field data tracked in Search Console for 28 days post-fix
Perth and WA context
Two LCP patterns specific to Perth and WA sites.
The Sydney-edge problem. Most Australian CDNs default to Sydney as the primary edge for Australian traffic. A Perth user opening a Perth business site hosted in AWS Sydney sees a 70 to 100ms round trip, versus 8 to 15ms for a Sydney user hitting the same site. That latency stacks across DNS, TLS, HTML fetch, and every asset request. The cumulative effect on LCP is 200 to 500ms on the slow end. CDNs with a Perth point of presence (Cloudflare has one, Bunny does not) genuinely help. Most Perth SMB sites we audit have no CDN at all, which means every request is a Perth-to-Sydney round trip.
Regional WA mobile is the worst-case visitor. A mining contractor in Karratha or a tradie in Bunbury on patchy 4G is exactly the user who defines the 75th percentile of your CrUX data. Test against a Slow 4G throttling profile in DevTools, not the default Fast 3G. Sites that pass the Slow 4G test usually pass field data. Sites that pass only the default tests usually do not.
For service-specific work, the speed optimisation service is the most-aligned engagement for any business with a real LCP problem. New sites should start with a free SEO audit that flags Vitals issues alongside the rest of the technical baseline. For sector context, the e-commerce SEO and real estate SEO guides both cover sectors where heavy hero imagery makes LCP particularly painful. Local Perth context lives in Local SEO Perth and the broader Perth services overview. For regional WA, see Karratha SEO and Mandurah SEO.