Technical guide · Web performance
A Lighthouse score is a clue, not an explanation for what real users experience. Acting on it means connecting field signals to browser work and, when the instrumentation supports it, the server path.
Starting point
Fast in the office, inconsistent in the field
In this scenario, a Next.js application serves public pages and a signed-in product area. Local tests look healthy, yet support reports slow interactions on mobile and Core Web Vitals vary widely between routes.
The team has already applied the obvious optimisations. Another checklist will not reveal where time is actually being lost, so the audit starts with an observed user experience and works back to a cause the team can verify.
The brief
Give the team a shared language and a diagnostic method they can reuse.
- Segment field data by route, build, viewport class and navigation type.
- Relate a slow interaction to browser work and, when an ID is propagated, the corresponding server trace.
- Fix one demonstrated bottleneck before adding more dashboards.
Investigation
Start with one user experience, not a site-wide average
We choose an affected journey: open an item, change a filter, then render the results. Field data shows which population experiences the slowdown; a controlled test then replays the sequence with representative network and CPU constraints.
Poor INP may come from an expensive React render, a long task or a third-party script. A poor LCP may be caused by server response time, late resource discovery or image decoding. The metric narrows the investigation, but it does not identify the culprit on its own.
Affected population
Is the regression limited to one route, viewport class, region or build?
User moment
Which element becomes the LCP, and which interaction produces the observed INP?
Browser work
Is the main thread running JavaScript, rendering React, calculating layout or executing third-party code?
Server path
For an instrumented request, is time spent in Next.js, the API, the database or an external service?
The investigation ends with a testable hypothesis for a specific population and action. A targeted fix does not claim to speed up every page.
Measurement design
Preserve context without inventing correlation
A field measurement becomes actionable when it includes a normalised route, build, viewport class, navigation type, page ID and timestamps. Those dimensions identify the relevant segment without collecting unnecessary personal data.
They do not prove that a Web Vital corresponds to a particular trace span. Exact correlation requires an ID created on the server, exposed to the browser and propagated through the relevant requests. Without that mechanism, Next.js and OpenTelemetry traces can still be compared for the same route, build and time window, but the analysis must be described as a comparison rather than a one-to-one link.
Field measurement
LCP, INP and CLS with route, build, viewport and navigation context.
Browser diagnosis
Long tasks, React renders, layout and third-party scripts explain client-side work.
Server traces
Rendering, data-access and dependency spans are filtered to the same route, build and time window.
Testable hypothesis
One suspected cause, one change and the signal expected to move.
import { onCLS, onINP, onLCP, type Metric } from 'web-vitals'
let registered = false
type ViewportClass = 'mobile' | 'desktop'
function getViewportClass(): ViewportClass {
return matchMedia('(max-width: 767px)').matches
? 'mobile'
: 'desktop'
}
export function registerWebVitals(normalizedRoute: string) {
if (registered) return
registered = true
const pageId = crypto.randomUUID()
const report = (metric: Metric) => {
const payload = {
route: normalizedRoute,
build: process.env.NEXT_PUBLIC_BUILD_ID ?? 'dev',
viewport: getViewportClass(),
navigation: metric.navigationType,
pageId,
pageStartedAt: performance.timeOrigin,
reportedAt: new Date().toISOString(),
metric: {
id: metric.id,
name: metric.name,
value: metric.value,
rating: metric.rating,
},
}
const body = new Blob([JSON.stringify(payload)], {
type: 'application/json',
})
navigator.sendBeacon('/api/vitals', body)
}
onCLS(report)
onINP(report)
onLCP(report)
}Register this callback once per document load; this snippet does not report each App Router soft navigation as a separate measurement. The application must inject the build ID at deployment. A sound diagnosis depends on consistent dimensions and an honest statement of confidence.
Delivery
Five steps from signal to verified fix
The audit moves one journey at a time. Each step produces something the team can inspect or measure: a segment, trace capture, hypothesis, diff or production result.
01
Validate the field signal
Validate collection, split the data by route and isolate the affected population.02
Reproduce the journey
Use a stable scenario, a credible device profile and the same build.03
Find where the time is going
Combine a flame chart, React Profiler and server spans when the request is instrumented.04
Address one cause
Shorten a long task, move a calculation, remove a request waterfall or prioritise a resource.05
Measure after release
Compare the same segment on the new build and keep a regression check in place.
If the expected signal does not move, the hypothesis is rejected and documented. That prevents the team from repeating an appealing but ineffective optimisation.
Qualitative outcomes
Performance discussions grounded in journeys, not impressions
Product, design and engineering use the same evidence. An alert names the affected population and action; a PR states the expected signal. Support can pass along the route, build and viewport context without asking the user to open DevTools.
What the team can verify
A shared diagnostic method that remains useful after each release.
- A field regression can be tied to a route, build and user segment.
- For instrumented requests, traces separate rendering time from dependency time when those dependencies emit their own spans.
- Every material optimisation starts with a falsifiable hypothesis.
- Unused dashboards can be removed without losing the diagnostic method.
Key takeaway
Core Web Vitals describe an experience, not the line of code at fault. The audit preserves enough context to propose a cause, test it and measure the outcome.
Sources and documentation
- Web Vitals. web.dev. The official definition of Core Web Vitals and field measurement.
- OpenTelemetry with Next.js. Next.js Documentation. Official guidance on tracing and custom spans in Next.js.
- Performance measurement APIs. Node.js Documentation. Official reference for Node.js runtime measurement APIs.
