Dynamic Axios Timeouts Based on Network Type

This article explores strategies for dynamically adjusting Axios HTTP client timeout thresholds based on the user's current network connection type. By leveraging modern browser APIs like the Network Information API alongside Axios interceptors and event listeners, developers can optimize application responsiveness and prevent premature request cancellations on slow or fluctuating mobile networks.


1. Detecting Connection Speed via the Network Information API

Modern browsers provide the navigator.connection (or navigator.mozConnection / navigator.webkitConnection) interface, which exposes network details such as effectiveType (4g, 3g, 2g, slow-2g) and estimated round-trip time (rtt).

You can map these connection states to specific timeout thresholds:

const TIMEOUT_CONFIG = {
  'slow-2g': 15000,
  '2g': 10000,
  '3g': 5000,
  '4g': 2500,
  default: 5000
};

function getDynamicTimeout() {
  const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
  if (!connection || !connection.effectiveType) {
    return TIMEOUT_CONFIG.default;
  }
  return TIMEOUT_CONFIG[connection.effectiveType] || TIMEOUT_CONFIG.default;
}

2. Applying Dynamic Timeouts via Axios Request Interceptors

The most reliable approach to dynamically adjusting timeouts on a per-request basis is using an Axios request interceptor. This ensures that every outgoing request fetches the latest network state immediately before dispatch.

import axios from 'axios';

const apiClient = axios.create();

apiClient.interceptors.request.use((config) => {
  // Only override timeout if not explicitly provided in the individual request config
  if (!config.timeout) {
    config.timeout = getDynamicTimeout();
  }
  return config;
}, (error) => {
  return Promise.reject(error);
});

export default apiClient;

3. Listening for Network State Changes Globally

Rather than querying the API per request, you can listen to network change events to update the global Axios client defaults whenever the user shifts between Wi-Fi, 4G, or poorer signals.

import axios from 'axios';

const apiClient = axios.create({
  timeout: getDynamicTimeout()
});

const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;

if (connection) {
  connection.addEventListener('change', () => {
    apiClient.defaults.timeout = getDynamicTimeout();
  });
}

For more granular control, timeout values can be calculated dynamically based on real-time latency (rtt) and estimated bandwidth (downlink in Mbps):

function calculateLatencyBasedTimeout(baseTimeout = 2000) {
  const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
  
  if (!connection || !connection.rtt) {
    return baseTimeout;
  }

  // Set timeout to (3 * RTT) + base overhead, bounded between 2s and 20s
  const calculated = (connection.rtt * 3) + baseTimeout;
  return Math.min(Math.max(calculated, 2000), 20000);
}

5. Server-Side Rendering (SSR) and Fallbacks

Because navigator.connection is purely a browser-side API, ensure defensive checks are in place for Node.js or SSR environments: