Do you need a CORS proxy in React Native or Expo?
Usually not — and if you add one where you don't need it, you're adding latency and a dependency for nothing. But some parts of a React Native app really do run inside a browser engine, and there CORS is exactly as real as it is on the web. Here's how to tell which one you're dealing with.
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 at all. 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-webview, or a Capacitor/Cordova-style hybrid wrapper, renders a real browser engine (WKWebView / Chromium) inside your native app. JS running inside that WebView is browser JS. CORS applies.
The fix in both cases is identical to 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 unconditionally — native doesn't need it and the extra hop is pure 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
Get a free API key — 500 requests/day, no credit card. Works the same on Expo Web, RN Web, and any WebView.