Free tool

Performance budget calculator

How many bytes can your LCP element afford? Set a target, pick a connection, get the byte budget — modelled on TCP slow start, not naive bandwidth math.

RFC 6928 slow start Lighthouse & WebPageTest throttling presets Exports budget.json

Your situation

One PageSpeed run grounds the inputs in your reality: your real users' p75 LCP for context, and your measured TTFB prefilled — field p75 when CrUX has it, lab when it doesn't. Measured on mobile (desktop when the Cable profile is selected). ~15–30 s. Or skip it and use the tool instantly.

Lighthouse/PSI mobile throttling (1.6 Mbps, 150 ms RTT)

Time to first byte of the HTML — measure it in DevTools or your audit report. Google's “good” bar is ≤ 800 ms.

Advanced assumptions

Main-thread time to layout, paint and decode after bytes arrive (mid-range mobile).

HTML → CSS → LCP image is 3. The HTML request itself is already paid for by your TTFB; every hop after it costs one full round trip. At these settings the longest chain that still leaves time for bytes is 11.

Where your 2500 ms goes

  • Server response (TTFB) 600 ms 24% within Google's 800 ms bar
  • Discovery round trips 300 ms 12% 2 hops after the HTML × 150 ms RTT
  • Render & decode 250 ms 10% assumed, not measured
  • Left for bytes 1350 ms 54% everything the budget below is made of

Your critical-path budget

247.9 KiB total critical-path budget
1350 ms left for network transfer
11 max sequential request hops

Naive “bandwidth × time” maths would promise 263.7 KiB for the same window — 6% more than a real connection can deliver. See the two curves.

How you spend it

The total is the contract; this cut is yours. Drag a share and the unlocked rows absorb the difference, so the split always adds to 100%.

For product, article and marketing pages whose hero image is the LCP element.

  • 8% 19.8 KiB
  • 12% 29.7 KiB
  • 25% 62.0 KiB
  • 45% 111.5 KiB
  • 10% 24.8 KiB

Allocated: 100% · 247.9 KiB

Bytes are the currency here because they are the one thing you control on every connection — what a kilobyte actually costs puts a time price on each one.

Export it for Lighthouse CI

The file is stricter than the model. This calculator answers “how many bytes fit on the LCP critical path”. Lighthouse's resourceSizes caps the transfer of every observed resource of that type on the page — so 400 KiB of below-the-fold images count against the file and not against the model. A page can satisfy the budget above and still fail this file. Treat the export as the CI ceiling and the number above as the design target.

Measure a URL above and this offers that page and its route family too.

