First Contentful Paint (FCP)

What First Contentful Paint measures, what's a good FCP score, why it isn't a Core Web Vital, how it differs from First Paint and LCP, and how to fix a slow one.

First published: Jun 26, 2026 · Last updated: Jul 17, 2026 · Advanced
demand #5 in Web Vitals#13 in Web Performance#114 in Technical SEO#151 on the site

First Contentful Paint (FCP) is the time from when a page starts loading to when any part of its content — text, image, SVG, or non-white canvas — first renders. Good is ≤1.8 s at the 75th percentile of real users. It is NOT a Core Web Vital: the ranking signals are LCP, INP, and CLS. FCP is a diagnostic metric (lab and field) that's a building block of LCP — it happens at or before LCP — so it's mainly useful for catching render-blocking resources and slow TTFB. In Lighthouse 10 it's 10% of the Performance score. Fix it by eliminating render-blocking CSS/JS, cutting TTFB, inlining critical CSS, using font-display: swap, and preconnecting to required origins.

TL;DR — FCPFirst Contentful Paint — the time from when a page starts loading to when any part of its content (text, image, SVG, or non-white canvas) first renders. Good is ≤1.8 s at the 75th percentile. It's a diagnostic metric, not a Core Web Vital. is the time from navigation start to when any page content (text, image, <svg>, or non-white <canvas>) first renders. It is not a Core Web Vital — it’s a supplementary, lab-and-field diagnostic metric, and a building block of LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. (FCP happens at or before LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good.). Field thresholds (p75): Good ≤ 1.8 s, needs-improvement ≤ 3.0 s, poor > 3.0 s. In LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. 10 it’s 10% of the Performance score. Because FCP’s clock starts at navigation — it includes redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. time, connection setup, and TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. — lab (LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal.) and field (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.) numbers often diverge. Fix it where it lives: render-blocking CSSRender-blocking resources are CSS and synchronous JavaScript files a browser must download and process before it can paint any visible content. They sit on the critical rendering path and delay First Contentful Paint and Largest Contentful Paint./JS first, then TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good., then fonts.

What FCP measures (precisely)

Google’s definition, from Philip Walton’s web.dev article, is the accuracy spine here: “First Contentful Paint (FCP) measures the time from when the user first navigated to the page to when any part of the page’s content is rendered on the screen.” “Content,” per the same doc, means “text, images (including background images), <svg> elements, or non-white <canvas> elements.”

The word that does all the work is any. FCP doesn’t care what renders — a 40-pixel logo counts the same as a full hero image. It’s the “is anything on screen yet?” signal, which is exactly why it’s an early indicator rather than a completion metric.

Evidence for this claim FCP measures from navigation until the first text, image, SVG, or non-white canvas content is rendered. Scope: Current web.dev FCP definition and qualifying content types. Confidence: high · Verified: web.dev: First Contentful Paint

One detail that’s easy to miss and changes how you read the number: FCP’s clock starts at navigation, so it bundles in everything that happens before your HTML is even parsed. Google’s own Key Point: “FCP includes any unload time from the previous page, connection set up time, redirect time, and Time To First Byte (TTFB) which can be significant when measured in the field.” A server that takes 1.5 s to respond has already burned most of your 1.8 s budget before the browser has processed a single byte.

FCP is NOT a Core Web Vital

Let me be blunt about this because most pages hedge it: FCP is not a Core Web Vital and is not part of Google’s ranking signals. The Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. are LCP, INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good., and CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. — and FCP isn’t mentioned anywhere on Google’s Search ranking Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. page.

What FCP is, in Google’s taxonomy, is an “Other Web Vital” — a supplementary metric that’s useful for diagnosis. web.dev puts it this way: “the metrics Time to First Byte (TTFB) and First Contentful Paint (FCP) are both vital aspects of the loading experience, and are both useful in diagnosing issues with LCP (slow server response times or render-blocking resourcesRender-blocking resources are CSS and synchronous JavaScript files a browser must download and process before it can paint any visible content. They sit on the critical rendering path and delay First Contentful Paint and Largest Contentful Paint., respectively).”

