Flask CORS Blocking Requests From Local Network IP
A Flask API that works fine when accessed from localhost but gets blocked by CORS when accessed from another device on the local network (like a phone testing against your dev machine’s IP) is a very common setup during mobile or multi-device development — and it’s almost always a matter of the allowed origins list not accounting for that second address.
The Problem
Your Flask app works fine when you open it in a browser on the same machine using http://localhost:5000, but when another device on your network hits it via your machine’s local IP, like http://192.168.1.42:5000, requests fail with:
Access to fetch at 'http://192.168.1.42:5000/api/data' from origin 'http://192.168.1.42:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The exact same endpoint, same code, same everything — the only difference is which address was used to reach it, and browsers treat localhost and a local network IP as two completely different origins, even when they refer to the same physical machine.
Why It Happens
CORS is enforced strictly based on the full origin (scheme + host + port), and localhost, 127.0.0.1, and a machine’s LAN IP like 192.168.1.42 are all considered entirely different origins by the browser, even though they might all reach the same server. Common causes once you understand this include:
- The Flask CORS configuration only lists
localhostas an allowed origin, since that’s what was used during initial development, without anticipating testing from a phone or another computer on the network - The local IP address changes between development sessions (common with DHCP-assigned addresses), so a hardcoded allowed origin becomes stale the next time you connect to a different network or your router assigns a new address
- The frontend app itself is also making requests using a mix of
localhostand the LAN IP inconsistently, depending on how it was launched, creating origin mismatches that aren’t obvious from the code alone
The Fix
Install and use flask-cors rather than hand-writing CORS headers, since it handles the various edge cases (preflight requests, multiple origins) more reliably:
pip install flask-cors
Configure it with an explicit list of allowed origins that includes both localhost and your local network IP, rather than just one or the other:
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins=[
"http://localhost:3000",
"http://192.168.1.42:3000",
])
Since local network IPs can change between sessions, especially on DHCP networks, a more resilient approach during development is to allow any origin from your local network range using a regex pattern, rather than hardcoding a specific address that might go stale:
CORS(app, origins=[
r"http://localhost:\d+",
r"http://192\.168\.\d+\.\d+:\d+",
])
This pattern allows any port on localhost and any device on a typical 192.168.x.x home network, which is convenient for development but should be tightened to explicit origins before anything resembling a production deployment.
If you’re testing from a physical mobile device and the frontend itself is also served from your development machine, make sure the frontend is consistently using the same type of address (the LAN IP, not localhost) when making its own API calls — otherwise the browser on the phone is comparing its own LAN-IP origin against a Flask config that still only expects localhost, even after fixing the Flask side.
Still Not Working?
If the CORS configuration looks correct but still isn’t taking effect, confirm you’re not running an old cached version of the Flask app — a development server that wasn’t restarted after changing the CORS configuration will keep serving the old headers, which looks identical to a configuration that was never actually applied. Restarting the Flask process and doing a hard refresh (clearing cached preflight responses) on the client device rules this out quickly.