Web Performance

What Is First Contentful Paint (FCP)?

First Contentful Paint marks when a page first shows content. What FCP is, what is good, how it differs from LCP, what causes a slow score, and how to fix it.

StackOptic Research Team16 May 20269 min read
First Contentful Paint — the FCP loading metric explained

The first thing a visitor wants to know, consciously or not, is whether the page is actually loading. A blank screen creates doubt; the first flash of content creates confidence. First Contentful Paint (FCP) puts a number on that moment — the time from when the page starts loading to when the browser paints the first piece of content, be it text, an image or any non-blank pixel. In short: FCP marks when something first appears on screen, a good score is 1.8 seconds or less at the 75th percentile per web.dev, and it is dominated by your server response, render-blocking resources and fonts. This guide explains what FCP measures, how it differs from LCP, what makes it slow, and how to fix each cause.

It is a companion to the loading metrics in Core Web Vitals explained.

What FCP measures

FCP records the moment the browser renders the first content after the page begins loading. "Content" has a specific meaning here: text, images (including background images), <svg> elements, and non-white <canvas> elements all count. What does not count is anything that leaves the screen blank — so the time spent waiting for the server, parsing render-blocking CSS, or running scripts before the first paint all sits inside FCP.

It is the first of the paint milestones a browser hits. After the request is made and the response starts arriving, the browser builds enough of the page to put something on screen, and that instant is FCP. It is an early, reassuring signal: the user sees that the page is alive and responding, even before the main content has finished arriving.

The thresholds

Web.dev defines FCP ratings at the 75th percentile of real page loads:

FCPRating
≤ 1.8sGood
1.8s - 3.0sNeeds improvement
> 3.0sPoor

As with the Core Web Vitals, the 75th-percentile rule means the median experience is not the whole story. Three-quarters of your visits — including those on mid-range phones and congested networks — should see content begin to appear within 1.8 seconds. A page that paints instantly on a developer laptop can still post a poor field FCP if real users wait far longer.

FCP vs LCP: first content vs largest content

FCP and LCP are easy to confuse because both are loading metrics measured in seconds, but they answer different questions.

FCPLCP
MarksFirst content of any kindLargest content element in the viewport
Typical elementA line of text, a logo, an iconHero image, main heading, video poster
Question it answers"Has the page started showing anything?""Has the main content arrived?"
Good threshold (75th pct)≤ 1.8s≤ 2.5s
Core Web Vital?NoYes

In sequence, FCP always happens at or before LCP — the first content cannot appear after the largest content. A common pattern is a fast FCP (a heading or navigation paints quickly) followed by a slower LCP (the hero image is still downloading). When FCP is fast but LCP is slow, the problem is usually the specific largest element, and the fix lives in what is Largest Contentful Paint and how to improve it. When FCP itself is slow, the whole render is being held up, and the causes below apply.

The causes of a slow FCP

Almost every slow FCP traces to one of three root causes, each with a direct remedy.

CauseWhat is happeningPrimary fix
Slow TTFBThe browser has nothing to render until the server respondsServer caching, CDN, faster backend
Render-blocking CSS/JSThe browser must fetch and process head resources before paintingInline critical CSS, defer/async JS, remove unused CSS
Slow web fontsText is hidden (FOIT) until the font loadsfont-display: swap/optional, preload key fonts

A genuinely slow FCP often combines these — for example a moderate TTFB and a large render-blocking stylesheet — so measuring the breakdown rather than the total is what makes the fix efficient.

How to improve FCP

1. Reduce Time to First Byte

FCP cannot start until the browser has received a response to begin rendering, so a slow Time to First Byte (TTFB) delays it directly. If the server takes 1.5 seconds to send the first byte, FCP simply cannot be under 1.8 seconds. Lower TTFB with full-page and server-side caching, a CDN serving from a nearby edge, optimised database queries, and adequate hosting. The full method is in what is Time to First Byte (TTFB) and how to improve it. This is the foundation; fix it first when it dominates.

2. Eliminate render-blocking resources

By default, CSS and synchronous JavaScript in the <head> block rendering: the browser will not paint until it has downloaded and processed them, because it needs the styles to know how the page should look and it pauses parsing for scripts. This is the most common FCP bottleneck once the server is fast. The fixes: inline the small amount of critical CSS needed for the above-the-fold view and load the rest non-blocking; add defer or async to scripts so they do not block the parser; and remove unused CSS the browser is downloading for nothing. Each render-blocking resource you remove from the critical path lets the first paint happen sooner.

3. Handle web fonts so text appears promptly

Web fonts can hide your text during load. With the default behaviour, a browser may show a flash of invisible text (FOIT) — blank space where text should be — until the custom font finishes downloading, pushing back FCP for any page whose first content is text. Set font-display: swap so the browser paints text immediately in a fallback font and swaps in the custom one when ready (or optional if you would rather not swap at all on slow connections). Preload the key font files so they arrive sooner. This is part of a broader font strategy covered in how to optimize web fonts for performance, and it directly protects FCP on text-first pages.

4. Reduce JavaScript on the critical path

Large scripts that run before the first paint delay it, both by competing for the network and by occupying the main thread. Shipping less JavaScript, code-splitting so each page loads only what it needs, and deferring non-critical scripts all help the browser reach its first paint sooner — see how to reduce JavaScript and speed up your site. This matters most for client-rendered pages, where content may not exist until a framework has downloaded and run.