So the honest framing for stakeholders is two-sided, and you should state both halves without flinching:

  • FCP does not affect rankings directly. Don’t optimize FCP “for SEO.”
  • FCP is a great diagnostic for LCP, which does affect rankings. Render-blocking resources show up in FCP first.

FCP vs First Paint (FP)

These get conflated constantly:

  • First Paint (FP) fires when the browser paints anything at all — including a bare background color with no actual content.
  • FCP fires only when eligible content renders: text, images (including background images), <svg> elements, or non-white <canvas> elements. That’s a specific, spec-defined list — not a loose “any DOM content” rule — and it’s worth keeping precise, since a background image counts even though it isn’t text in the DOM.

So FP ≤ FCP, always. On most pages they’re nearly identical, because painting a background color with no content on top is rare. When there is a meaningful gap, it usually means a cosmetic background painted before any real content did. The Paint Timing API returns both first-paint and first-contentful-paint entries — but FCP is the one worth analyzing; FP rarely tells you anything actionable.

FCP vs LCP

The other pair people merge:

  • FCP = when any content paints. Fires early. Could be a tiny logo or a nav link.
  • LCP = when the largest element in the viewport renders. Fires at or after FCP.

Google’s wording: FCP measures when any content is painted and LCP when the main content is painted, so LCP is intended to be more selective. Read that as “more selective,” not “certified correct” — neither metric proves the page’s actual main content is complete or useful to the visitor. FCP just confirms something eligible painted; LCP confirms the largest eligible candidate did. A page can have a fast FCP (logo at 0.5 s) and a slow LCP (hero image at 4 s) — that gap is itself a useful diagnostic. And if your FCP is close to your LCP, that’s often a good sign: it means the first thing painted is also the largest one, with no wasted early-paint on chrome that doesn’t matter to the user.

One measurement oddity worth knowing: because of security restrictions on cross-origin image timing, the browser API can in rare cases report LCP earlier than FCP. That’s a measurement artifact, not something that physically happened.

Thresholds — and why lab and field disagree

Field thresholds (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program., p75): Good ≤ 1.8 s · needs improvement ≤ 3.0 s · poor > 3.0 s. Google’s guidance is to measure at the 75th percentile of page loads, split across mobile and desktop.

Evidence for this claim A good FCP is 1.8 seconds or less at the 75th percentile; above 3 seconds is poor. Scope: Current web.dev FCP field thresholds. Confidence: high · Verified: web.dev: First Contentful Paint

But Lighthouse desktop uses different, stricter cutoffs — green is roughly 0–0.9 s, orange 0.9–1.6 s, red over 1.6 s — because the lab runs a clean, throttled Chrome on a simulated device, not real-world conditions. (Those bands, like the score weights below, are Lighthouse-version-specific — this reflects the current audit doc as of this writing.) The Lighthouse FCP score is “a comparison of your page’s FCP time and FCP times for real websites, based on data from the HTTP Archive.”

This is the single most common source of FCP confusion, so internalize it:

The 1.8 s “good” line is the field (CrUX p75) threshold. Lighthouse desktop’s “green” line is ~0.9 s. They are different scales for different jobs.

Field and lab numbers diverge mainly because they sample different populations, not because one is universally “more true.” Lighthouse runs a single clean session on fixed device/network conditions. Field/CrUX aggregates real devices, real networks, cache states, and navigation types — including back/forward-cache restores and prerendered pages, which don’t automatically get a fresh FCP the way a normal navigation does; they need their own lifecycle handling (the web-vitals library does this for you). On most sites the field number does read higher — real users carry redirect chainsA → B → C instead of A → C. Each hop loses link equity and adds latency., previous- page unload time, and cold connections a lab run skips — but that’s a tendency, not a rule. Before reading a lab/field gap as a problem, check you’re comparing like-for-like (same device class, same network conditions). Use field dataPerformance metrics captured from real users, not lab tests. for your real-world number and Lighthouse for diagnosis.

Where FCP sits in the Lighthouse score

In Lighthouse 10 — the current version as of this writing, not a permanent figure — FCP is 10% of the Performance score. The full weighting:

