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.
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.
<!-- 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.
<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.
@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?
- Re-run Lighthouse: FCP should drop under 1.8 s on the mobile profile.
- DevTools → Performance → record a load → read the FCP marker.
- Check field data in Search Console / CrUX: lab FCP improving should track with real users over a few weeks.
- Confirm LCP and TBT did not regress while changing the critical path.
Related audits
- Largest Contentful Paint (LCP), the next paint milestone after FCP
- Eliminate render-blocking resources, the most common FCP blocker
- Enable text compression, smaller HTML/CSS reaches the browser sooner
Audit your URL at https://lighthouse-md.com.
Audit your page now
Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.