This file will govern /* — every route on the origin, including ones you never modelled here. It carries 5 resource caps, a total, and one timing budget (LCP).

Read the file before you download it (459 characters)
[
  {
    "path": "/*",
    "resourceSizes": [
      { "resourceType": "document", "budget": 19 },
      { "resourceType": "stylesheet", "budget": 29 },
      { "resourceType": "script", "budget": 61 },
      { "resourceType": "image", "budget": 111 },
      { "resourceType": "font", "budget": 24 },
      { "resourceType": "total", "budget": 244 }
    ],
    "timings": [
      { "metric": "largest-contentful-paint", "budget": 2500 }
    ]
  }
]

Lighthouse CI reads it through assert.budgetsFile — an assert option, so nothing happens until lhci assert (or lhci autorun) runs after collect. The path is relative to the directory you run lhci from:

{ "ci": { "assert": { "budgetsFile": "./budget.json" } } }

budgetsFile cannot be combined with assertions, assertMatrix or preset. A config that already has assertions keeps them and gates the budget in a second call that opts out of the config file — lhci assert --no-lighthouserc --budgetsFile=./budget.json — because lhci merges the file's assert block into every run and would refuse the pair. Or restate the budget as resource-summary:<type>:size assertions, which take bytes where this file uses kilobytes, plus largest-contentful-paint and cumulative-layout-shift maxNumericValue entries for its two timings. Then a build that busts the budget fails.

Before you spend the budget on a specific change, the fix simulator prices that change against your own page; the sample-size planner says how many runs it takes to prove it moved.

Why the budget is smaller than the pipe suggests

Bytes delivered in the first 1350 ms on Slow 4G — Lighthouse mobile default
  • Naive bandwidth × time — 263.7 KiB
  • TCP slow start — 247.9 KiB

A new connection starts at 10 segments = 14,600 bytes (RFC 6928) and doubles every round trip until it saturates the link. The gap between the two lines is the budget a naive model would hand you and the network would never deliver.

The same page on every connection

Your inputs, unchanged, on each preset. A budget is a property of the network as much as of the page.

Budget by connection preset
ConnectionTransfer windowBudgetUse this profile
Slow 4G — Lighthouse mobile default · selected 1350 ms 247.9 KiB
4G 1310 ms 906.0 KiB
3G 1050 ms 129.1 KiB
Cable / desktop 1594 ms 970.1 KiB

What each lever is worth

One change at a time, everything else held at your current inputs. Work on the page first — the biggest single number here is “promise users a slower page”, which buys budget by giving up the thing the budget is for.

One change at a time, against your current inputs
ChangeBudget becomesDifference
Change the page
Cut TTFB by 200 ms a cache or a faster origin 286.9 KiB +39.1 KiB
Remove one discovery hop preload or inline it — worth 150 ms of RTT 277.1 KiB +29.3 KiB
Add one discovery hop one more chained request costs 150 ms 218.6 KiB −29.3 KiB
Change the promise
Loosen the target by 500 ms the same page, a slower promise 345.5 KiB +97.7 KiB
Tighten the target by 500 ms the same page, a faster promise 150.2 KiB −97.7 KiB

The model (and why naive bandwidth math lies to you)

Dividing “1.6 Mbps × time” into bytes overestimates small budgets badly, because TCP doesn't start at line rate. A new connection starts with an initial congestion window of 10 segments = 14,600 bytes (RFC 6928) and doubles it every round trip until it saturates the link. On a 150 ms-RTT mobile connection that means the first ~450 ms move only ~100 KiB — no matter how fat the pipe is.

This calculator therefore computes:

  1. Time budget

    LCP target − TTFB − render allowance − ((sequential requests − 1) × RTT). Every hop after the HTML in a discovery chain (HTML → CSS → font) burns a full round trip before its first byte — the HTML's own round trip is already inside your TTFB.

  2. Bytes from time

    TCP slow start from 10 segments, doubling per RTT, capped at the bandwidth-delay product, line-rate after that.

  3. A suggested split

    Weighted toward the LCP image because on most commercial pages the LCP element is an image. The total is the contract; the split is a starting point you can re-cut above.

Deliberate simplifications

One connection (HTTP/2/3 multiplexing shares it anyway), no packet loss, no BBR, render allowance as a flat constant instead of a CPU simulation. These all make the budget slightly optimistic — treat it as an upper bound, which is exactly what a budget should be.

And if you prefill from your page: the field p75 gap you see is closed by the whole path — TTFB, redirects, the discovery chain, render on real devices — not by bytes alone. The byte budget is the piece this calculator disciplines. Treat it as necessary, not sufficient — and see when a lab model actually predicts the field for how far a number like this one carries.

Proving a change actually landed

Getting under budget is a lab result. Whether the change moved anything is a statistical question: how many Lighthouse runs prove a change covers why a single before/after pair proves nothing, and the sample-size planner turns your own variance into a run count.

Sources

Want the budget enforced against your real page?

A PageSpeedAudit report measures where your actual bytes go, which ones block your LCP, and the exact code changes that bring you under budget.

Get your audit

The other half of the loop

Watch this URL's real-user data — the day-28 verdict, emailed

Everything above is a lab model: a promise about bytes, made today. A budget is finally a promise about the field. We fetch your CrUX p75s now as the baseline, email the verdict when the 28-day window has turned over, and alert you if any vital crosses out of “good”. If your site is below CrUX's traffic threshold, we say so honestly — and tell you the moment Chrome starts publishing data.

Double opt-in: we email a confirmation link first. Baseline card · day-28 verdict · threshold alerts — your own numbers, on the instrument's clock. Stop any time with one click.