Skip to content

Appendix A — The audit checklist

A printable, 120‑point audit. Work top to bottom; each item links to the lesson that explains it. Score yourself: ✅ done · ⚠️ partial · ❌ missing · N/A.

How to use it: run this once as a baseline, then quarterly. The delta between runs is your program's progress. Anything still ❌ after two quarters either doesn't matter for you (mark N/A and move on) or needs an owner.


1. Measurement (do this first — 12 points)

Check Lesson
☐ Field RUM collecting LCP, INP, CLS, FCP, TTFB 9.1
☐ Using the attribution build, not the basic one 9.1
☐ Paths normalized before sending (no unbounded cardinality) 9.1
☐ Dimensions: pageType, deviceClass, connection, releaseSha, experiments, isReturning, country 9.1
☐ Collection endpoint is same‑origin, async, always 204 9.1
☐ Commerce custom metrics (atc_ready, interaction latencies) 1.3
☐ Soft navigation timing approximated 9.1
☐ Dashboards: executive, engineering, diagnostic, business 9.1
☐ Alerts on change, not static thresholds 9.1
☐ Alert on RUM data volume dropping 9.1
☐ Baseline lab numbers committed and dated 1.4
☐ Conversion elasticity measured on your own data 1.1

2. Images (14 points)

Check Lesson
☐ LCP image present in the initial HTML (curl verified) 2.1
☐ sizes matches real rendered width at every breakpoint 2.1
☐ Exactly one priority image per page, on the true LCP element 2.1
☐ Everything below the fold is lazy 2.1
☐ AVIF with WebP fallback enabled 2.1
☐ Quality tuned (AVIF q65–75), verified on a phone 2.1
☐ Every image has reserved space (aspect-ratio or width/height) 6.3
☐ deviceSizes/imageSizes limited to what layouts request 2.1
☐ Transform width allowlist enforced at the CDN 2.1
☐ Image CDN hit ratio > 98% 2.1
☐ Blur placeholders only where they earn their bytes 2.1
☐ SVG for icons and flat graphics, never PNG 2.1
☐ decoding="async" on grid images 5.4
☐ No image waste > 1.5× (console audit run) 2.1

3. Fonts (8 points)

Check Lesson
☐ Self‑hosted via next/font; no third‑party font origin 2.2
☐ display: swap everywhere 2.2
☐ Metric‑compatible fallbacks (adjustFontFallback / size-adjust) 2.2
☐ WOFF2 only 2.2
☐ Subset to needed scripts + Latin‑1 + punctuation + currency 2.2
☐ Variable fonts where 3+ weights are used 2.2
☐ At most 1–2 preloaded fonts, with crossorigin 2.2
☐ No icon fonts 2.2

4. Third parties (10 points)

Check Lesson
☐ Complete inventory with bytes, ms, and a named owner per tag 2.3
☐ Cost measured via WebPageTest request blocking 2.3
☐ Long Animation Frame monitoring in production 2.3
☐ Only genuinely required scripts use beforeInteractive 2.3
☐ Chat, video, maps, reviews, social behind facades 2.3
☐ Marketing tags on lazyOnload or idle 2.3
☐ Consent banner overlays (no CLS), bundle < 30 KB 2.3
☐ Zero non‑essential third parties on checkout 7.4
☐ Server‑side event collection for analytics 2.3
☐ CI blocks new third‑party origins 2.3

5. Delivery & caching (12 points)

Check Lesson
☐ Brotli/Zstd on all text assets, verified with curl 2.4
☐ JSON, SVG, and RSC payloads compressed 2.4
☐ Compression happens in exactly one place 2.4
☐ immutable on all hashed assets 2.4
☐ s-maxage + stale-while-revalidate on cacheable HTML 2.4
☐ no-store only on cart/checkout/account 8.3
☐ Tracking params stripped from the cache key 2.4
☐ Device bucketing (2–3 buckets); no raw UA in the key 2.4
☐ Surrogate keys with soft purge as the default 7.2
☐ HTTP/3 enabled and verified 2.4
☐ ≤ 3 preconnects, correct crossOrigin 2.4
☐ CDN HTML hit ratio > 90% on cacheable routes 7.2

6. Rendering architecture (14 points)

Check Lesson
☐ Every route's intended mode documented and gated in CI 3.1
☐ No cookies()/headers() in the root or shared layouts 3.1
☐ generateStaticParams covers the traffic knee, not everything 3.5
☐ dynamicParams: true for the long tail 3.5
☐ Event‑driven revalidation, signed, batched, rate‑limited 3.5
☐ CDN purge alongside revalidateTag 7.2
☐ Jittered TTLs; stampede protection tested under load 3.5
☐ Shared cache handler if self‑hosting multi‑instance 3.4
☐ Every fetch has explicit cache intent 3.4
☐ Tag hierarchy designed; no single global tag 3.4
☐ Nothing session‑derived is cached, enforced by a CI test 3.6
☐ PPR: dynamic reads inside Suspense boundaries; 2–4 holes 3.6
☐ Middleware matcher is an allowlist; p95 ≤ 5 ms; no network calls 3.7
☐ Streaming verified end‑to‑end in production (curl -N) 3.3

