First Contentful Paint (FCP) is a Web Vitals metric that measures the time from when a page starts loading to when the browser renders the first piece of DOM content — text, image, non-blank canvas, or SVG. Google considers FCP good when it happens in under 1.8 seconds at the 75th percentile of real users.

Good threshold
< 1.8s
Category
Technical SEO
Measured at
75th percentile
Difficulty
Intermediate

FCP is the first honest signal your page gives a visitor: "something is happening." Before FCP, the browser is a white screen. After FCP, the user knows the page is alive. That gap is where bounces are born.

What is First Contentful Paint (FCP)?

FCP is a page-load metric that fires the moment the browser paints the first piece of DOM content from the server response. That first content can be any of:

  • Text (once fonts have loaded or fallback fonts are used)
  • An <img> (once decoded)
  • A non-blank <canvas>
  • An SVG element

Background CSS images and iframes do not count. Neither does anything hidden with opacity: 0 or visibility: hidden. FCP is defined by the W3C Paint Timing API and reported by every modern browser through performance.getEntriesByType('paint').

Google's stance

FCP is one of the six metrics tracked in Chrome UX Report (CrUX) and PageSpeed Insights. It's not a Core Web Vital in itself, but Google uses it as a diagnostic and treats consistently slow FCP as a signal of poor page experience.

Why FCP matters

FCP is the earliest signal of perceived speed. Get it wrong and no other metric can save you.

  1. Bounce prevention. Users decide whether to wait or bail within the first 3 seconds. A white screen past 2 seconds materially lifts bounce rate — Google's own studies put the impact at 32% higher bounce probability going from 1s to 3s.
  2. LCP prerequisite. Largest Contentful Paint (the ranking-factor Core Web Vital) can't happen before FCP. Optimize FCP and LCP usually follows.
  3. Conversion signal. Amazon and Walmart have both published data showing every 100ms of load delay costs 1% of revenue. FCP is where those 100ms are usually hiding.

How FCP is measured

The Paint Timing API exposes FCP directly. Every Chromium browser (Chrome, Edge, Opera, Brave) records it and reports it to Google's CrUX dataset. Safari and Firefox measure it in DevTools but don't ship it to CrUX.

# Measure FCP in the browser
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.name === 'first-contentful-paint') {
      console.log('FCP:', entry.startTime, 'ms');
    }
  }
}).observe({ type: 'paint', buffered: true });

Where FCP is measured in the wild

Two data sources matter:

  • Field data (CrUX) — real Chrome users. This is what Google uses for ranking signals.
  • Lab data (Lighthouse) — a simulated single load in a controlled environment. Useful for debugging, not for grading.

FCP thresholds and where FCP fits in Web Vitals

MetricWhat it measuresGoodPoor
FCP First content painted < 1.8s > 3.0s
LCPLargest element painted< 2.5s> 4.0s
INPInteraction to Next Paint< 200ms> 500ms
CLSCumulative Layout Shift< 0.1> 0.25
TTFBTime to First Byte< 800ms> 1.8s

Real FCP examples and fixes

Three common patterns account for most slow FCPs.

1. Render-blocking stylesheet

# Before: FCP 3.2s — CSS blocks the first paint
<link rel="stylesheet" href="/theme.css">

# After: FCP 1.4s — critical CSS inlined, rest deferred
<style> /* critical above-the-fold rules */ </style>
<link rel="preload" href="/theme.css" as="style" onload="this.rel='stylesheet'">

2. Slow origin, no CDN

A blog on a single VPS in Frankfurt served visitors globally with TTFB of 1.4s. Moving to a CDN with 30+ POPs dropped TTFB to 180ms and FCP from 3.1s to 1.2s — no code changes.

3. Third-party font blocking text render

An e-commerce site loaded Google Fonts synchronously. Text stayed invisible until fonts arrived — FCP effectively pushed to 2.9s. Adding font-display: swap pulled FCP back under 1.5s by letting the browser paint fallback fonts immediately.

Both measure paint. The difference is what gets painted.

Optimize FCP when

  • Your page shows a long white screen
  • TTFB is over 800ms
  • Render-blocking CSS/JS is present
  • You want to reduce perceived load time
  • You're chasing Lighthouse score improvements

Prioritize LCP when

  • FCP is already under 1.8s
  • Your hero image is late or oversized
  • You're chasing Core Web Vitals ranking
  • Above-the-fold content is heavy
  • Google Search Console flags LCP issues

7 best practices to hit FCP under 1.8s

  1. Cut TTFB first. Every millisecond of server delay pushes FCP later. Cache HTML at the edge, upgrade hosting, or move to a CDN.
  2. Inline critical CSS. Extract the CSS needed for the first viewport (usually under 14KB) and inline it in <head>.
  3. Defer non-critical JavaScript. Add defer or async to script tags so JS parsing doesn't block the paint.
  4. Use font-display: swap. Never let web fonts hide text. Show fallback fonts immediately, swap when ready.
  5. Preconnect to critical origins. Add <link rel="preconnect"> for CDNs and font hosts to open the TCP+TLS handshake early.
  6. Serve WebP / AVIF images. Modern formats cut image bytes by 25-50%, so above-the-fold images paint faster.
  7. Eliminate 3XX redirect chains. Every hop costs a full round trip. Redirect once, directly to the final URL.
Common mistake — optimizing Lighthouse, not CrUX

Lighthouse runs a single simulated load on your dev machine. CrUX shows real users on real devices at the 75th percentile. Chasing a green Lighthouse score won't help ranking if your CrUX FCP is still over 3s. Always verify improvements in Search Console's Core Web Vitals report.

Common FCP mistakes to avoid

  • Loading web fonts synchronously — hides all text until fonts arrive.
  • Blocking JavaScript in <head> — parser stops until the script downloads and executes.
  • Massive bundled CSS — 300KB stylesheets block the paint even when 90% of the rules aren't needed above the fold.
  • Client-side rendering on cold visits — SPAs that render the entire DOM in JS often have FCP over 3s.
  • Skipping preconnect — cross-origin requests eat 200-400ms per handshake without it.
  • Testing on desktop only — mobile is where FCP is graded. Test on throttled 4G, not fiber.

Frequently asked questions

FCP is the moment the browser paints the first bit of real content — text, an image, or an SVG — after someone clicks your link. It's the first sign that the page is alive.

Google considers FCP good under 1.8 seconds, needs improvement between 1.8 and 3.0 seconds, and poor above 3.0 seconds. These thresholds are measured at the 75th percentile of real users.

FCP is not one of Google's three Core Web Vitals, but it's part of the Page Experience signals and is closely correlated with LCP, which is a ranking factor. Improving FCP almost always improves LCP too.

FCP measures the first pixel of content painted. LCP (Largest Contentful Paint) measures when the largest visible element finishes rendering. FCP tells you the page started loading; LCP tells you it's usable.

Reduce server response time, eliminate render-blocking resources (JS and CSS), inline critical CSS, preconnect to required origins, and serve static assets from a CDN. Each optimization typically cuts hundreds of milliseconds.

Sources

Akshay VR

Akshay VR

Marketing Head · theStacc · ex-Sr Marketing Specialist, ARKA 360

Akshay leads editorial and content operations at theStacc. He writes about the intersection of technical SEO and content — including the performance metrics that decide whether pages ever get a chance to rank.