Do you need a CORS proxy in React Native or Expo?
Usually not, and adding one where you don't need it costs latency and a dependency. But some parts of a React Native app do run inside a browser engine, and there CORS applies exactly as it does on the web. This post shows how to tell which case you're in.
The short version
CORS is a restriction the browser enforces on JavaScript it's running, checking response headers before handing the response back to your code. React Native's JS engine (Hermes or JSC) is not a browser: fetch() called from a native screen talks straight to the network with no CORS layer in the way. If your native fetch() call is failing, it is almost never a CORS error, no matter what the symptom looks like.
Where it doesn't apply
- Standard React Native screens:
fetch()oraxioscalled from your normal app code, running on-device via Hermes/JSC. No CORS. - Expo Go on a physical device or simulator: same JS engine, same answer. No CORS.
If a request fails here, look at: the actual HTTP status code, network permissions (Android's cleartext-traffic block on plain http://, iOS App Transport Security), or a genuine server-side error. A CORS-shaped fix won't touch any of these.
Where it does apply
- Expo Web / React Native Web:
expo start --webor any RN Web build runs your app as actual JavaScript inside an actual browser. Full CORS enforcement, identical to any other web app. - WebView-based screens:
react-native-webviewrenders a real browser engine (WKWebView / Chromium) inside your native app. JS running inside that WebView is browser JS. CORS applies.
If you came here from Capacitor rather than React Native: Capacitor apps also run in a WebView, so the same rule holds, but its native HTTP plugin (CapacitorHttp) sends requests from native code and bypasses browser CORS.
The fix in both React Native cases is the same as in any web app:
// Fails with a CORS error, only in the web / WebView target
fetch('https://api.example.com/data')
// Works
const target = encodeURIComponent('https://api.example.com/data');
fetch(`https://api.corsproxy.dev/proxy?url=${target}&key=YOUR_CORSPROXY_KEY`)
.then(r => r.json())
.then(data => console.log(data));
The practical pattern for a codebase that targets both
If you ship the same code to native and web (Expo's whole pitch), branch on platform rather than routing every request through a proxy. Native doesn't need it, and the extra hop only adds latency there:
import { Platform } from 'react-native';
async function fetchData(url) {
const needsProxy = Platform.OS === 'web';
const finalUrl = needsProxy
? `https://api.corsproxy.dev/proxy?url=${encodeURIComponent(url)}&key=YOUR_CORSPROXY_KEY`
: url;
const res = await fetch(finalUrl);
return res.json();
}
Try it
Create a free key for your web build.