7. JavaScript payload (12 points)

Check Lesson
☐ First Load JS per route within budget 1.5
☐ Shared chunk understood line by line 4.1
☐ Root layout has no 'use client'; providers scoped by route group 3.2
☐ children pass‑through used for client shells 3.2
☐ 'use client' only on interactive leaves 3.2
☐ RSC payload measured and budgeted per route 3.2
☐ Boundary mappers; no whole entities crossing 3.2
☐ No barrel imports from large packages 4.3
☐ optimizePackageImports configured 4.3
☐ Dates/prices via cached Intl formatters 4.3
☐ browserslist matches your real user base 4.1
☐ server-only on every data‑access module 3.2

8. React runtime (12 points)

Check Lesson
☐ Profiling done on production builds at 4–6× throttling 5.1
☐ Commit count per interaction is 1–2 5.1
☐ No derived state computed in effects 5.1
☐ No monolithic context; split by change frequency 5.3
☐ All context values memoized; actions permanently stable 5.2
☐ High‑frequency shared state in an external store with selectors 5.3
☐ Filters/sort/pagination in the URL 5.3
☐ startTransition on every expensive update 5.5
☐ Urgent feedback outside every transition 5.5
☐ Long loops chunked with scheduler.yield 5.5
☐ Every memoization measured before/after 5.2
☐ Zero hydration mismatches; production reporting wired 4.4

9. Data & backend (10 points)

Check Lesson
☐ Server-Timing emitted and forwarded to RUM 6.4
☐ No sequential awaits for independent data 7.1
☐ Preload pattern across layout/page boundaries 7.1
☐ cache() on every data accessor; DataLoaders per request 7.1
☐ Every external call has a timeout, with a documented budget 7.1
☐ Circuit breakers on flaky services 7.1
☐ BFF responses shaped to what the UI renders 7.1
☐ No N+1 patterns; batch endpoints where counts scale 7.1
☐ Keep‑alive configured for backend HTTP 8.6
☐ Cart repriced server‑side on every view 7.4

10. Search & lists (8 points)

Check Lesson
☐ Search shell streams; TTFB independent of query latency 7.3
☐ Only displayed facets requested; values capped 7.3
☐ Filter keys normalized (allowlisted, deduped, sorted) 7.3
☐ Typeahead: debounced network, deferred render, aborted requests, ≤ 8 items 7.3
☐ Suggestion endpoint edge‑cached 7.3
☐ content-visibility on off‑screen list items 2.5
☐ Infinite scroll capped, URL‑synced, with a paginated fallback 5.4
☐ Scroll restoration works on back navigation 5.4

11. Advanced (10 points)

Check Lesson
☐ bfcache working (restore rate measured in the field) 8.3
☐ Zero unload listeners; beforeunload conditional 8.3
☐ <Link prefetch> audited on dense grids 8.1
☐ Speculation Rules at moderate, cart/checkout excluded 8.1
☐ Analytics prerender‑aware 8.1
☐ Every listener/timer/observer cleaned up 8.4
☐ All client caches bounded 8.4
☐ Long‑session memory and INP tests in CI 8.4
☐ No anti‑flicker snippet; variants assigned at the edge 8.5
☐ Flag registry with owners and expiry, enforced in CI 8.5

12. Operating (10 points)

Check Lesson
☐ Budgets derived from a UX target, per page type 1.5
☐ Deterministic gates block; noisy ones warn 9.2
☐ Bundle budgets gzipped, compared against the base branch 9.2
☐ Route rendering mode gated 9.2
☐ Client Component count ratcheted 9.2
☐ PR comment explains failures and suggests fixes 9.2
☐ Synthetics on vitals, cache health, and a purchase journey 9.2
☐ Cross‑system change log (deploys, tags, CDN, CMS, vendors) 9.3
☐ Named owner per page type; one‑page scorecard 9.4
☐ Written budget exception process with expiry dates 1.5

13. Mobile (8 points)

Check Lesson
☐ Tested on a real mid‑tier Android in the last quarter 10.6
☐ DevTools default is 4–6× CPU throttling 10.6
☐ Mobile budgets set tighter than desktop 10.6
☐ touch-action: manipulation on interactive elements 10.6
☐ Touch targets ≥ 44×44 px with spacing 10.6
☐ Viewport allows zoom 10.6
☐ Save-Data respected 10.6
☐ DOM ≤ 1,500 nodes on list pages 10.6

Scoring

Total items: 120

  0–40   🔴 Start with sections 1, 2, 3, 4 — the Tier 1 quick wins
 41–70   🟠 Foundations in place; move to sections 6 and 7 (architecture)
 71–95   🟡 Solid. Focus on 8, 9, and 11 (interaction and advanced)
 96–120  🟢 Mature. Section 12 is what keeps you here

The five items that matter most if you can only do five:

  1. Field RUM with attribution (§1)
  2. LCP image in the HTML with correct sizes (§2)
  3. bfcache working (§11)
  4. Nothing session‑derived is cached, with a CI test (§6)
  5. Bundle budgets gated in CI (§12)