FCPCore Web VitalsLighthousePerformanceTutorial

How to Improve First Contentful Paint (FCP): The Complete Guide

First Contentful Paint above 1.8s hurts your Lighthouse score and perceived speed. Learn every major FCP cause and fix — server response, render-blocking resources, fonts — for WordPress, Shopify, and Next.js.

PageSpeed Exporter Team··8 min read

First Contentful Paint (FCP) measures the time from navigation start to the moment the browser paints the first piece of real content — text, an image, a canvas, or an SVG. Google considers 1.8 seconds or faster "good." Anything above 3.0 seconds is "poor" and signals a real loading problem to users before they see anything on screen.

FCP is not one of Google's three Core Web Vitals (that's LCP, INP, and CLS), but it contributes 10% to your Lighthouse Performance score and shares nearly all the same root causes as LCP — so fixing FCP is usually the first domino in a broader speed improvement.

This guide covers every major FCP cause Lighthouse flags, with platform-specific code fixes you can ship today.


What Is FCP and Why Does It Matter?

FCP answers a simple question: "How long does the user stare at a blank white screen?" It is the first signal that a page is actually loading, well before the main content (LCP) is ready.

| FCP range | Rating | User perception |

|---|---|---|

| 0 – 1.8s | Good | Feels instant |

| 1.8 – 3.0s | Needs improvement | Noticeable delay |

| > 3.0s | Poor | Users may bounce before content appears |

Unlike Cumulative Layout Shift, which measures stability, and LCP, which measures when the main content is ready, FCP only cares about the first pixel of real content — even a single line of header text counts.


How Do I Find What's Slowing My FCP?

Run a Lighthouse audit on your URL. In the Diagnostics and Opportunities sections, look for:

  • "Reduce initial server response time" — flags slow TTFB, which delays every downstream metric including FCP
  • "Eliminate render-blocking resources" — CSS and JavaScript in that must finish before any paint occurs
  • "Avoid enormous network payloads" — large HTML documents take longer to parse before the first paint

Export a stripped AIReport from PageSpeed Exporter and check the metrics.fcp value alongside the issues array for "id": "server-response-time" or "id": "render-blocking-resources" — these two audits explain the vast majority of slow FCP scores.


Cause 1: Slow Server Response Time (TTFB)

The browser cannot paint anything until it receives the first byte of HTML. If your server takes 1.5 seconds to respond, your FCP floor is already 1.5 seconds — no client-side optimization can beat that.

Fixes by platform:

| Platform | Fix |

|---|---|

| WordPress | Install WP Rocket or W3 Total Cache for full-page caching; use a managed WordPress host |

| Next.js / Vercel | Use Static Generation (generateStaticParams) or ISR instead of pure SSR where possible; enable Vercel Edge caching |

| Shopify | Shopify's platform handles server response automatically — focus on theme-level render-blocking instead |

| Custom Node/Express | Add Redis or in-memory caching for expensive database queries; put a CDN (Cloudflare, Fastly) in front |

# Quick TTFB check with curl
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" https://example.com

TTFB above 800ms is flagged by Lighthouse. See What is TTFB? for a full breakdown of server-side causes.


Cause 2: Render-Blocking CSS and JavaScript

Stylesheets and synchronous scripts in stop the browser from painting anything until they finish downloading and executing.

Before (blocks first paint):
<head>
  <link rel="stylesheet" href="/css/theme.css">
  <script src="/js/vendor-bundle.js"></script>
