Home » How to Measure Frontend Performance in React AI Applications
React • Technology

How to Measure Frontend Performance in React AI Applications

Metrics, profiling techniques, and lessons from GeekyAnts, Anthropic, Vercel, Atlassian, and Google.

A React AI application can load quickly and still feel slow.

The prompt field may hesitate while a response streams. A long answer may freeze the interface when syntax highlighting begins. A model may return text promptly, yet the browser may struggle to display it.

These are different performance problems. Measuring only API latency or a Lighthouse score leaves important gaps.

An effective measurement strategy covers three layers: page experience, AI response delivery, and browser rendering. Together, they explain where users wait and which changes actually improve the application.

1. Measure the Page and the AI Interaction Separately

Core Web Vitals remain a useful foundation for React applications:

MetricWhat it measuresGoogle’s “good” threshold
Largest Contentful Paint, LCPLoading performance2.5 seconds or less
Interaction to Next Paint, INPInteraction responsiveness200 milliseconds or less
Cumulative Layout Shift, CLSVisual stability0.1 or less

Google recommends assessing these thresholds at the 75th percentile, with mobile and desktop considered separately. Passing requires meeting the targets for all three metrics.

However, these metrics do not describe the entire AI interaction.

An interface can acknowledge a submit action quickly, producing a good interaction measurement, while the answer takes several seconds to arrive. Conversely, a response can begin promptly while repeated rendering makes typing or scrolling uncomfortable.

The application therefore needs additional, explicitly defined measurements:

Application metricSuggested definitionProblem it helps isolate
Composer readinessNavigation until the prompt field accepts inputInitialization and hydration delays
First answer-text arrivalSubmission until the first decoded answer-text delta reaches the clientEnd-to-end response startup
First answer committedSubmission until React commits the first answer textRendering delay after arrival
Inter-chunk gapTime between decoded answer-text deltasUneven response delivery
Completion timeSubmission until the application receives its completion signalTotal generation workflow duration
Cancellation latencyCancel action until updates stop in the interfaceAbort propagation and stale updates

These are application-defined metrics, not standardized Web Vitals. Their names and boundaries should remain consistent across releases.

A status message such as “Searching documents” should also be measured separately from actual answer content.

2. Add Real User Monitoring

Real user monitoring reveals how the deployed application behaves across devices, browsers, networks, and conversation lengths.

Google’s web-vitals library provides callbacks for collecting LCP, INP, and CLS. Its documentation includes sending measurements to an analytics endpoint with navigator.sendBeacon().

A minimal browser-side example is:

import { onCLS, onINP, onLCP, type Metric } from "web-vitals";

function reportMetric(metric: Metric) {
  const body = JSON.stringify({
    id: metric.id,
    name: metric.name,
    value: metric.value,
    rating: metric.rating,
    release: "release-identifier",
  });

  navigator.sendBeacon(
    "/api/performance",
    new Blob([body], { type: "application/json" })
  );
}

// Initialize once in the browser entry point.
onCLS(reportMetric);
onINP(reportMetric);
onLCP(reportMetric);

The receiving endpoint must validate and store the events. Metric IDs can help handle updates or duplicate delivery according to the collection strategy.

Useful segmentation includes route, release, browser, device class, conversation-length bucket, and response format. A short plain-text answer and a large Markdown table should not disappear into one average.

Prompts and generated answers do not need to be included in performance telemetry.

3. Instrument the Response Lifecycle

The browser’s User Timing API supports custom performance marks and measurements. These entries can also appear in developer-tool timelines, making them useful for investigating application-specific events.

For each AI request, instrumentation should identify:

  1. Submission.
  2. First decoded answer text.
  3. First answer text committed to the interface.
  4. Completion, cancellation, or failure.

A unique request ID prevents concurrent responses from overwriting one another’s measurements. Marks should be cleared when no longer needed.

The distinction between arrival and display matters. An HTTP response chunk may contain protocol metadata, a tool event, partial encoding, or several text deltas. It is not necessarily a model token or a visible answer.

React commitment is also not an exact paint timestamp. Likewise, requestAnimationFrame() runs before a repaint, so it should not be presented as proof that the answer has already appeared on screen. Browser traces and frame screenshots provide stronger evidence when visual timing needs investigation.

Client timings should be correlated with server-side spans for retrieval, tool execution, and model generation through a shared request identifier. Durations recorded on separate machines should not be calculated by subtracting unsynchronized wall-clock timestamps.

4. Profile React Rendering During Streaming

A common streaming problem is excessive work per update.

Each new text delta may trigger Markdown parsing, code highlighting, message-list rendering, and unrelated sidebar updates. The response becomes longer while the amount of repeated work grows.

React’s <Profiler> helps identify expensive subtrees:

import { Profiler, type ProfilerOnRenderCallback } from "react";

const onRender: ProfilerOnRenderCallback = (
  id,
  phase,
  actualDuration,
  baseDuration
) => {
  // Diagnostic example: aggregate samples in a real test harness.
  console.debug({ id, phase, actualDuration, baseDuration });
};

