Hero Image File Size for a Good LCP: The Byte Budget
Neither web.dev's LCP guidance nor Lighthouse's audits set a maximum file size for an LCP image. Working backwards from Lighthouse's mobile throttling and the 2.5-second target, a hero on an already-open same-origin connection can deliver about 160 to 180 KiB inside its 1-second load slice; one fetched from a new origin, about 43 KiB. Both are derived arithmetic, not Google rules.
Those two numbers carry a lot of conditions, and the conditions matter more than the headline. The Web Almanac 2025 Performance chapter reports an image as the LCP element on 76.0% of mobile pages and 85.3% of desktop pages, so for most pages the hero file is the thing the 2.5-second clock is waiting for. Yet the same chapter finds only 62% of mobile websites with a good LCP, against 74% on desktop, and the Almanac's Page Weight chapter shows even the lightest mobile home pages landing just above the threshold. Bytes are one input. When the image request starts, which connection carries it, and how long the HTML took to arrive decide how many of those bytes you can afford.
File sizes in this guide are in KiB (1,024 bytes), the unit Lighthouse reports. The budget below is a ceiling to design under, not a target to aim for: a hero that fits has not earned a good LCP, it has only stopped being the reason for a bad one.
What the sources set, and what they leave open
Google's Core Web Vitals thresholds for Largest Contentful Paint are 2,500 ms or less for "good" and more than 4,000 ms for "poor", both measured at the 75th percentile of page loads. A page or origin passes when at least 75% of visits are at or under 2.5 seconds. The web.dev article on how the thresholds were defined explains where the numbers came from: in April 2020, 42% of phone origins and 51% of desktop origins in CrUX already met a 2.5-second target, and the team judged 2.5 seconds to be consistently achievable at the 75th percentile for top-performing sites. The 4-second poor line was chosen because it classified about 26% of phone origins as poor, inside the 10 to 30% range the team wanted.
Time, then, is what the LCP threshold regulates, and file size does not appear in it. Five published numbers are close enough to size to be mistaken for a rule, and none is one.
| Source | Number | What it actually is | A cap on an LCP image? |
|---|---|---|---|
| web.dev, Largest Contentful Paint | 2.5 s good, over 4.0 s poor, at p75 | A time threshold for the whole load | No |
| web.dev, Optimize LCP | TTFB about 40%, load delay under 10%, load duration about 40%, render delay under 10% | Guideline shares of the LCP time | No, and the page warns against turning them into absolute numbers |
| Lighthouse, LCP scoring (mobile) | 2,500 ms at the p10 control point, 4,000 ms at the median control point | Where the score curve reads 90 and 50 | No |
| Lighthouse, total-byte-weight | 2,667 KiB p10 and 4,000 KiB median control points | A scoring curve for the entire page transfer | No, whole page |
| Lighthouse, image-delivery insight | 1/6 byte per pixel (2/12), savings under 4,096 bytes ignored | Flags an image when it is well above a modern-format estimate | No, it reports savings and sets no limit |
The last row is the nearest thing to an official per-image number. The insight compares each image's bytes with the pixels in the file and, when bytes per pixel exceed one sixth of a byte, reports the difference as potential savings. The code comments build that figure from 2 bytes per pixel for an uncompressed 4:2:2 bitmap divided by an assumed 12:1 AVIF compression ratio, which they call pessimistic. It is a diagnostic, and Lighthouse's scoring documentation says that in general only metrics contribute to the Performance score, not the results of opportunities or diagnostics. It applies to every image on the page, not only the LCP one. It is a useful cross-check later in this guide and not a budget.
The warning on web.dev's own optimization page is the reason this guide calls its numbers derived. After giving the four-part breakdown, the page says: "Given the 2.5 second target for LCP, it may be tempting to try to convert these percentages into absolute numbers, but that is not recommended. These subparts are only meaningful relative to each other, so it's best to always measure them that way." (web.dev, Optimize Largest Contentful Paint, last updated March 31, 2025.) A byte budget built from those percentages does exactly what the page advises against.
There is a reason to do it anyway, with the warning kept in view. A designer handed a full-width hero needs an export setting before any field data exists, and "as small as possible" is not a setting. The same page also says: "Note that these time breakdowns are guidelines, not strict rules. If the LCP times on your pages are consistently within 2.5 seconds, then it doesn't really matter what the relative proportions are. But if you're spending a lot of unnecessary time in either of the "delay" portions, then it will be very difficult to constantly hit the 2.5 second target." So if your field LCP is already good, the proportions are irrelevant and the budget below is moot. If it is not, the ceiling helps you tell a hero that cannot fit from one that fits and is being delayed by something else. That second case is the common one, and a later section returns to it.
The page also contains a sentence that should temper everything in this guide: "Our research shows that the load duration portion of LCP tends not to be a significant bottleneck for most sites. Whenever possible, consult your site's real-user data for help deciding which LCP subpart to focus your efforts on."
From 2.5 seconds to bytes
The conversion has four inputs: the LCP target, the share of it available to the image download, the network the download happens on, and how that network behaves in the first second.
The target and its slices
Applying web.dev's shares to the two thresholds gives these slices. The delay rows are ceilings ("under 10%"), so they are the most the guideline tolerates.
| LCP target | TTFB (about 40%) | Resource load delay (under 10%) | Resource load duration (about 40%) | Element render delay (under 10%) |
|---|---|---|---|---|
| 2,500 ms (good line) | 1,000 ms | 250 ms | 1,000 ms | 250 ms |
| 4,000 ms (poor line) | 1,600 ms | 400 ms | 1,600 ms | 400 ms |
Load duration is the slice that carries the hero's bytes: from the moment the browser starts the image request until the last byte lands. The four subparts have no gaps and no overlap, according to the same article, and add up to the whole LCP. The 4,000 ms row is not a goal. It is the line at which a page becomes "poor", and Lighthouse's mobile score curve puts 4,000 ms at a score of 50.
The network
Lighthouse's own documentation describes its mobile throttling this way: "Lighthouse applies network throttling to emulate the ~85th percentile mobile connection speed even when run on much faster fiber connections." The preset is 150 ms of latency, 1.6 Mbps down, 750 Kbps up, and no packet loss. A few lines later the same page describes the same preset differently: it represents "roughly the bottom 25% of 4G connections and top 25% of 3G connections", and Lighthouse labels it "Slow 4G". The two descriptions do not match exactly, and neither says that the typical visitor sits on 1.6 Mbps. The preset is a deliberately slow lab condition. A real p75 visitor might have a faster link and also a slower phone, and the field result is the one that counts for Core Web Vitals.
Lighthouse uses simulated throttling by default, which models an alternative page load from data observed in an unthrottled one. Its documentation says this approach is fast and deterministic, and also that it has "inherent inaccuracy" in edge cases. The mobile emulation that goes with the network preset is a 412 by 823 CSS pixel screen at a device pixel ratio of 1.75 (the current constants file in the Lighthouse repository), with a 4x CPU slowdown (throttling.md). Desktop emulation is 1350 by 940 at ratio 1.
The unit chain
The preset's "1.6 Mbps" is written in the Lighthouse constants as 1.6 times 1,024 Kbps, which is 1,638.4 Kbps, and the simulator then multiplies by 1,024 to get bits per second. The chain, step by step:
- 1.6 × 1,024 = 1,638.4 Kbps
- 1,638.4 × 1,024 = 1,677,721.6 bits per second
- divided by 8 = 209,715.2 bytes per second
- divided by 1,024 = 204.8 KiB per second
A reader who takes 1.6 Mbps as exactly 1,600,000 bits per second gets 200,000 bytes per second, about 5% less. The 204.8 figure is what the simulator uses, and it is the one in every table here.
Why one second does not deliver 204.8 KiB
Dividing a second by a rate would suggest a 1-second slice carries 204.8 KiB. Lighthouse's network simulator does not behave that way, because it models TCP slow start. The model, taken from Lighthouse's TCP connection code (the same constants appear in Lighthouse 12.0.0 and in the trace_engine package 0.0.67 that Lighthouse 13.6.0 depends on):
- A connection starts with an initial congestion window of 10 segments of 1,460 bytes, 14,600 bytes in all.
- Each round trip, the window doubles, up to a cap set by the link. At 150 ms and 204.8 KiB per second, the link holds 31,457 bytes per round trip, or 21 whole segments, so the cap is 21 segments (30,660 bytes).
- On an already-open HTTP/1.1 connection the model charges one round trip (150 ms), plus any server time, before the first window arrives. On an already-open HTTP/2 or HTTP/3 connection it charges no first-byte time at all, and the window starts doubling at once, so the first window to arrive is already 20 segments. A new connection pays for a DNS lookup (modelled at two round trips, 300 ms), a TCP handshake (150 ms), a TLS handshake (150 ms, assuming TLS False Start, which the code comments name) and then the request (150 ms): 750 ms before the first byte.
- When several requests are in flight, the simulator divides the throughput among them, which lowers each one's window cap.
Run on a warm HTTP/1.1-style connection with the initial window of 10, the model delivers the image in steps. This is the staircase the conservative budget in this guide comes from.
Show the data as a table
| ms after request starts | Warm HTTP/1.1, window 10 (KiB) | New origin (KiB) | Warm HTTP/1.1, 4 in flight (KiB) |
|---|---|---|---|
| 300 | 42.8 | 0.0 | 14.3 |
| 600 | 102.7 | 0.0 | 28.5 |
| 900 | 162.5 | 42.8 | 42.8 |
| 1,200 | 222.4 | 102.7 | 57.0 |
| 1,500 | 282.3 | 162.5 | 71.3 |
| 1,800 | 342.2 | 222.4 | 85.5 |
| 2,000 | 372.1 | 252.4 | 92.7 |
| Time after the request starts | Cumulative bytes | KiB |
|---|---|---|
| 150 ms | 14,600 | 14.3 |
| 300 ms | 43,800 | 42.8 |
| 450 ms | 74,460 | 72.7 |
| 600 ms | 105,120 | 102.7 |
| 750 ms | 135,780 | 132.6 |
| 900 ms | 166,440 | 162.5 |
| 1,050 ms | 197,100 | 192.5 |
| 1,200 ms | 227,760 | 222.4 |
Two things follow. The first window is small and arrives after one round trip, so a 20 KiB image needs two windows and takes 300 ms, not the 98 ms that 20 KiB at 204.8 KiB per second suggests. And the curve reaches its slope of 30,660 bytes per 150 ms only after the third window, so short transfers run well below line rate. By the 1,000 ms mark the model has delivered 162.5 KiB (the last complete window lands at 900 ms), against the 204.8 KiB a pure rate calculation gives. The difference, about 42 KiB, is what latency and slow start cost.
The model treats a warm HTTP/2 or HTTP/3 connection differently. With no first-byte step, the first window to arrive is 20 segments (29,200 bytes) at 150 ms, then 59,860 bytes at 300 ms, and by 900 ms the total is 182,500 bytes, or 178.2 KiB. That path is 15.7 KiB ahead of the HTTP/1.1 path at the 1,000 ms mark and 26.6 KiB behind the ideal pipe. The code marks this timing as difficult to model for warm multiplexed connections, so treat the two warm paths as the two ends of a range.
The ceiling, by connection state
The staircase depends on what the connection looked like when the hero's request went out. Each column below is the same model with a different starting state, giving the most KiB that finish inside the allowance in the first column. The 1,000 ms row is the web.dev share for a 2.5-second LCP. The 1,600 ms row is the equivalent share if the page is allowed to reach the poor line.
| Load-duration allowance | Ideal pipe, no latency | Warm HTTP/1.1, window 10 | Warm HTTP/2 or 3, window 10 | Warm, window open (21) | New origin (DNS, TCP, TLS) | Warm HTTP/1.1, 2 requests in flight | Warm HTTP/1.1, 4 requests in flight |
|---|---|---|---|---|---|---|---|
| 1,000 ms (40% of 2.5 s) | 204.8 | 162.5 | 178.2 | 179.6 | 42.8 | 85.5 | 42.8 |
| 1,250 ms (after a 750 ms TTFB and 250 ms each of load and render delay) | 256.0 | 222.4 | 238.1 | 239.5 | 102.7 | 114.1 | 57.0 |
| 1,750 ms (after a 750 ms TTFB, no other delay) | 358.4 | 312.2 | 327.9 | 329.4 | 192.5 | 156.8 | 78.4 |
| 1,600 ms (40% of 4.0 s) | 327.7 | 282.3 | 298.0 | 299.4 | 162.5 | 142.6 | 71.3 |
All values are KiB. The headline figures in this guide come from the first row: 162.5 KiB on a same-origin HTTP/1.1 path that has barely been used (window 10), 178.2 KiB on the HTTP/2 or 3 path, up to 179.6 KiB when earlier downloads have already opened the window, and 42.8 KiB when the hero comes from a host the browser has not yet connected to. The tables after this one use the conservative 162.5 KiB as "the ceiling" for a same-origin hero; add about 15 KiB if your site serves HTTP/2 or 3 and the model is right about that path.
The new-origin penalty
The 42.8 KiB cell is the one most designers will not expect. A hero served from a separate image host, with no earlier request to that host, spends 750 ms of its 1,000 ms setting up the connection. Only two windows arrive before the allowance runs out, and that is 42.8 KiB. The same file from the page's own origin gets between 162.5 and 178.2.
How much of the web is exposed to this? The Web Almanac 2025 chapter measured where LCP images come from: on mobile, 44% of pages serve the LCP image from the same host as the document and 16% from a different host, with the rest classed as other content (on desktop the same-host and cross-host figures are 51% and 18%). About one mobile page in six hands its hero to a second host, and the chapter notes those pages may be paying a connection cost unless a preconnect hint covers it.
Where the setup time lands depends on a header. The web-vitals library, which implements the LCP subpart attribution, measures the start of the LCP resource from its request start if the server sends a Timing-Allow-Origin header, and otherwise from its fetch start, which includes connection setup. Without that header on the image host, the handshakes count as load duration; with it, they count as load delay. Either way they are inside the 2.5 seconds.
TTFB moves the whole table
The 1,000 ms row assumes the HTML arrives in 1,000 ms or less. The model's own floor for a cold document request is 750 ms: DNS 300, TCP 150, TLS 150, request and response 150, with no server think time. That is 30% of 2,500 ms before the server has done anything, which leaves 250 ms of the 40% TTFB share for the server and any redirects.
The Web Almanac 2025 reports TTFB under 0.8 seconds for 44% of mobile websites and 55% of desktop ones, with 17% of mobile websites over 1.8 seconds. For a slow origin, the image budget shrinks fast. The next table holds LCP at 2.5 seconds with load delay and render delay at zero, which is the best case, and shows what is left for the hero on a warm connection.
| TTFB | Time left for the image | Warm HTTP/1.1, window 10 | Warm, window open (21) |
|---|---|---|---|
| 400 ms | 2,100 ms | 402.1 KiB | 419.2 KiB |
| 800 ms | 1,700 ms | 312.2 KiB | 329.4 KiB |
| 1,000 ms | 1,500 ms | 282.3 KiB | 299.4 KiB |
| 1,400 ms | 1,100 ms | 192.5 KiB | 209.6 KiB |
| 1,800 ms | 700 ms | 102.7 KiB | 119.8 KiB |
| 2,200 ms | 300 ms | 42.8 KiB | 59.9 KiB |
A page with a 1,800 ms TTFB can still reach a 2.5-second LCP, but only if the hero is under about 100 KiB and nothing else delays it. That is the scenario where shrinking the image pays off most, and also the scenario where fixing the server pays off more.
Pixels before bytes
A byte ceiling means little until you know how many pixels it must cover, and the pixel count is where many oversized heroes start.
Lighthouse's mobile run renders at 412 CSS pixels wide with a pixel ratio of 1.75, so a full-width image needs 412 × 1.75 = 721 pixels across to be sharp on that device. Its desktop run is 1,350 CSS pixels at ratio 1, so a full-width hero needs 1,350. Real phones vary: ratios of 2 and 3 are common, and a 412-pixel slot at ratio 3 wants 1,236 pixels. The srcset mechanics that choose among candidates are covered in the responsive images guide, and the DPI and PPI resolution guide covers why more pixels do not make a screen image sharper once the slot is filled. This guide only needs the widths as inputs.
Two rules in web.dev's LCP article change which pixels count. For an image resized from its intrinsic size, the size reported for LCP "is either the visible size or the intrinsic size, whichever is smaller". Shipping a file bigger than the slot adds bytes and does not make the element larger for LCP purposes; shipping one smaller than the slot makes the candidate smaller, and a headline may then become the LCP element. And Chromium-based browsers exclude some elements as "non-contentful": invisible ones, "elements that cover the full viewport, that are likely considered as background rather than content", and "placeholder images or other images with a low entropy". A hero that exactly fills the viewport, or a very flat graphic, may not be the LCP candidate at all, which moves the question to whatever else is.
Dividing the 162.5 KiB ceiling by the pixels of a 16:9 hero at each width shows the compression the budget demands. Lighthouse's image-delivery insight threshold, one sixth of a byte per pixel, is shown alongside as the point below which the insight reports no format savings.
| File size (16:9) | Pixels | Ceiling of 162.5 KiB, bytes per pixel | Same, bits per pixel | Insight threshold, KiB | Ceiling for a new origin (42.8 KiB), bytes per pixel |
|---|---|---|---|---|---|
| 480 × 270 | 129,600 | 1.284 | 10.27 | 21.1 | 0.338 |
| 721 × 406 | 292,726 | 0.569 | 4.55 | 47.6 | 0.150 |
| 1,080 × 608 | 656,640 | 0.253 | 2.03 | 106.9 | 0.067 |
| 1,350 × 759 | 1,024,650 | 0.162 | 1.30 | 166.8 | 0.043 |
| 1,920 × 1,080 | 2,073,600 | 0.080 | 0.64 | 337.5 | 0.021 |
| 2,560 × 1,440 | 3,686,400 | 0.045 | 0.36 | 600.0 | 0.012 |
At 721 pixels wide, the transfer ceiling allows 0.569 bytes per pixel, about 3.4 times what Lighthouse's own flag allows, so a same-origin mobile hero rarely has a size problem if it is served at 721 pixels. At 1,350 the two nearly coincide, and the widest 16:9 image at which the transfer ceiling and Lighthouse's flag agree is about 1,332 pixels wide. Beyond that, the transfer budget is stricter than the insight threshold. At 1,920 pixels a hero must come in below 0.08 bytes per pixel, under half of Lighthouse's flag, to make the 1,000 ms slice. Nothing in the insight will warn you before the LCP does.
The practical reading is that the size problem is a wide-screen problem. A phone served a 721-pixel file has plenty of room; a desktop served 1,920 or 2,560 pixels at 2.5 seconds does not, unless the picture is unusually simple.
Measured: three photographs at six widths and three formats
A ceiling in KiB is only useful beside real file sizes. Three photographs that Wikimedia Commons labels CC0 (the CC0 1.0 legal code is a dedication that lets others reuse a work for any purpose, including commercial ones) were cropped to 16:9, scaled to each width and encoded to JPEG, WebP and AVIF at two quality tiers. They were chosen for their spread of detail: a snack on a plain white background (low detail), a mountain lake with forest (medium), and a Havana street with painted facades, cars and people (high).
Encoder settings, so the numbers can be reproduced: sharp 0.34.5 on libvips 8.17.3; JPEG through mozjpeg, WebP through libwebp 1.6.0 with effort 4, AVIF through libaom 3.13.1 with effort 4. The balanced tier uses JPEG quality 75, WebP 75 and AVIF 50; the high tier uses JPEG 85, WebP 82 and AVIF 60. Quality numbers do not mean the same thing across formats, so the table compares bytes at plausible export settings, not bytes at equal visual quality, and no perceptual metric was computed. The sources were already JPEG files, so these are re-encodes of a lossy original.
Each cell gives the file size in KiB for the low-detail, medium-detail and high-detail photograph in that order, so you can see the spread. Balanced tier:
| Width | JPEG q75 | WebP q75 | AVIF q50 |
|---|---|---|---|
| 480 | 8.9 / 11.6 / 30.3 | 6.3 / 9.8 / 31.3 | 4.9 / 7.0 / 26.1 |
| 721 | 17.3 / 24.0 / 63.2 | 12.2 / 20.1 / 63.1 | 8.5 / 13.6 / 50.7 |
| 1,080 | 33.5 / 48.2 / 126.3 | 22.8 / 40.6 / 119.7 | 15.7 / 26.5 / 93.3 |
| 1,350 | 48.7 / 71.2 / 189.6 | 32.2 / 59.2 / 179.7 | 21.4 / 37.5 / 135.0 |
| 1,920 | 86.6 / 132.5 / 345.5 | 54.0 / 106.6 / 315.6 | 34.7 / 66.4 / 225.4 |
| 2,560 | 137.6 / 218.7 / 565.9 | 82.1 / 171.1 / 497.2 | 50.6 / 101.4 / 340.5 |
High tier:
| Width | JPEG q85 | WebP q82 | AVIF q60 |
|---|---|---|---|
| 480 | 12.3 / 16.4 / 40.4 | 8.9 / 13.4 / 38.8 | 7.8 / 10.7 / 36.3 |
| 721 | 24.1 / 34.5 / 84.5 | 17.5 / 28.1 / 79.3 | 14.3 / 22.0 / 70.6 |
| 1,080 | 47.4 / 70.3 / 169.3 | 33.6 / 57.5 / 150.0 | 27.2 / 43.9 / 130.9 |
| 1,350 | 69.0 / 104.0 / 254.9 | 47.1 / 84.4 / 225.0 | 37.0 / 62.4 / 189.7 |
| 1,920 | 123.4 / 195.0 / 464.6 | 78.5 / 149.7 / 399.3 | 59.4 / 112.2 / 317.7 |
| 2,560 | 197.4 / 324.5 / 759.9 | 119.6 / 243.1 / 625.8 | 85.4 / 173.3 / 481.9 |
Three observations fall out of those tables.
Content decides more than format. At each width the high-detail street photograph is three to four times the size of the plain-background photograph in JPEG at the balanced tier, and five to seven times in AVIF. A one-size KiB rule applied to a portfolio of heroes will be too loose for the plain ones and too tight for the busy ones, which is the case for setting the budget per image, not per template.
Format savings are real and uneven. Across the 18 photo-and-width combinations, WebP came out at 0.81 times the JPEG size on average at the balanced tier (range 0.60 to 1.03; on the street photograph at small widths it was about the same size as JPEG), and AVIF at 0.57 times (range 0.37 to 0.86). At the high tier the averages were 0.79 for WebP and 0.64 for AVIF. These ratios apply to these three photographs at these settings and will move with other content and encoders. The image formats guide covers the support and decision side of choosing between them, and the Almanac reports where adoption stands: among LCP images, JPG is 57%, PNG 26%, WebP 11%, and AVIF 0.7%.
The ceiling bites at desktop widths. Counting how many of the three photographs fit under the 162.5 KiB warm ceiling at the balanced tier:
| Width | JPEG q75 | WebP q75 | AVIF q50 |
|---|---|---|---|
| 480 | 3 of 3 | 3 of 3 | 3 of 3 |
| 721 | 3 of 3 | 3 of 3 | 3 of 3 |
| 1,080 | 3 of 3 | 3 of 3 | 3 of 3 |
| 1,350 | 2 of 3 | 2 of 3 | 3 of 3 |
| 1,920 | 2 of 3 | 2 of 3 | 2 of 3 |
| 2,560 | 1 of 3 | 1 of 3 | 2 of 3 |
At the high tier, JPEG fits only one photograph at 1,920 and none at 2,560, while AVIF at 60 fits two at 1,350 and 1,920 and one at 2,560. Against the 42.8 KiB new-origin ceiling, the picture is far worse. At the balanced tier all three photographs pass only at 480 pixels; the street photograph fails at 721 pixels in every format (50.7 KiB in AVIF, 63.1 in WebP, 63.2 in JPEG); and at 2,560 pixels nothing passes in any format.
Against the Lighthouse insight threshold of one sixth of a byte per pixel, the number of the 18 files over the line, by format: at the balanced tier, 5 for JPEG, 4 for WebP and 2 for AVIF; at the high tier, 6, 6 and 4. Every file over the line is the street photograph; the plain-background and lake files stay under it at every width, format and tier.
Six cases through the model
The next table runs six of those files through the staircase. LCP floor here means the model's cold-document TTFB of 750 ms plus the image's load duration, with zero load delay and zero render delay. It is the best the page could do, since real pages add server time, delay and render work. The two warm columns are same-origin cases on the HTTP/1.1 and HTTP/2 or 3 paths of the model; the last column puts the same file on a new image host.
| Case (16:9) | File size | Warm HTTP/1.1: load, LCP floor | Warm HTTP/2 or 3: load, LCP floor | New origin: load, LCP floor |
|---|---|---|---|---|
| Street, 1,920 wide, JPEG q75 | 345.5 KiB | 1,950 ms, 2,700 ms | 1,800 ms, 2,550 ms | 2,550 ms, 3,300 ms |
| Street, 1,920 wide, AVIF q50 | 225.4 KiB | 1,350 ms, 2,100 ms | 1,200 ms, 1,950 ms | 1,950 ms, 2,700 ms |
| Street, 721 wide, JPEG q75 | 63.2 KiB | 450 ms, 1,200 ms | 450 ms, 1,200 ms | 1,050 ms, 1,800 ms |
| Street, 721 wide, AVIF q50 | 50.7 KiB | 450 ms, 1,200 ms | 300 ms, 1,050 ms | 1,050 ms, 1,800 ms |
| Lake, 721 wide, JPEG q85 | 34.5 KiB | 300 ms, 1,050 ms | 300 ms, 1,050 ms | 900 ms, 1,650 ms |
| Lake, 2,560 wide, JPEG q75 | 218.7 KiB | 1,200 ms, 1,950 ms | 1,200 ms, 1,950 ms | 1,800 ms, 2,550 ms |
The first row is the failure the budget is meant to catch: a 1,920-pixel JPEG of a busy scene gives a floor of 2,550 to 2,700 ms on a warm connection, over the line before any other delay has been added. The same picture as AVIF at 50 floors at 1,950 to 2,100 ms, leaving 400 to 550 ms for everything else. The mobile rows show the opposite, that at 721 pixels both the busy photograph in JPEG and the plain one at high quality sit around 1,050 to 1,200 ms. File size is a desktop-width concern in this model. The last column shows the origin effect from the other side: a 218.7 KiB lake photograph that passes comfortably from the page's own origin lands at 2,550 ms from a new host.
The ladder behind these rows, in the model, for the same three connection states:
| File size | Warm HTTP/1.1 | Warm HTTP/2 or 3 | New origin |
|---|---|---|---|
| 40 KiB | 300 ms | 300 ms | 900 ms |
| 80 KiB | 600 ms | 450 ms | 1,200 ms |
| 120 KiB | 750 ms | 750 ms | 1,350 ms |
| 160 KiB | 900 ms | 900 ms | 1,500 ms |
| 200 KiB | 1,200 ms | 1,050 ms | 1,800 ms |
| 300 KiB | 1,650 ms | 1,650 ms | 2,250 ms |
| 400 KiB | 2,100 ms | 2,100 ms | 2,700 ms |
| 500 KiB | 2,700 ms | 2,550 ms | 3,300 ms |
Times are load duration, from request start to last byte. The steps are 150 ms wide because the model works in whole round trips.
What moves the milliseconds before the bytes
Trimming a file works on one subpart out of four, and the same web.dev article that supplies the percentages is blunt about what it can and cannot do. Its example: compressing an image or switching to AVIF or WebP "would reduce the resource load duration, but it wouldn't actually improve LCP because the time would just shift to the element render delay subpart", because on that page the LCP element was hidden until JavaScript finished loading and then everything was revealed at once. A smaller file that arrives earlier gains nothing if the browser cannot paint it.
That is the first of three causes that regularly cost more than bytes.
Load delay. The resource load delay subpart is the time between the first byte of HTML and the start of the image request. Web.dev's rule of thumb is that the LCP resource should start loading at the same time as the first resource the page loads, and that the browser can only do that if it can find the image in the initial HTML: an img element with src or srcset present in the markup, not one added by script, hidden behind a data-src attribute or applied as a CSS background. On priority, web.dev's wording is direct: "Never lazy-load your LCP image, as that will always lead to unnecessary resource load delay, and will have a negative impact on LCP." It recommends fetchpriority="high" on the likely LCP image and warns that more than one or two high-priority images makes the hint unhelpful. Its preload example, for an image the HTML does not reference, also carries fetchpriority="high", and the Web Almanac adds that a preload is only necessary when the resource is not quickly discoverable in the HTML document.
The Web Almanac 2025 shows how far practice sits from that advice. About 16 to 17% of pages lazy-load their LCP image, a share that has held steady since 2024. Only 17.3% of mobile pages put fetchpriority="high" on it (16.3% on desktop), and 2.1% use a preload. The chapter adds that 0.3% of pages mark the LCP image fetchpriority="low", which it suspects is accidental, because the LCP element varies with viewport and content. A page in any of those groups can be spending hundreds of milliseconds before a single image byte is requested. The responsive images guide covers the loading attributes in more detail, including why a fixed-file preload can defeat srcset.
Render delay. The time between the last image byte and the paint can swell for the reasons web.dev lists: a render-blocking stylesheet that is larger than the image and still loading, scripts in the head, an element added to the DOM by script after the image has arrived, an A/B testing library hiding the element, and long main-thread tasks. The page recommends keeping stylesheets smaller than the LCP resource so they are not the bottleneck, and says that all browsers render images on the main thread, so anything blocking it can delay the paint of a fully downloaded image. For statically generated sites, the page calls prerendering generally the better choice for performance when the architecture allows it: the image is in the first HTML and no script has to run before the first paint.
Bandwidth contention. The "2 and 4 requests in flight" columns of the budget table are the simulator's behaviour when the hero shares the link with other downloads. At four concurrent requests, the ceiling falls from 162.5 to 42.8 KiB, the same as a new origin. Web.dev lists reducing contention as one of four ways to shorten load duration and says a high fetchpriority makes the browser "do its best" to keep lower-priority resources from competing. In practice, that means a hero should not start its download alongside a font bundle, a carousel's other slides, a chat widget and a tag manager.
Page weight on its own is a weak predictor. In the Web Almanac 2025 Page Weight chapter, mobile home pages under 1 MB had a typical LCP of 2.6 seconds, pages of 1 to 2 MB 3.0 seconds, pages of 2 to 3 MB 3.2 seconds, and pages of 5 MB or more 3.8 seconds. The share of mobile home pages with a good LCP fell from 72% for the lightest to 44% for the heaviest. Weight clearly matters, but even the lightest group sat at 2.6 seconds, above the 2.5-second line, so low weight alone did not guarantee a pass. The chapter's per-image numbers tell a similar story: the median image file on mobile is 8 KB, the 75th percentile 52 KB and the 90th 186 KB, though the chapter notes those percentiles include tracking pixels. A hero at the 162.5 KiB ceiling is already near the 90th percentile of all images on the mobile web.
There is one more group to remember. On roughly one mobile page in four (23.7%), the LCP element is text, not an image. For those pages the byte budget that matters is the web font's, and the format and loading guidance is in the WOFF2 and web font formats guide and the web fonts troubleshooting guide.
Turning the ceiling into an export spec
A usable spec needs one number per candidate file, a rule for the situations in which the number changes, and a measurement afterward.
- List the slot widths. For a full-width hero, take the layout widths at each breakpoint, multiply by the device pixel ratios you intend to serve, and round to a ladder. A ladder such as 480, 721, 1,080, 1,350 and 1,920 maps to the rows above. Keep the largest candidate no wider than the widest layout needs, because a 2,560-pixel file for a 1,350-pixel slot spends bytes the LCP does not count.
- Assign each candidate a ceiling. Use 162 KiB (the conservative end of the 162 to 178 KiB same-origin range) for same-origin images on pages where the HTML is fast, and 42 KiB when the image host is separate and not preconnected. If your TTFB is slow, take the value from the TTFB table instead. Treat those numbers as the most any single candidate should weigh, not as a goal.
- Encode, then compare. If a candidate is over its ceiling, the order of fixes by effect on bytes is: crop the composition tighter (fewer pixels), reduce resolution at that breakpoint (a 1,350-pixel file has 1.56 times the pixels of a 1,080-pixel one), move to AVIF or WebP (0.57 and 0.81 of JPEG here, on average), and lower quality. Reduce the quality setting last, since it is the only step that changes what readers see.
- Put the hero first in line. Same origin; present in the initial HTML; no loading="lazy"; fetchpriority="high"; a preload only if it cannot be in the HTML. The same ceiling means nothing if those are wrong.
- Measure the subparts, not only the total. Chrome DevTools and PageSpeed Insights show the LCP breakdown. If load delay or render delay is above its 10% share, fix that before touching the file. If TTFB alone takes more than its 1,000 ms share, the hero has to shrink to keep LCP under 2.5 seconds, and the TTFB table above shows by how much.
- Check the field. The CrUX data in PageSpeed Insights and Search Console is what the pass or fail is based on. A lab run on the simulated 1.6 Mbps preset is a stress test, and a hero that passes the ceiling can still fail for a real audience on a poor network.
Three variants of the hero change the arithmetic. A hero served as SVG (a flat illustration) is usually a few KiB of text, far below these ceilings; the SVG optimization guide covers keeping it that way. A looping video background is judged by the poster image or first frame, according to web.dev's list of elements, and has its own byte problem that the web animation performance guide covers. And a text-led hero, with a small image beside a headline, may simply not have an image as its LCP element, in which case the headline's font becomes the resource to budget. The page layout choices that produce these variants are also covered in the landing page blueprint.
Field data against a lab ceiling
The arithmetic here has limits, and they are worth listing before anyone puts a number in a design system.
- It is a lab model, and a pessimistic one. The 1.6 Mbps preset, the 150 ms round trip and the 4x CPU slowdown are Lighthouse's stress conditions. Real mobile visitors on 5G or good Wi-Fi get faster delivery, and real visitors on poor connections get slower. The p75 of a site's own visitors is the number that decides pass or fail.
- It models TCP slow start with fixed constants. An initial window of 10 segments is the Lighthouse model's choice. Servers and CDNs may use different initial windows, and modern protocols behave differently from the simple model. A real deployment should be measured before the ceiling is trusted to the kilobyte.
- The HTTP/2 and HTTP/3 path is only partly ported. Lighthouse's model also credits bytes that overshoot on earlier downloads over the same multiplexed connection to later requests, and the port here leaves that out. Its code comment calls the timing of warm multiplexed connections difficult to model.
- The steps are whole round trips. The model charges a full 150 ms for a partial window, so the ceilings move in steps of about 30 KiB. A 170 KiB file and a 190 KiB file land in the same 1,050 ms step in the simulator, and the difference between 162 and 163 KiB is not meaningful.
- It ignores everything that is not the image. Redirects, server think time, render-blocking CSS and JavaScript all take time from the same 2.5 seconds. The ceiling shows the most the image alone could take under favourable conditions.
- It uses one share of the clock. The 40% allowance comes from guideline proportions that web.dev says are not strict rules. A page with fast HTML and no delays can afford a larger image; a page with a heavy stylesheet cannot.
- The photographs are three examples. They show the size of the effect of content and format. They do not predict a particular image. Content with fine texture, text or film grain compresses far worse than the street photograph.
- Source attribution. The Web Almanac 2025 chapter combines HTTP Archive crawl data with CrUX field data. The good-LCP shares (62% on phones, 74% on desktop) are per-website figures in a chapter whose text switches between "websites" and "pages", and the chapter does not name the dataset behind the 76.0% and 85.3% image-as-LCP shares. A 2026 edition does not yet exist at the expected URL.
None of that makes the budget useless. It makes it a screening tool: a candidate over its ceiling deserves a look before launch, and one under it still has to be measured.
Hero image budget questions
How big should a hero image be for a good LCP?
No official number exists. From the Lighthouse mobile preset and the 2.5-second target, a same-origin hero on an open connection can deliver about 162 to 180 KiB in a 1,000 ms load slice (162.5 KiB on the HTTP/1.1 path of the model, 178.2 KiB on the HTTP/2 or 3 path), and about 43 KiB from a new origin. Lower TTFB leaves more room and higher TTFB less. These are derived ceilings for a lab simulation and not a Google limit.
Is there an official maximum file size for an LCP image?
Not in the web.dev LCP and optimization articles, the Core Web Vitals thresholds article, and Lighthouse's LCP, total-byte-weight and image-delivery audits. The nearest are Lighthouse's whole-page byte-weight scoring curve and an image-delivery flag at one sixth of a byte per pixel, and neither is a cap on a single image.
Does a smaller hero file always improve LCP?
No. Load duration is one of four subparts, and web.dev's own example shows a smaller file that arrived earlier but did not improve LCP, because the element stayed hidden until scripts finished. Fix load delay and render delay first if they exceed about 10% each, and check whether TTFB is the larger share.
Is AVIF worth it for a hero image?
At the settings tested, AVIF files averaged 0.57 times the JPEG size at the balanced tier and 0.64 at the high tier, and at the balanced tier AVIF was the only format to fit the busy 1,350-pixel photograph under the 162.5 KiB ceiling. It still has to be under the ceiling for the width being served, and a JPEG or WebP fallback may be needed depending on the support statement in the image formats guide.
What width should the hero be for Lighthouse mobile?
Lighthouse's mobile emulation is 412 CSS pixels wide at a device pixel ratio of 1.75, so a full-width image needs about 721 pixels. Real devices with ratio 2 or 3 want more, which is the job of srcset. A desktop run is 1,350 pixels wide at ratio 1.
Why does PageSpeed Insights flag a hero that is under my budget?
The image-delivery insight uses pixels, not time. It reports potential savings when an image's bytes per pixel are over one sixth of a byte, or when the file has noticeably more pixels than are displayed, and it ignores savings under 4,096 bytes (12,288 bytes for responsive-size savings when srcset or picture is present). A hero can be under the transfer ceiling and still be flagged for being larger than its slot.
Lighthouse and web.dev documents behind the ceiling
- web.dev, Largest Contentful Paint (LCP), last updated September 4, 2025: good threshold, p75, elements considered, size rule for resized images, exclusions; checked November 3, 2026.
- web.dev, Optimize Largest Contentful Paint, last updated March 31, 2025: the four subparts, the percentage table, the warning against absolute numbers, lazy-loading and fetchpriority guidance, load-duration notes; checked November 3, 2026.
- web.dev, How the Core Web Vitals metrics thresholds were defined, last updated May 7, 2025: 2,500 ms and 4,000 ms thresholds, p75 rule, CrUX achievability tables; checked November 3, 2026.
- Lighthouse, docs/throttling.md (repository package version 13.6.0): the 150 ms, 1.6 Mbps, 750 Kbps preset, its percentile descriptions, simulated throttling and the 4x CPU slowdown; checked November 3, 2026.
- Lighthouse, core/config/constants.js on main: mobile emulation 412 by 823 at 1.75 and desktop emulation 1350 by 940 at 1; and the same file at tag v12.0.0, which holds the 1.6 × 1,024 Kbps preset constant (on main the preset lives in the Lantern constants, shipped in trace_engine); checked November 3, 2026.
- Lighthouse at tag v12.0.0 and the @paulirish/trace_engine 0.0.67 package (the version Lighthouse main pins), files Constants.js, TCPConnection.js, ConnectionPool.js, DNSCache.js, Simulator.js and NetworkAnalyzer.js: the 1.6 × 1,024 Kbps preset, the 10-segment initial window, 1,460-byte segments and window doubling, the separate warm HTTP/2 and HTTP/3 branch (protocols h2 and h3 count as multiplexed), DNS modelled at two round trips, throughput divided among in-flight requests; checked November 3, 2026.
- Lighthouse, largest-contentful-paint.js (mobile control points 2,500 and 4,000 ms), total-byte-weight.js (control points 2,667 and 4,000 KiB) and image-delivery-insight.js with trace_engine's ImageDelivery.js (one-sixth byte per pixel, 4,096 and 12,288 byte thresholds); checked November 3, 2026.
- Chrome for Developers, Lighthouse performance scoring: the median control point is a score of 50 and the good control point a score of 90; checked November 3, 2026.
- Google, web-vitals library, LCP attribution source (version 6.2.3): how load delay, load duration and render delay are computed from Resource Timing, with requestStart used when Timing-Allow-Origin is set and startTime otherwise; checked November 3, 2026.
- HTTP Archive, Web Almanac 2025, Performance, published January 15, 2026, last updated May 5, 2026: LCP content types, good-LCP shares, TTFB, same-host and cross-host LCP images, fetchpriority, preload and lazy-loading adoption, LCP image formats; checked November 3, 2026. The 2026 edition URL returned not found on the same date.
- HTTP Archive, Web Almanac 2025, Page Weight, published January 15, 2026: image bytes per page, per-image size percentiles, LCP by page-weight group; checked November 3, 2026.
- Creative Commons, CC0 1.0 Universal legal code: the terms under which the three test photographs ("Hello Panda 02", "Lake Mountain Landscape" and "Architecture Travel City Street Tourism Cuba", each carrying a CC0 label on its Wikimedia Commons file page) were reused for measurement; checked November 3, 2026.