Skip to main content

From field data to traces: audit web performance

An audit that segments field Core Web Vitals, reproduces a user journey and verifies where browser or server time is spent.

Testable hypotheses, a prioritised backlog and a repeatable diagnostic method.

SpeedCurve dashboard showing web performance metrics

Engagement context and deliverables

Common situations

  • Slow mobile pages
  • Regressions that are hard to explain
  • An unprioritised performance backlog

What you receive

  • Field and lab measurements
  • Browser, data and asset analysis
  • Quick wins, backlog and performance budget

Plan your engagement

When to request an audit
Users report delays, measurements vary between routes or the team is unsure which fix to choose. We start with an affected journey and the available data.
Prepare the assessment
Bring the affected URLs, a reproducible scenario, available field measurements and access to relevant traces. If collection is missing, instrumentation may be the first step.
Choose what to fix first
The backlog records the affected journey and population, evidence, estimated effort and the measurement to check after release. A sign-up or purchase flow may take priority depending on usage and observed problems.

Technical guide · Web performance

By Théo LubertUpdated on 5 min read

Tech Lead and TypeScript/Next.js developer at Byrds Consulting.

Pages that feel fast in the office can still be slow on mobile. The audit starts with the journey users report, then identifies where the browser or server spends time.

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

Isolate the affected journey and users

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.

Illustrative example: a filter feels slow on mobile. A trace shows a long task while React renders the results. The team reduces that work, replays the scenario and compares the same segment after release. If the measurement does not change, that fix does not adequately explain the delay.

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

Keep measurement context and state the limits of 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.

Shared dimensions narrow the search; only a propagated ID establishes a direct link between a navigation and a trace.
Send Web Vitals with actionable contextTypeScript
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.

  1. 01

    Validate the field signal

    Validate collection, split the data by route and isolate the affected population.
  2. 02

    Reproduce the journey

    Use a stable scenario, a credible device profile and the same build.
  3. 03

    Find where the time is going

    Combine a flame chart, React Profiler and server spans when the request is instrumented.
  4. 04

    Address one cause

    Shorten a long task, move a calculation, remove a request waterfall or prioritise a resource.
  5. 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.

Expected outcomes in this scenario

A diagnosis the team can repeat after the engagement

This scenario illustrates the method; it does not report measured client improvements. The deliverable ties each problem to a journey, a user segment, a hypothesis and a fix to verify.

Product, design and engineering can then work from the same evidence. 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.

If the measurement does not improve

Replaying the same journey on the new build tests the fix. If the expected signal does not move, revisit the hypothesis before extending the change to other pages.

Sources and documentation

  1. Web Vitals. web.dev. The official definition of Core Web Vitals and field measurement.
  2. OpenTelemetry with Next.js. Next.js Documentation. Official guidance on tracing and custom spans in Next.js.
  3. Performance measurement APIs. Node.js Documentation. Official reference for Node.js runtime measurement APIs.

Let’s check whether this format fits your context

A first 30-minute conversation lets us review your needs and agree on the next step.

Schedule the call