Skip to main content

Debugging Network Requests in React Native: Fetch, Axios, and DevTools

· 6 min read
Mobile Developer
Last updated on May 18, 2026

Debugging React Native network requests

Network bugs in React Native usually fall into a few categories: the request never leaves the device, the server rejects it, the response shape is different from what the app expects, or the UI keeps using stale data. The fastest way to debug them is to inspect the request, log safely, reproduce on the platform that fails, and verify the server-side trace.

Quick Answer

Start with React Native DevTools when your stack supports the Network panel. It records requests made through fetch, XMLHttpRequest, and images. Add a thin logging layer around Fetch or Axios, redact secrets, capture status codes and request IDs, cancel stale requests with AbortController, and compare device logs with backend logs. Use Android Studio, Xcode, or a proxy tool when the issue is TLS, cleartext HTTP, certificates, localhost routing, or platform networking.

For implementation patterns, pair this guide with React Native REST API integration, React Native memory leak fixes, and the current Instamobile React Native stack.


Use the Right Debugging Tool

Use this order for most API bugs:

  1. React Native DevTools Network panel for supported fetch, XMLHttpRequest, and image requests.
  2. Application logs from a single API wrapper or Axios instance.
  3. Backend logs using a request ID or correlation ID.
  4. Android Studio Logcat or Xcode Console for platform-level failures.
  5. A proxy tool such as Charles or Proxyman when you need full device traffic inspection and your security policy allows it.

Flipper can still be useful in older projects that already depend on it, but it should not be the default recommendation for modern React Native network debugging.

Log Requests Without Leaking Secrets

Never log access tokens, refresh tokens, API keys, passwords, payment payloads, or PII. A useful debug log only needs method, path, status, duration, and a request ID.

type RequestLog = {
method: string;
url: string;
status?: number;
durationMs: number;
requestId?: string;
};

function logNetworkEvent(event: RequestLog) {
if (__DEV__) {
console.log('[network]', event);
}
}

When the backend returns a request ID, surface it in error logs and support screens. It lets developers match the exact mobile request to server logs without exposing user data.


Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount 🔥

Get the Mega Bundle

Debug Fetch With Timeouts and Cancellation

React Native supports the familiar Fetch API. Build a small wrapper so every request has the same timeout, error shape, and logging behavior.

type ApiErrorBody = {
message?: string;
code?: string;
};

export class ApiError extends Error {
status: number;
body: ApiErrorBody | null;

constructor(status: number, body: ApiErrorBody | null) {
super(body?.message ?? `Request failed with status ${status}`);
this.status = status;
this.body = body;
}
}

export async function fetchJson<T>(
url: string,
options: RequestInit & { timeoutMs?: number } = {},
): Promise<T> {
const startedAt = Date.now();
const controller = new AbortController();
const timeoutId = setTimeout(
() => controller.abort(),
options.timeoutMs ?? 15_000,
);

try {
const response = await fetch(url, {
...options,
signal: controller.signal,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
...options.headers,
},
});

const requestId = response.headers.get('x-request-id') ?? undefined;
const text = await response.text();
const body = text ? JSON.parse(text) : null;

logNetworkEvent({
method: options.method ?? 'GET',
url,
status: response.status,
durationMs: Date.now() - startedAt,
requestId,
});

if (!response.ok) {
throw new ApiError(response.status, body);
}

return body as T;
} finally {
clearTimeout(timeoutId);
}
}

Use cancellation when a user leaves the screen, changes a search term, or starts a newer request that makes the old response irrelevant.

Debug Axios With One Shared Instance

Axios is still useful when a project relies on interceptors, upload progress, response transforms, or shared error handling. Keep all Axios behavior in one module.

import axios, { AxiosError } from 'axios';

export const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 15_000,
});

api.interceptors.request.use(config => {
config.headers.set?.('x-client', 'mobile');
config.metadata = { startedAt: Date.now() };
return config;
});

api.interceptors.response.use(
response => {
const startedAt = response.config.metadata?.startedAt ?? Date.now();

logNetworkEvent({
method: response.config.method?.toUpperCase() ?? 'GET',
url: response.config.url ?? '',
status: response.status,
durationMs: Date.now() - startedAt,
requestId: response.headers['x-request-id'],
});

return response;
},
(error: AxiosError) => {
const status = error.response?.status;

logNetworkEvent({
method: error.config?.method?.toUpperCase() ?? 'GET',
url: error.config?.url ?? '',
status,
durationMs: Date.now() - (error.config?.metadata?.startedAt ?? Date.now()),
requestId: error.response?.headers?.['x-request-id'],
});

return Promise.reject(error);
},
);

If TypeScript complains about metadata, define a small Axios module augmentation in your app. Keep the augmentation near the API client so it does not leak into unrelated code.

Triage Common React Native Network Failures

Use symptoms to narrow the issue:

SymptomLikely causeWhat to check
Network request failed on Android onlyTLS chain, cleartext HTTP, emulator routing, certificate issueUse HTTPS, verify full certificate chain, check Android network security config
Works on simulator but not devicelocalhost, Wi-Fi, firewall, backend bindingUse the machine LAN IP or a tunnel; verify the server accepts device traffic
401 or 403expired token, wrong audience, missing role, clock skewInspect auth headers without logging token values; compare backend auth logs
404wrong base URL, route prefix, API versionLog normalized URL and environment name
Request repeats too oftenfocus refetch, effect dependencies, retry loopAdd request IDs, inspect component lifecycle, use a server-state cache
UI shows old datastale cache or optimistic update bugInvalidate the correct query/list and update pagination state
Upload fails on one platformMIME type, file URI, permissions, multipart boundaryLog file metadata and test a small known-good file

React Native apps do not run inside a browser sandbox, so browser CORS rules are not usually the first suspect. If you see a CORS-like failure, also verify TLS, redirects, API gateway rules, and custom origin checks on the server.

Test Network Behavior Explicitly

Before shipping API-heavy changes:

  • test on iOS simulator, Android emulator, and at least one physical device;
  • test Wi-Fi, cellular, airplane mode, and slow network conditions;
  • test token expiry and refresh;
  • test empty, loading, error, and retry states;
  • test app background and foreground resume;
  • confirm that canceled requests do not update unmounted screens;
  • verify backend logs include the same request IDs seen in the app.

For release readiness, use the Instamobile publishing checklist.

Looking for a custom mobile application?

Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.

Get in Touch