First Contentful Paint (FCP)
First Contentful Paint (FCP) is the time from when the page starts loading until the browser renders the first piece of content: any text, image, non-white canvas or SVG. It marks the moment the visitor sees that something is happening, instead of a blank screen.
FCP is not the moment the page is useful. That is closer to Largest Contentful Paint. But nothing useful can appear before the first content does, so a slow FCP drags every later metric with it.
Why it matters
A blank screen gives no feedback. Visitors cannot tell whether the site is slow or broken, and the longer it lasts, the more of them go back. A fast FCP is reassurance that the page is on its way. FCP also counts toward the Lighthouse performance score.
What we check
We read the FCP value from the Lighthouse mobile run in PageSpeed Insights:
| Result | FCP |
|---|---|
| Good | 1.8 s or less |
| Needs attention | over 1.8 s, up to 3 s |
| Poor | over 3 s |
What delays FCP
Before the browser can paint anything, it needs:
- The HTML. A slow server response delays everything. See the server response time guide.
- All render-blocking CSS. Stylesheets in the
<head>block rendering until they download and parse. - All render-blocking scripts. A
<script>in the<head>withoutdeferorasyncstops the parser until it downloads and runs. - Web fonts, in some cases. With the default font loading behavior, browsers may hide text for a short period while a font downloads.
Redirects before the final page also add a full round trip each. See the redirect chains guide.
How to fix
Speed up the HTML response. Cache rendered pages and serve them from a CDN close to visitors. Avoid redirects on the entry URL.
Inline critical CSS and load the rest without blocking. Put the styles needed for the first
screen directly in the <head>, and keep the full stylesheet small. If you must load a large
stylesheet, split it so that only the part for the current page blocks rendering.
Defer scripts. Scripts in the <head> should almost always have defer, which downloads them in
parallel and runs them after parsing:
<head>
<script src="/app.js" defer></script>
</head>
Use async only for independent scripts, such as analytics, where the execution order does not
matter.
Make text visible during font loading. Add font-display: swap so the browser shows a fallback
font right away:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}
Self-hosting fonts avoids a connection to an extra origin. Preload only the one or two fonts used above the fold.
Compress text resources. Serve HTML, CSS and JavaScript with Brotli or gzip. In Nginx:
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
Most CDNs compress automatically; check that the Content-Encoding response header is present.
Avoid client-side-only rendering for the first screen. If the HTML is an empty <div> filled in
by JavaScript, FCP must wait for the bundle to download and run. Server-side rendering or static
generation puts content in the HTML itself.