MetricWeight
Total Blocking Time (TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital.)30%
Largest Contentful Paint (LCP)25%
Cumulative Layout Shift (CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.)25%
First Contentful Paint (FCP)10%
Speed IndexSpeed Index measures how quickly content is visually displayed during page load — the average time at which visible parts of the page appear, scored in seconds (lower is better). It's a lab-only Lighthouse metric, not a Core Web Vital and not a ranking factor.10%

The Performance score is a weighted average of the individual metric scores, and Google notes the weightings change over time as their research evolves — FCP has held at 10% from Lighthouse 8 through 10, but confirm against whatever version you’re running before treating “10%” as timeless. The practical read: a perfect FCP can only move your Lighthouse number so far — and a bad FCP often points at a bad LCP too (they share root causes), though that’s an overlap worth checking, not something the score guarantees.

What causes a slow FCP

In rough priority order:

  1. Render-blocking resources — the #1 killer. CSS and synchronous JS in <head> force the browser to wait: it can’t build the CSSOM and render tree, so it can’t paint anything, until those files are downloaded and parsed.
  2. High TTFB — FCP can’t fire before bytes arrive. A slow server is the first domino, and it’s inside the FCP measurement.
  3. Redirect chains — every redirect is a full round-trip added before the first byte.
  4. Webfont loading strategyfont-display: block (or no rule) can leave text invisible for up to ~3 seconds. Even if paint technically fires on a background, the user sees nothing useful.

How to fix it

The full list, but with a priority order the docs don’t give you. These are the common levers, not universal ones — check your own trace or filmstrip first to see which resource or phase is actually delaying your FCP candidate before reaching for fixes (preconnect, preload, a font-display change) that may not apply to your page:

Do these first (biggest wins):

  • Eliminate render-blocking CSS and JavaScript. Inline the critical, above-the-fold CSS directly in <head>; load the rest asynchronously; add async/defer to non-critical scripts. Repositioning a <link> tag does not help — the browser won’t paint until all CSS is loaded and parsed regardless of where the tag sits.
  • Reduce TTFB (server response time). Caching, a CDN, a faster origin — anything that gets the first byte out sooner directly shaves FCP.
  • Fix font loadingFont loading is how a browser fetches, applies, and renders custom web fonts — and specifically what it shows while the font file downloads. Those choices, controlled mainly by the CSS font-display property, directly affect two Core Web Vitals: LCP and CLS.. Use font-display: swap (shows fallback text immediately, swaps in the web font when ready) or font-display: optional (skips the web font if it isn’t already cached). Avoid font-display: block for critical text — it’s the worst for FCP.

Then tidy up the rest:

  • Preconnect to required origins with <link rel="preconnect"> — establishing early connections to important third-party origins can save 100–500 ms.
  • Preload key requests (<link rel="preload">) for a critical font or the LCP image.
  • Minify CSS, remove unused CSS, remove unused JavaScript — smaller files parse and unblock paint faster.
  • Avoid multiple redirects, avoid enormous network payloads, serve static assets with an efficient cache policy, avoid an excessive DOM size, and minimize critical request depth. General payload hygiene that all feeds first paint.

The FCP → TTFB → LCP diagnostic chain

This is how I’d actually use FCP, and it’s the framing the docs gesture at but don’t develop. Treat the three loading metrics as one workflow:

  1. FCP is high → check for render-blocking resources (CSS/JS in <head>). That’s the most common cause and the fastest win.
  2. Also check TTFB — because FCP includes it, a slow server inflates FCP before any render-blocking even enters the picture. web.dev’s guidance: because TTFB precedes both FCP and LCP, your server should respond fast enough that the 75th percentile of users hit a “good” FCP.
  3. These same problems often cascade into LCP — the metric that’s actually a ranking signal — because FCP and LCP frequently share root causes. That’s an overlap worth checking, not a guarantee: LCP has factors of its own (the size, priority, and load path of its specific largest element), so fixing FCP’s causes doesn’t promise a fixed LCP. It’s the right first place to look, not the last step.

That’s the value of FCP for an SEO: it’s a cheap, early read on whether the loading path is healthy, before the more selective LCP measurement even completes.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.