# First Contentful Paint (FCP): what it is and how to fix it

**Audit ID:** `first-contentful-paint` · **Category:** Performance

<!--QA-->
> **Quick answer:** First Contentful Paint measures when the first text or image appears on screen. A good FCP is under 1.8 seconds. Improve it by cutting server response time, removing render-blocking CSS and JavaScript, preconnecting to critical origins, and using font-display swap. FCP happens before LCP and gates it.
<!--/QA-->

FCP measures the time from navigation start to when the browser paints the first piece of content: text, an image, a non-blank canvas. It is the user's first signal that the page is actually loading.

## TL;DR

- **What:** Time until the first text or image renders.
- **Thresholds:** Good under 1.8 s, needs improvement 1.8-3.0 s, poor over 3.0 s (mobile, throttled).
- **Fix:** Cut server response time, remove render-blocking CSS/JS, preconnect to critical origins, fix font loading.

## What is First Contentful Paint (FCP)?

FCP is the gap between the request starting and the first DOM content paint. It comes before LCP: FCP is "something appeared," LCP is "the main thing appeared." A slow FCP almost always drags LCP with it, so fixing FCP is upstream leverage.

## Why does First Contentful Paint matter?

FCP is the first moment a user stops looking at a blank screen. Pages with slow FCP feel broken even when they eventually load fast. It also gates every later metric: nothing meaningful paints until the first paint happens.

## What causes slow FCP and how do I fix it?

### 1. Slow server response (TTFB)

Nothing renders until the first bytes arrive. If time to first byte is high, FCP cannot be fast.

- Cache HTML at a CDN edge.
- Use HTTP/2 or HTTP/3.
- Reduce backend work: query optimization, response caching, avoid per-request cold starts.

### 2. Render-blocking CSS and JavaScript

The browser will not paint until it has processed blocking CSS in `<head>` and any synchronous scripts before content.

```html
<!-- Inline the critical above-the-fold CSS -->
<style>/* critical CSS here */</style>

<!-- Load the rest non-blocking -->
<link rel="preload" href="/styles.css" as="style" onload="this.rel='stylesheet'" />

<!-- Defer scripts -->
<script src="/app.js" defer></script>
```

### 3. No early connection to critical origins

If your fonts, hero image, or critical API live on another origin, the browser pays DNS + TCP + TLS before it can fetch them.

```html
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preconnect" href="https://cdn.example.com" />
```

### 4. Web fonts blocking text

With the default `font-display: auto`, text can stay invisible until the font downloads (flash of invisible text), delaying FCP.

```css
@font-face {
  font-family: 'Inter';
  src: url('/inter.woff2') format('woff2');
  font-display: swap;
}
```

Preload the one or two fonts used above the fold.

## What are common FCP mistakes?

- **Optimizing LCP while ignoring FCP.** If FCP is 3 s, LCP cannot be 2 s. Fix the first paint first.
- **Large blocking CSS frameworks.** Shipping an entire UI library's CSS render-blocking in `<head>`.
- **Synchronous third-party tags in `<head>`.** Tag managers and A/B tools loaded before content block the first paint.
- **No preconnect for the font origin.** Costs a full round trip on the critical path.
- **Client-side rendering with an empty shell.** If the initial HTML is `<div id="root"></div>`, FCP waits for the JS bundle. Consider SSR or static prerender.

## How do I improve FCP in Next.js, SPAs, or WordPress?

- **Next.js / Astro / SvelteKit:** prefer static or server rendering so meaningful HTML ships in the first response.
- **SPAs:** add a server-rendered or prerendered shell with real above-the-fold content, not just a spinner.
- **WordPress:** a page cache plugin plus critical-CSS generation (e.g. via a performance plugin) addresses most FCP issues.

## How do I verify FCP improved?

1. Re-run Lighthouse: FCP should drop under 1.8 s on the mobile profile.
2. DevTools → Performance → record a load → read the FCP marker.
3. Check field data in Search Console / CrUX: lab FCP improving should track with real users over a few weeks.
4. Confirm LCP and TBT did not regress while changing the critical path.

## Related audits

- [Largest Contentful Paint (LCP)](/audits/largest-contentful-paint), the next paint milestone after FCP
- [Eliminate render-blocking resources](/audits/render-blocking-resources), the most common FCP blocker
- [Enable text compression](/audits/enable-text-compression), smaller HTML/CSS reaches the browser sooner

---

Audit your URL at https://lighthouse-md.com.
