Generated from: “Show how the product page does against our web performance budgets.”
View the Markdown
```meta
title: Product page — web performance budgets
subtitle: Field data for /products/{slug} at p75 on mobile, 28 days to 12 Sep 2026, against the budgets set in Q2.
tag: STATUS
```
The product page passes five of its seven budgets. INP is over budget at 265 ms against 200 ms, and JavaScript transferred is over at 342 KB against 300 KB. LCP sits at 2,310 ms, inside its 2,500 ms budget but with less than 200 ms of room. The two misses share one cause. The reviews widget and the size picker ship as one 118 KB bundle, and it runs on the main thread during the first tap.
```callout
tone: note
title: Assumptions
body: "Field data comes from the RUM beacon on the production product page (CrUX-compatible sampling, 2.1 M page views in the window). All values are p75 on mobile, the device class that carries 71% of product-page traffic. Budgets are the Q2 2026 numbers from the web-platform team. They are the Core Web Vitals 'good' thresholds plus our own limits for TTFB, transfer size, and the Lighthouse score. Weekly trend points are the p75 of each ISO week. Release 2026.08.24 shipped the new reviews widget on 24 Aug; we take it as the cause of the INP and JavaScript regressions. The storefront team did not confirm it yet."
```
## Budget by metric
INP and JavaScript transferred are the two misses. LCP and image bytes are within budget but near the line. One more gallery image or one more script tag turns them red. CLS, TTFB, and the Lighthouse score have room.
```perfbudget
id: product-budgets
title: Product page · p75 mobile · 28 days to 12 Sep 2026
context: "p75, mobile, RUM field data, 2.1 M page views"
metrics:
- { metric: LCP, budget: 2500, measured: 2310, unit: ms, note: "Hero image on the gallery; 190 ms of headroom" }
- { metric: INP, budget: 200, measured: 265, unit: ms, note: "First tap on the size picker; over since release 2026.08.24" }
- { metric: CLS, budget: 0.1, measured: 0.03, note: "Gallery and price block reserve their space" }
- { metric: TTFB, budget: 800, measured: 410, unit: ms, note: "Edge cache hit rate 93%" }
- { metric: JS transferred, budget: 300, measured: 342, unit: KB, note: "Reviews widget adds 118 KB compressed" }
- { metric: Image bytes, budget: 900, measured: 860, unit: KB, note: "Six gallery images, AVIF, no lazy load on slides 2-6" }
- { metric: Lighthouse perf, budget: 90, measured: 91, lowerIsBetter: false, note: "Lab run, mobile preset, 4G throttling" }
```
## INP over the last eight weeks
INP was inside budget for the five weeks before release 2026.08.24 and has not returned since. The 34 ms drop in week 36 came from deferring the analytics tag; it did not close the gap. The size picker hydrates on the first pointer event, so the first tap pays for both the widget and the hydration.
```chart
id: inp-trend
title: INP p75 by ISO week · mobile
kind: line
unit: ms
budget: 200
labels: [W30, W31, W32, W33, W34, W35, W36, W37]
series:
- { label: INP p75, accent: red, values: [176, 181, 174, 188, 279, 291, 257, 265] }
```
## How long the slow tail is
The p75 hides the tail. LCP p99 on mobile is 6.4 s and INP p99 is 1,120 ms. One visitor in a hundred waits more than a second for the size picker to respond. Desktop passes every latency budget at p99 except INP, where the same widget costs 340 ms.
```percentiles
id: vitals-tail
title: Product page latency by percentile · 28 days to 12 Sep 2026
unit: ms
scale: log
rows:
- { label: LCP mobile, p50: 1640, p90: 3120, p95: 3980, p99: 6400, max: 14200, slo: 2500 }
- { label: LCP desktop, p50: 980, p90: 1710, p95: 2050, p99: 2480, max: 9100, slo: 2500, accent: teal }
- { label: INP mobile, p50: 96, p90: 410, p95: 560, p99: 1120, max: 4300, slo: 200, accent: red }
- { label: INP desktop, p50: 48, p90: 150, p95: 210, p99: 340, max: 1900, slo: 200, accent: teal }
- { label: TTFB mobile, p50: 210, p90: 560, p95: 720, p99: 1450, max: 5200, slo: 800 }
- { label: TTFB desktop, p50: 140, p90: 380, p95: 470, p99: 890, max: 3600, slo: 800, accent: teal }
```
## What closes each gap
Each fix below has an owner and an expected p75 effect from the lab run of 10 Sep. The first two fixes together bring INP to about 170 ms and JavaScript to 262 KB, inside both budgets. The third fix protects LCP before the Q4 gallery redesign adds a video slide.
```table
id: budget-fixes
title: Fixes, owners, and expected effect at p75 mobile
columns: [Metric, Fix, Owner, Expected p75, Due]
rows:
- [{ v: INP, tone: neg }, "Load the reviews widget on scroll into view, not on page load", Storefront, "≈ 205 ms", 26 Sep 2026]
- [{ v: INP, tone: neg }, "Hydrate the size picker at idle, not on the first pointer event", Storefront, "≈ 170 ms", 3 Oct 2026]
- [{ v: JS transferred, tone: neg }, "Split the reviews widget out of the page bundle; 118 KB moves to a lazy chunk", Web platform, "262 KB", 26 Sep 2026]
- [{ v: LCP, tone: warn }, "Add fetchpriority=high to the first gallery image and lazy-load slides 2-6", Storefront, "≈ 2,050 ms", 10 Oct 2026]
- [{ v: Image bytes, tone: warn }, "Lazy-load slides 2-6; drops about 520 KB from the initial load", Storefront, "≈ 340 KB", 10 Oct 2026]
note: "Expected values come from the Lighthouse lab run with the fix applied on a branch; field p75 will differ by device mix."
```
```callout
tone: warn
title: Budget gate
body: "The CI budget check blocks a deploy only when JS transferred or image bytes exceed budget. It does not see INP, because INP is a field metric. Until the two INP fixes land, the storefront team reviews the weekly INP p75 by hand every Monday."
```