CORS Error in Your AI-Built App: What It Means and How to Fix It
\ \ \You built an app with Lovable, Bolt.new, Cursor, v0, or Replit. It was working. Then you connected it to an API, or deployed it, or changed the domain, and now you see something like this in the console:
\ \Access to fetch at 'https://api.example.com' from origin 'https://your-app.vercel.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
You paste that into the AI. It suggests a fix. The error stays, or it changes to a different CORS error, or it disappears but your API call silently returns nothing. You've been going back and forth for 45 minutes.
\ \Stop. Here's what's actually happening.
\ \What CORS is, in plain English
\ \Your app has two sides that talk to each other:
\- \
- The frontend — the page your users see, running in their browser. \
- The backend — a server somewhere (yours, Supabase's, Stripe's, an API you found) that handles data and logic. \
Browsers have a security rule: your frontend can only talk to servers that explicitly say \"yes, I'll accept requests from you.\" That's CORS — Cross-Origin Resource Sharing. If the server doesn't send back the right headers saying \"this origin is allowed,\" the browser blocks the response. Your code doesn't get the data. Nothing happens, or you get that red error in the console.
\ \This isn't a bug in your code. It's the browser enforcing a security policy. The fix almost always has to happen on the server side, not in your frontend.
\ \Why this keeps happening with AI-built apps
\ \AI coding tools are great at generating a frontend and a backend. They're bad at making them talk to each other correctly once they're deployed to different places. Here's why:
\ \1. Your frontend and backend are on different origins
\During development, everything runs on localhost and it works. Then you deploy the frontend to Vercel and the backend to Railway, or the frontend to Netlify and the database is on Supabase. Now they're on different domains. The browser treats them as strangers, and the server needs to explicitly allow the connection.
The AI built it to work on localhost. It didn't set up the CORS headers needed for production.
\ \2. You're calling a third-party API directly from the browser
\The AI wrote code that calls an external API (weather data, AI model, payment processor) directly from your frontend JavaScript. Some APIs don't allow this at all. They expect to be called from a server, not from someone's browser. No amount of frontend code changes will fix this — the API itself is refusing browser requests.
\ \3. The AI put your API key in the frontend
\This is the worst version. The AI needed to call an API, so it put the secret key right in the frontend code. Even if this \"works\" locally, it means anyone who visits your site can open the browser console and steal your API key. Many APIs block browser requests specifically to prevent this. You're hitting CORS because the API is protecting you from a security hole the AI created.
\ \What to try
\ \1. Figure out which server needs the fix
\Look at the CORS error message. It will say something like from origin 'https://your-app.com' trying to reach 'https://api.something.com'. The fix goes on the server that's being called (the second URL), not in your frontend (the first URL).
- \
- If it's your own backend (Express, Flask, a Supabase edge function) — you need to add CORS headers there. Tell the AI: \"Add CORS headers to the backend server that allow requests from my frontend domain.\" \
- If it's Supabase — check that your Supabase URL and anon key are correct, and that your Row Level Security policies aren't blocking the request. Supabase's API already allows browser requests if configured correctly. \
- If it's a third-party API you don't control — you can't add CORS headers to someone else's server. You need a proxy (see below). \
2. Use a proxy for third-party APIs
\If you're calling an API that doesn't allow browser requests, the solution is to not call it from the browser. Instead:
\ \- \
- Your frontend calls your own backend (same origin, no CORS issue) \
- Your backend calls the third-party API (server-to-server, no CORS issue) \
- Your backend sends the result back to your frontend \
In practice, this means setting up a serverless function (Vercel edge function, Supabase edge function, Netlify function) that acts as a middleman. Tell the AI: \"Move the API call to a server-side function and have the frontend call that function instead.\"
\ \3. Get API keys out of the frontend
\Search your frontend code for any API keys, tokens, or secrets. If they're there, they need to move to environment variables on the server. The frontend should never have direct access to secret keys — it should call your backend, and the backend uses the keys.
\ \The credit burn trap
\ \CORS is where AI coding tools waste more of your credits than almost any other error. Here's the loop:
\ \- \
- You paste the CORS error into the AI \
- The AI adds
mode: 'no-cors'to your fetch call \
- The error disappears, but now your API response is empty — the data is gone, your app is broken in a new way, and there's no error message to debug \
- You tell the AI the data isn't loading \
- The AI adds CORS headers to your frontend code (wrong place — they need to be on the server) \
- That doesn't work either \
- The AI suggests installing a CORS browser extension (only works for you, not your users) \
- Round and round \
These are the specific traps to watch for:
\ \- \
mode: 'no-cors'— This tells the browser \"don't check CORS, and also don't let me read the response.\" It silences the error by making the response useless. Your API call goes through but you can't use the result. This is almost never what you want. \
- Adding headers in the frontend —
Access-Control-Allow-Originis a response header. It goes on the server's response, not on your request. The AI often puts it in the wrong place. \
- \"Use a CORS proxy\" — The AI might suggest a public CORS proxy like
cors-anywhere. These are fine for a quick test but they're unreliable, slow, and a security risk for production. Your real solution is a server-side function you control. \
CORS errors are frustrating because the AI keeps generating changes that look like fixes but aren't. It can't actually test whether the server response headers are correct. A human engineer checks the actual network request in the browser, sees exactly which header is missing, and adds it in the right place on the server. One pass.
\ \Going in circles with CORS?
\Install MeatButton. Press it from inside ChatGPT or Claude and a real expert will look at your actual setup, find where the headers need to go, and tell you exactly what to change. First one's free.
\ Get MeatButton\