Lab data vs field data for FCP

FCP, like the other loading metrics, comes in two forms and they can disagree. Lab data from Lighthouse or the PageSpeed Insights lab test is a single simulated load on a fixed device and network — reproducible and ideal for diagnosis and quick iteration. Field data from the Chrome UX Report reflects real visits across the full range of devices and connections, and it is the version that represents your actual users. A page can post a great lab FCP yet a mediocre field FCP if real visitors are on slower hardware than the test assumes, or if a third-party script behaves differently in the wild. The workflow is the same as for every metric: iterate with lab data because it is fast and controllable, but judge success by field data because that is what your users experience. Where the two diverge sharply, trust the field and look for what the clean lab run is failing to reproduce.

How to measure FCP

A short, repeatable process:

  1. Run the URL through PageSpeed Insights — it reports FCP in both field data (CrUX) and the lab test, and flags the render-blocking resources holding it back.
  2. Open Chrome DevTools - Performance, record a load, and read the FCP marker on the timeline alongside the network and main-thread activity that preceded it.
  3. Use the DevTools Network panel Timing tab to see whether a high TTFB is eating into your budget before any rendering can happen.
  4. Cross-check with WebPageTest, whose filmstrip shows the exact frame where content first appears — a visual confirmation of FCP that makes the cause obvious.

The diagnostic question is always the same: in the time before first paint, what was the browser waiting on — the server, a blocking resource, or a font? The answer points straight at the relevant fix above.

A worked example

Imagine PageSpeed Insights reports a field FCP of 2.9 seconds — "needs improvement". The DevTools breakdown shows a healthy TTFB of around 300ms, so the server is fine, but a large blocking stylesheet and two synchronous scripts sit in the <head>, and the page's body text uses a custom font with default loading. Three changes follow. You inline the critical above-the-fold CSS and load the rest of the stylesheet non-blocking; you add defer to the two scripts; and you set font-display: swap on the body font and preload it. The browser can now paint the heading and text in a fallback almost as soon as the HTML arrives, instead of waiting for CSS, scripts and a font. Field FCP drops to around 1.4 seconds, comfortably "good". This is the typical shape of FCP work — unblocking the critical path so the first paint happens early.

Why FCP matters

FCP is not a Core Web Vital and is not a direct ranking factor, but it matters for two reasons. First, perceived performance: the gap between clicking a link and seeing anything is when users decide whether a site feels fast or broken, and a quick first paint reassures them the page is loading. Second, diagnostic value: because FCP captures the server response and the render-blocking critical path, it is an excellent early-warning metric — a slow FCP almost always means a slow LCP too, since LCP includes everything FCP does and more. Fixing FCP therefore tends to lift the loading Core Web Vital alongside it, which is why it earns attention even though it does not appear on the scorecard itself.

Common mistakes

  • Treating a slow FCP as a front-end problem when a high TTFB is the real cause.
  • Leaving large stylesheets and synchronous scripts in the <head>, blocking the first paint.
  • Ignoring fonts, so text stays invisible (FOIT) until a custom font downloads.
  • Optimising the lab FCP while the field FCP, which represents real users, stays poor.
  • Confusing FCP with LCP and optimising the wrong element as a result.

Go deeper

Want your First Contentful Paint measured alongside the rest of your Core Web Vitals, SEO and security? Analyse any URL with StackOptic — free, no sign-up.

Frequently asked questions

What is First Contentful Paint (FCP)?

FCP is a performance metric that measures how long it takes, from when the page begins loading, for the browser to render the first piece of content. 'Content' means any text, image, non-white canvas or SVG — essentially the first moment the screen stops being blank and shows something. It is an early signal that the page is working and loading, which reassures the user that their request was received.

What is a good First Contentful Paint score?

According to web.dev, a good FCP is 1.8 seconds or less, measured at the 75th percentile of real page loads. Between 1.8 and 3.0 seconds needs improvement, and above 3.0 seconds is considered poor. The 75th-percentile rule means most of your visitors, including those on slower devices and connections, should see content begin to appear within 1.8 seconds, not just your fastest users.

What is the difference between FCP and LCP?

FCP marks when the first content of any kind appears — it could be a small piece of text or a logo. LCP marks when the largest content element in the viewport appears, usually the hero image or main heading. So FCP tells you when the page first shows something, and LCP tells you when the main content a visitor came for has rendered. A page can have a fast FCP but a slow LCP if a small element paints early while the big one lags.

What causes a slow FCP?

Three causes dominate. A slow Time to First Byte delays everything because the browser has nothing to render until the response arrives. Render-blocking CSS and synchronous JavaScript in the head force the browser to fetch and process them before it paints anything. And slow-loading web fonts can hide text until the font is ready. Each of these prevents the browser from painting that crucial first content quickly.

How do I improve First Contentful Paint?

Start by reducing Time to First Byte with caching and a CDN so the response arrives sooner. Eliminate render-blocking resources: add defer or async to scripts, inline the critical CSS needed for the first view, and remove unused CSS. Handle fonts with font-display: swap so text paints in a fallback immediately, and preload key fonts. These changes let the browser show content as early as possible, lowering FCP.

Analyse any website with StackOptic

Get the full technology stack, performance, security and SEO report in seconds — free.

Analyse a website

Related articles