Lightscore

First Contentful Paint (FCP)

First Contentful Paint is the time from the start of the navigation to the first text or image on screen. It answers one question for the visitor: is anything happening? Google calls 1.8 seconds or less good, at the 75th percentile of real page loads. Over 3 seconds is poor. FCP isn't a Core Web Vital, and it carries 10 percent of the Lighthouse performance score.

Everything before the paint counts: redirects, connection setup, and TTFBHow long the browser waited before the first byte of the response arrived.. A fast server doesn't guarantee a fast FCP. A slow one guarantees a slow FCP.

What counts as contentful

The Paint Timing spec sets out eight conditions. These are the ones that come up:

Two exclusions matter in practice. A parent frame never sees the paints inside its iframes. A page built entirely from iframes records a first paint and no FCP at all. Text also doesn't count while its web font is in the block period. Set font-display: block and you hide your own first paint behind a font download.

What is a good FCP?

Google's threshold is a field number: 1.8 seconds at the 75th percentile, across real visits. Lighthouse reports a lab number and grades it on a curve, per device.

Device Fast Moderate Slow
Mobile 0–1.8 s 1.8–3 s over 3 s
Desktop 0–0.9 s 0.9–1.6 s over 1.6 s

Desktop is graded about twice as hard, which surprises people who compare the two runs. The control points sit in the Lighthouse source. On mobile, 1,800 ms scores 90 and 3,000 ms scores 50. On desktop those same two scores land at 934 ms and 1,600 ms. Both pairs are quantiles of real pages from the HTTP Archive — the desktop pair from a July 2020 crawl, the mobile pair from May 2021.

FCP is not a Core Web Vital. LCPTime until the largest thing in view (hero image, headline) has painted., INPHow long the page takes to visibly respond to a tap, click or key press. and CLS are. Google does still collect FCP from real Chrome users and publishes it in the Chrome UX Report.

what’s this

The small set of field metrics Google treats as a ranking input and reports in Search Console. We measure their lab equivalents here — real-user field data (CrUX) is a separate signal. TBT is the lab stand-in for INP, not a Core Web Vital itself.

Why does the same page get a different FCP from a different region?

Because of what Lighthouse does with the network it measured on: it throws most of it away.

The default throttling method is simulate. Chrome loads your page over the real connection, and Lantern — Lighthouse's simulator — then replays the request graph on a modelled one. Mobile gets 150 ms of round-trip time and 1.6 Mbps. Desktop gets 40 ms and 10 Mbps, but only under Lighthouse's desktop config preset: the desktop form factor on its own leaves the mobile link in place.

Two measurements survive the swap:

Read the first one twice. The baseline is subtracted, so a page whose hosts are all equally far away measures the same from anywhere. What survives is the spread between origins, plus your server's own thinking time.

Chrome loads the page
on the real network

Lantern reads the
request graph

Kept: each origin's
response time and
relative latency

Dropped: the measured
baseline latency

Replaced by a fixed
150 ms / 1.6 Mbps link

The FCP in your report

What a simulated FCP is made of. Your server's response time and its latency relative to the other hosts survive the swap; the connection they were measured over does not.

Three pages from our own fleet show all three cases. Each row is one audit, fanned out to Frankfurt and Washington on 2026-08-13, mobile, Lighthouse 12.8.2. Both network columns are the numbers Lantern kept:

Page FCP, fra → iad Origin round trip Origin response time
wikipedia.org 1,740 → 1,739 ms 1 → 1 ms 7 → 5 ms
liber.tax 1,715 → 2,717 ms 131 → 240 ms 17 → 239 ms
www.safes.ru 6,959 → 8,147 ms 38 → 116 ms 7 → 6 ms

Wikipedia keeps both inputs near zero from either worker, and its two FCP values land 1 ms apart across an ocean. liber.tax moves on both inputs at once. safes.ru moves on latency alone — its server answers just as fast from Washington, and it still loses 1,188 ms. That page is HTTP/1.1 and pulls from twelve origins, so its critical path pays the extra latency many times over.

So I read a regional FCP spread as a claim about the hosts your page pulls from. It says nothing about the last mile to a real visitor, because Lighthouse replaced that part. A CDNA network of edge servers that serve your content from near the visitor. is the usual fix for the first two rows. The other half of the story — the CPU — is why two Lighthouse scores disagree.

How to improve it

  1. Cut server response time first. It sits on the critical path, and it's one of the two things a simulated run keeps.
  2. Take render-blocking CSS and JavaScript off that path. Inline the styles the first screen needs, and defer the rest.
  3. Keep the request chain shallow. A stylesheet that imports another stylesheet costs a whole round trip before anything paints.
  4. Set font-display: swap, so text paints in a fallback font.
  5. Delete redirects on the entry URL. Each hop is a round trip you pay before the first byte.

What we do about it

Every Lightscore result carries fcp_ms per region, plus the raw Lighthouse JSON and HTML. The Lighthouse and Chromium versions are pinned and recorded with the run, so two of our numbers are comparable to each other. The free tool takes up to two regions per audit, mobile or desktop, and keeps a result for 24 hours.

What we can't hand you is a field FCP. Our workers are datacentre machines on a simulated connection, and Google's 1.8-second threshold describes real Chrome users at the 75th percentile. Take that number from the Chrome UX Report. Ours is for comparing builds, devices and regions under conditions we hold still.

Common questions