</head>
After (critical CSS inline, everything else deferred):
<head>
  <style>
    /* Inlined critical above-the-fold CSS only */
    body { margin: 0; font-family: system-ui, sans-serif; }
    header { min-height: 64px; background: #0f172a; }
  </style>
  <link rel="preload" href="/css/theme.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <script src="/js/vendor-bundle.js" defer></script>
</head>
Next.js: Client-side JavaScript in Server Components does not block FCP the way it does in a pure client-side React app — the initial HTML already contains real content. If you're using 'use client' heavily on above-the-fold sections, consider moving static content back to Server Components. WordPress: Autoptimize and WP Rocket can auto-generate critical CSS and defer the rest. Manually, identify above-the-fold selectors using Chrome DevTools Coverage (Cmd+Shift+P → "Show Coverage").

See the full render-blocking resources guide for more detail — the same fixes benefit both FCP and LCP.


Cause 3: Large or Unoptimized HTML Payloads

A page with an enormous DOM (many nested divs, huge inline SVGs, or bloated component libraries rendering server-side) takes longer to parse before the browser can paint the first element, even after the HTML has fully downloaded.

Fixes:
  • Reduce total DOM nodes — Lighthouse flags pages above ~1,500 nodes
  • Avoid inlining large SVGs or base64 images directly in the initial HTML response
  • For React/Next.js: avoid rendering entire off-screen sections server-side that could be lazily hydrated instead

Cause 4: Slow DNS, Connection Setup, or No HTTP/2

Every new domain the browser must resolve and connect to before rendering (fonts, analytics, CDNs) adds latency before FCP. HTTP/1.1 also serializes requests, adding further delay.

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

Enable HTTP/2 or HTTP/3 on your server or CDN — nearly all modern hosts (Vercel, Cloudflare, Netlify) support this by default. If you're on shared hosting or an older CDN configuration, confirm with curl -I --http2 https://example.com.


Cause 5: Web Fonts Blocking Text Render (FOIT)

If a to a web font is render-blocking and the browser is configured to hide text until the font loads (Flash of Invisible Text), FCP is delayed until the font downloads — even though a fallback font could render instantly.

Fix with font-display: swap:
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap; /* renders fallback text immediately */
}
Next.js with next/font handles this automatically:
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], display: 'swap' });

Self-hosting fonts (rather than loading from fonts.googleapis.com) also removes a third-party DNS lookup and connection, typically saving 50–200ms on first render.


Platform Quick-Reference: Top FCP Fixes

| Platform | #1 FCP cause | Fastest fix |

|---|---|---|

| WordPress | No page caching + render-blocking plugin CSS | Install WP Rocket; defer non-critical plugin assets |

| Shopify | Theme CSS/JS loaded synchronously in | Audit theme.liquid; defer app embed scripts |

| Next.js | Over-use of client components for static content | Prefer Server Components for above-the-fold sections |

| Webflow | Custom code injection in | Move non-critical scripts to before with defer |

| Plain HTML | Unminified CSS/JS, no caching headers | Minify assets; add Cache-Control headers; enable gzip/brotli |


Before and After: Real-World Impact

A WordPress blog with no caching plugin and a render-blocking Google Fonts import measured FCP: 3.4s on mobile. After installing WP Rocket (full-page caching, dropping TTFB from 1.4s to 0.3s) and switching the font import to font-display: swap with preconnect hints, FCP dropped to 1.3s — moving from "poor" to "good," and the overall Lighthouse performance score rose from 54 to 81.


How to Verify Your FCP Fix

  1. Re-run Lighthouse on the same URL and device strategy (mobile vs desktop)
  2. Confirm FCP is under 1.8 seconds in the metrics section
  3. Check that "Eliminate render-blocking resources" and "Reduce initial server response time" no longer appear as opportunities
  4. Compare lab FCP against real-user CrUX data in your export — FCP itself isn't in Search Console's Core Web Vitals report, but LCP field data (which shares the same root causes) will confirm the improvement over time

For before/after tracking on Starter plans, re-scan the same URL and use the comparison view to confirm FCP dropped.


How Do I Fix FCP Using AI?

Export your Lighthouse data and ask an AI agent to prioritize the fix order:

I'm attaching my Lighthouse AIReport for example.com.
My FCP is 3.1s (poor). I need to get it under 1.8s.

1. Identify the exact audits contributing to slow FCP, sorted by estimated savings in ms
2. For each one, explain the root cause and provide the exact code fix
3. Tell me which single fix will have the biggest FCP impact

I'm using [WordPress / Shopify / Next.js].

See How to Fix Core Web Vitals Using ChatGPT for the full AI workflow.


Further Reading


Sources


Further reading

Try it yourself

Run a free Lighthouse audit on any URL and get the full JSON report for your AI agent — no account required.

Analyze a URL for free