export function ProfiledConversation() {
  return (
    <Profiler id="Conversation" onRender={onRender}>
      <Conversation />
    </Profiler>
  );
}

Here, Conversation represents the application’s own component.

actualDuration measures rendering work for the profiled subtree during an update. baseDuration estimates the cost of rendering the subtree without optimizations. Neither is a complete measurement of browser layout, painting, network latency, or user-visible completion. Profiling also adds overhead and requires a special profiling build for production-style profiling.

Measurements should compare equivalent workloads: the same response, stream cadence, conversation history, and device conditions.

React Performance Tracks can help connect component and scheduling activity with network requests and JavaScript execution on a shared browser timeline. They are available in supported development and profiling configurations.

5. Inspect Browser Work Beyond React

React rendering is only part of the frontend workload.

A component may render quickly while expensive layout, scrolling, syntax highlighting, or third-party code blocks the main thread.

Chrome’s documentation defines long tasks as tasks occupying the main thread for 50 milliseconds or longer. It also explains why individual long-task measurements can miss problematic frames made up of several shorter tasks. The Long Animation Frames API provides another diagnostic view where supported.

A useful browser recording includes:

  • Typing while an answer streams.
  • Scrolling through a long conversation.
  • Rendering tables and highlighted code.
  • Expanding citations or tool results.
  • Cancelling and immediately submitting another request.

Average frame rate alone can hide disruptive freezes. Frame gaps, long tasks, layout activity, and interaction traces should be inspected together.

6. Use Repeatable Tests and Production Evidence

A stable benchmark should replay fixed responses with controlled chunk sizes and delays.

That separates frontend regressions from changes in model speed. A separate end-to-end test can then assess the real provider, retrieval system, and tools.

Test scenarioMain measurement
Short answer, empty conversationResponse startup
Long answer, extensive historyRendering growth
Code-heavy answerHighlighting cost
Large tableParsing and layout
Typing during generationResponsiveness under load
Interrupted streamRecovery and cancellation behavior

Tests should run repeatedly under consistent CPU and network conditions. Release decisions should consider distributions and variability rather than one favorable run.

A standard Lighthouse navigation audit does not reproduce a complete interactive AI session. Total Blocking Time is useful as a laboratory diagnostic and proxy for responsiveness, while real user interaction measurements remain necessary. Google’s measurement guidance distinguishes these laboratory and field roles.

How Five Companies Approach Relevant Performance Problems

The following examples distinguish production reports, published implementation guidance, and proof-of-concept work. They do not establish a comparative ranking.

GeekyAnts: Tracking Latency Across a Multimodal Pipeline

GeekyAnts’ published real-time conversational AI proof of concept uses Next.js 13, React 18, WebRTC, and Pipecat. Its engineering article describes frame-level observability for stages such as speech recognition, LLM generation, and speech synthesis.

The transferable lesson is to measure individual stages alongside the overall experience.

For a React text application, that suggests separating retrieval, generation, transport, and rendering. The publication does not establish a company-wide Core Web Vitals monitoring practice or a production frontend benchmark.

Anthropic: Measuring Readiness and Streaming Smoothness

Anthropic’s engineering account describes optimizing specific Claude user journeys, including time until the page becomes typeable. It reports reducing that fresh-load measurement at the 75th percentile from 3.1 seconds to 0.55 seconds.

The same account describes investigating repeated subscriptions, style recalculation, code highlighting, and streaming-renderer work. Completed blocks were memoized, and tokenization work for growing code fences moved to a worker.

The lesson is that page readiness and streaming responsiveness deserve separate benchmarks. These are Anthropic-reported results for its own workloads.

Vercel: Avoiding Repeated Markdown Rendering

Vercel’s current AI SDK cookbook demonstrates Streamdown for streamed Markdown. It documents handling incomplete Markdown and memoizing blocks so unchanged content can skip re-rendering.

This is published implementation guidance rather than a benchmark across all Vercel applications. Teams can evaluate the pattern by measuring rendering duration and browser blocking time with identical streamed responses.

Atlassian: Measuring Visibility, Interactivity, and Hydration

Atlassian’s Confluence engineering article describes tracking First Contentful Paint, visual completion, interactivity, and hydration success. It reports approximately 40% improvement in First Contentful Paint after introducing React streaming server-side rendering.

This is a React page-loading example, not an LLM response benchmark. Its relevance is the measurement approach: early visibility, usable controls, and successful hydration are distinct outcomes.

Google: Standardizing Field Measurement

Google provides Core Web Vitals guidance and the open-source web-vitals library for collecting browser experience metrics. These establish a consistent baseline alongside application-specific AI timings.

This example concerns public tooling and measurement methodology, rather than an undocumented claim about Google’s internal AI interfaces.

Turn Measurements Into Release Decisions

A useful performance report should connect each symptom with its likely owner.

If answer-text arrival is slow while rendering remains smooth, investigation should focus upstream. If arrival is prompt but typing deteriorates during streaming, browser work deserves attention. If only long conversations regress, the test should examine how work grows with history.

The goal is an interface that becomes usable promptly, displays responses steadily, and remains responsive throughout the task. Measuring those outcomes separately gives React teams evidence for deciding what to improve next.