First Contentful Paint: what it measures and what moves it
You fix First Contentful Paint by reducing back end wait, unblocking the first render and sorting fonts. This guide shows what FCP measures, why it sits in Lighthouse, how it relates to LCP, and a quick routine you can run on any page.
By Théophile Louvart, founder of Porteur · Updated 14 September 2026 · Markdown
What First Contentful Paint measures
First Contentful Paint is the time from navigation to the first text or image draw. It is the moment something real appears, not a blank screen.
- Good as of 2026: up to 1.8 s
- Needs work: 1.8 s to 3 s
- Poor: above 3 s
FCP is not a Core Web Vital. It is part of Lighthouse’s Performance score, weighted 10 percent. It does not appear in the Search Console Core Web Vitals report.
You will see two kinds of data. Field data, from real Chrome users over 28 days at the 75th percentile. Lab data, a single Lighthouse run on a simulated mid-range phone over throttled 4G. The two can disagree. Field data wins for Search and for prioritisation.
Why FCP matters on a small site
Users feel the page has started when FCP lands early. It reduces the blank screen time while the rest builds. It sets the tone before LCP arrives.
You do not chase 100. You ship fast first paint on the pages that get visits: the home page, /pricing, /guides/getting-started. A quick first draw lowers drop-offs on slow mobile connections and older devices.
How FCP relates to LCP, INP and CLS
FCP is the first visible content. LCP is the largest above-the-fold content: a hero image, a big heading or a video poster. FCP is first, LCP is the big thing you care about for rankings.
| Metric | What it measures | Good threshold |
|---|---|---|
| Largest Contentful Paint (Core Web Vital) | Time to the largest image, video poster or text block in the viewport | Up to 2.5 s |
| Cumulative Layout Shift (Core Web Vital) | Unexpected layout movement during a session window | Up to 0.1 |
| Interaction to Next Paint (Core Web Vital) | Slowest interaction’s delay to next paint over a visit | Up to 200 ms |
| First Contentful Paint (Lighthouse only) | Time to first text or image draw | Up to 1.8 s |
| Time to First Byte | Time to first response byte from the server | Up to 0.8 s |
INP replaced First Input Delay in March 2024. Lighthouse cannot interact, so Total Blocking Time is its lab proxy for INP and carries 30 percent of the score. Keep that in mind when you balance work.
What actually moves FCP
Three levers move FCP on most product sites: back end wait, render-blocking resources, and fonts. Fix them in this order.
- Time to First Byte: long server work or slow networks delay the first paint.
- Render-blocking resources: CSS in the head blocks rendering, synchronous scripts block parsing.
- Fonts: the first text cannot draw until the font decision is clear, and a late web font can blank text.
A quick diagnosis routine for any page
Open PageSpeed Insights for your URL
Check the Mobile tab first. Look at the field section at the top. If FCP shows in the distribution, note the 75th percentile. If there is no field data, use Lighthouse lower down but treat it as lab only.
Compare with LCP and TTFB
If LCP is slow and TTFB is high, start with the server. If FCP is slow but TTFB is fine, look for blocking CSS and fonts.
Read Lighthouse opportunities
Under Diagnose performance issues, expand Render-blocking resources, Reduce unused CSS and Eliminate render-blocking resources. Expand Preload key requests and Ensure text remains visible during webfont load.
Inspect the head of the document
View-source on yourpage.com. Count stylesheets and synchronous scripts in the head. Note @import in CSS. Spot any Google Fonts CSS URL and whether you preload fonts.
Check the first paint content
What draws first? A logo SVG, a nav, or a heading. Make sure the markup for that content is in the HTML, not injected by JavaScript.
Run a local throttle test
Use Chrome DevTools, Performance panel. Simulate a mid-range phone and slow 4G. Record once. Look at the first paint and long tasks around it.
A page that is fixed will show FCP close to TTFB plus a small render time, stable across runs on mobile. The first text appears before any heavy scripts execute.
Reduce Time to First Byte
TTFB is the time from request start to the first byte of the response. It includes DNS, TCP and TLS, redirects, and your server’s work. It sets the earliest possible FCP.
- Cache or pre-render the HTML on the edge. Serve the shell fast even if data loads later.
- Use a CDN close to users. Enable HTTP/2 or HTTP/3 and keep-alive.
- Remove redirect chains. Send the final URL in all links and sitemaps.
- Profile slow back end code. Cut database round trips and serial API calls.
- Ship 103 Early Hints for critical CSS and fonts when your stack supports it.
On yourproduct.com/pricing, a drop in TTFB from 1.6 s to 0.5 s often moves FCP by about a second, because the browser can start layout and paint sooner.
Unblock the first render
Stylesheets in the head block first paint. Synchronous scripts block parsing. Your goal is to inline only what is needed for the above-the-fold view, and defer the rest without breaking the design.
- Inline critical CSS for the hero and nav. Under about 14 kB compressed is a common ceiling for the first chunk.
- Load non-critical CSS with media=print and swap onload, or use disabled until onload patterns. Remove @import chains.
- Defer or async all scripts that do not set up the first paint. type=module defers by default. Move any remaining blocking scripts to the end of body.
- Remove unused CSS. Ship fewer kilobytes and fewer files. A single merged CSS file for critical styles is fine.
- Avoid JavaScript-inserted first content. Server-render the first heading and nav so the browser can paint without waiting for hydration.
/guides/getting-started with four CSS files in the head and a synchronous analytics script will paint late. Inline the header styles, defer the script, and load the rest of the CSS after onload. The first H1 will draw sooner, and FCP will drop under 1.8 s on mobile in lab runs.
Make fonts stop blocking paint
Web fonts delay text. The browser must decide which face to use and fetch it. If the font arrives late and you block rendering, FCP suffers. If you swap too late, you get a flash of invisible text.
- Use font-display: swap or optional so fallback text draws at FCP. Only the first viewport needs this guarantee.
- Preload the one font file used above the fold. rel=preload as=font crossorigin. Point it at the exact WOFF2 file.
- Self-host fonts in WOFF2. A third-party host adds DNS, connection and TLS before bytes flow.
- Subset by unicode-range so the file the first paint needs is small. A variable font can replace several files, but still subset.
- Consider a system font stack for the UI. It costs no network trip and paints early.
- If the swapped font shifts layout, match metrics. Use size-adjust and ascent-override on the fallback to keep CLS low.
On yourproduct.com, if your first visible copy is the H1, preload the regular weight that renders it. Set font-display: swap. The first paint will not wait for a 90 kB font from a third-party CSS URL.
Do third-party scripts affect FCP
They can. A synchronous tag in the head blocks parsing. Even deferred scripts compete for bandwidth before the first paint if you start many at once. A heavy tag manager container can inject CSS and JS that add work before paint.
- Remove scripts nobody uses. Verify in your analytics and tag manager.
- Load on interaction when possible. Use a facade for video embeds.
- Defer until after load. Preconnect to origins that must start early, but be sparing.
- Keep the tag manager container small and split by environment.
How to check FCP the right way
PageSpeed Insights shows field data at the top when there is enough traffic, and a Lighthouse run below. Scores vary between runs. Use field data to judge real users and pass or fail of Core Web Vitals. Use Lighthouse to find fixes. The Lighthouse score itself is not a ranking factor.
- Search Console’s Core Web Vitals report reads field data per URL or origin. It shows LCP, CLS and INP only.
- CrUX field data comes from opted-in Chrome users on Android and desktop, not iOS.
- Mobile-first indexing is complete. Prioritise mobile FCP and LCP.
A worked example: moving a slow FCP
Say /pricing has FCP 3.2 s on Mobile in Lighthouse, TTFB 1.4 s, LCP 4.6 s. You see three CSS files in the head, a Google Fonts stylesheet, and a synchronous A/B test script. The hero image is marked loading=lazy.
Fix the server wait
Enable HTML caching for /pricing and edge cache it. TTFB falls to 0.6 s.
Inline critical CSS
Inline styles for the header, hero and first section. Load the rest after onload. Remove @import chains. Fewer requests hit the head.
Defer scripts
Move the A/B test off the critical path or run it as deferred with a fast no-flash variation CSS. Defer analytics too.
Sort fonts
Self-host the Inter regular WOFF2, preload it, and set font-display: swap. Add size-adjust to match fallback.
Fix the hero
Remove loading=lazy and add fetchpriority=high to the hero image. If it is a CSS background, add a preload link.
After these changes the next Lighthouse run shows FCP about 1.6 s and LCP about 2.5 s. Field data will follow if traffic is steady, as it needs 28 days and the 75th percentile to move.
Questions
Good FCP is up to 1.8 seconds. Between 1.8 and 3 seconds needs work, above 3 seconds is poor. Treat this as a user comfort target, not a ranking factor.
No. FCP is not a Core Web Vital. It is part of the Lighthouse Performance score at 10 percent. Core Web Vitals as of 2026 are LCP, CLS and INP.
Cut TTFB by caching HTML and using a CDN. Inline critical CSS and defer other CSS and scripts. Use font-display: swap, preload the first font, and self-host WOFF2. These three changes move most pages.
FCP is the time to the first visible content of any size. LCP is the time to the largest above-the-fold element. FCP comes first. LCP is the Core Web Vital that matters for Search.
Lighthouse is one simulated run. PageSpeed Insights shows that plus field data from real Chrome users. Scores vary between runs. Use the field section for real-world judgement and the audits below it for fixes.
Indirectly. You still defer heavy scripts and break long tasks for INP, which also helps the first paint by freeing the main thread. INP’s good threshold is up to 200 ms and it replaced FID in March 2024.
Sources
Check my site, free
Paste your URL to see how your first paint stacks up against rivals and which of TTFB, blocking CSS or fonts holds it back, in about thirty seconds, free.
- Free check, no card
- Read-only, your own accounts
- Readable by your agent
Read next
- GuideCore Web Vitals for a product site: the three numbers
- GuideLargest Contentful Paint: what slows it and what fixes it
- GuideTime to first byte: the delay every other metric inherits
- GuideRender-blocking resources: what blocks the first paint and how to unblock it
- GuideWeb fonts and page speed: load one face, and load it first
- GuideHow to read PageSpeed Insights: field data first, then the score
- GlossaryE-E-A-T
- GuideHow to improve Interaction to Next Paint