Measure Round-Trip Time Using Axios Interceptors

Measuring network round-trip time (RTT) is essential for monitoring API performance and diagnosing network latency issues in web applications. By utilizing Axios request and response interceptors, developers can attach high-resolution timestamps to outgoing requests and calculate the total elapsed time once a response or error is received. This guide provides a straightforward implementation for tracking RTT across your HTTP calls without modifying individual endpoint logic.

How Axios Interceptors Track RTT

Axios interceptors act as middleware for HTTP requests. To calculate RTT:

  1. Request Interceptor: Records a start timestamp and stores it inside the request's custom configuration object.
  2. Response Interceptor: Reads the start timestamp upon receiving the response, captures an end timestamp, and calculates the difference.
  3. Error Interceptor: Performs the same calculation for failed network requests to ensure latency metrics are not lost during outages or errors.

Using performance.now() instead of Date.now() is recommended because it provides millisecond timestamps with microsecond precision and is unaffected by system clock adjustments.

Implementation Example

The following code demonstrates how to configure an Axios instance to measure and log RTT for all outgoing requests:

import axios from 'axios';

// Create a custom Axios instance
const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
});

// Request Interceptor: Attach start time
apiClient.interceptors.request.use(
  (config) => {
    // Add custom metadata property to the config object
    config.metadata = { startTime: performance.now() };
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// Response Interceptor: Calculate duration on success
apiClient.interceptors.response.use(
  (response) => {
    if (response.config && response.config.metadata) {
      const endTime = performance.now();
      const rtt = endTime - response.config.metadata.startTime;
      
      // Attach duration to response object or dispatch to analytics
      response.duration = rtt;
      console.log(`[HTTP Success] ${response.config.method?.toUpperCase()} ${response.config.url} - RTT: ${rtt.toFixed(2)} ms`);
    }
    return response;
  },
  (error) => {
    // Response Interceptor: Calculate duration on error
    if (error.config && error.config.metadata) {
      const endTime = performance.now();
      const rtt = endTime - error.config.metadata.startTime;
      
      error.duration = rtt;
      console.error(`[HTTP Error] ${error.config.method?.toUpperCase()} ${error.config.url} - RTT: ${rtt.toFixed(2)} ms`);
    }
    return Promise.reject(error);
  }
);

export default apiClient;

Best Practices