AI Build South Africa
Checked against MDN's own CORS documentation and browser vendor behaviour, September 2026.

Quick answer

A CORS error means your browser blocked your own frontend JavaScript from reading a response, because the server that sent it never said your site was allowed to. It's not a bug in your code; it's the browser's Same-Origin Policy working as designed. You can't fix it by changing your own frontend, and you usually can't fix it on a third-party API you don't control either. The real fix for an AI-built app: move the call into a backend function (a Supabase Edge Function on Lovable or Bolt.new, or a Base44 backend function), and have your frontend call that instead, since server-to-server calls aren't subject to CORS at all.

What the error actually means

The exact wording usually reads something like "Access to fetch at '...' from origin '...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource." Underneath the specific phrasing, one mechanism is always the cause: your browser enforces a Same-Origin Policy, and a request from your site's own origin to a different one (a different domain, protocol or port) only succeeds if the server on the other end explicitly says, via an Access-Control-Allow-Origin response header, that your origin is allowed to read the response. No matching header, no access, regardless of whether the request itself actually succeeded on the server. This is the same frontend/backend boundary this site's own guide to what a frontend and backend are covers, seen from the browser's own enforcement side.

To confirm it really is CORS, and not a network or authentication failure, open the browser console and look for the words "blocked by CORS policy". If the console shows a different message instead, such as a 401 or 403 status or a timeout with no CORS wording, it is a different problem with a different fix, even though several of these errors look alike at a glance.

Why this isn't a bug in your code

CORS (Cross-Origin Resource Sharing) exists specifically to stop a malicious site from silently reading data from another site using a visitor's own logged-in session. Seeing this error means that protection is doing its job correctly, not that something in your app is broken. It's also worth knowing the request itself often still reaches the third-party server and can still run there; CORS blocks your browser from reading the response, it doesn't necessarily stop the request from happening at all. This site's own guide to what an API is covers the request/response mechanics this protection sits on top of, if either term is unfamiliar.

Do you control the API's own server?

Yes, it's your own backend

Add the right CORS headers there:

A real, direct fix, since you control the response headers

No, it's a third-party service

Headers on your side can't fix it:

Route the call through your own backend function instead

AI Build · aibuild.co.za

The real fix for an AI-built app: route it through a backend function

Since a third-party API's CORS policy isn't yours to change, the working fix is to stop calling it directly from the browser at all. Move the request into a Supabase Edge Function if you're on Lovable or Bolt.new, or a Base44 backend function if you're on Base44, and have your frontend call your own function instead, which then makes the actual request to the third-party API server-to-server. CORS only governs browser-to-server requests, so a call made from your own backend function to the third-party API never triggers it in the first place. This is the same architectural pattern our guide to calling a third-party API safely covers for a different reason (keeping credentials off the frontend), and it's worth knowing it solves both problems with the same one move: a secret never exposed to the browser, and a request that never has to satisfy the browser's own CORS check.

One catch: your own function is a different origin from your frontend, so a browser call to it can hit the same error unless the function answers the browser's preflight request and returns CORS headers for your site. Supabase's Edge Functions documentation says that to invoke a function from the browser you need to handle CORS preflight requests, either with its withSupabase wrapper or by adding the headers yourself. That requirement comes from Supabase's documentation; on Base44, confirm how your backend function is called from the frontend before you conclude the fix didn't work.

Confirm the fix from the browser

Once your backend function is in place, check the result from the browser, not just the function's own log. Reload the page that made the original call and check that the "blocked by CORS policy" message no longer appears in the console. A successful call on the backend doesn't guarantee the frontend received a usable response.

The one thing that makes this confusing: it works in Postman but not in your browser

CORS applies only inside a browser. Postman, curl, and any server-to-server call entirely ignore it, since none of them are the browser's own JavaScript engine enforcing the Same-Origin Policy. This is exactly why a request that succeeds perfectly in Postman, giving every appearance that the API itself is fine, still fails the moment the same request runs from your app's actual frontend code. That gap isn't a sign of a flaky API; it's the expected, designed-in difference between how a browser and every other client handle a cross-origin request.

What not to do: browser extensions or a public CORS proxy

Using a browser extension that disables CORS checking, or routing your request through a public CORS-bypass proxy, makes the error disappear locally without fixing anything real. An extension only affects your own browser, doing nothing for any actual visitor to your live site. A public proxy is worse: it routes your request, and any API key or token attached to it, through a server run by someone you have no relationship with and no visibility into, the same exposure this site's own guide to why you can't put an API key in the frontend covers for a client-side secret. Both are fine for a five-minute local check that the API itself works; neither belongs anywhere near a build handling real credentials or real user data.

Other CORS variants worth recognising

A request that uses a method other than GET, HEAD or POST, a non-simple content type such as JSON, or headers outside the small CORS-safelisted set (an Authorization header counts) triggers a preflight: the browser automatically sends an OPTIONS request first, checking whether the real request is allowed before sending it. If you see the CORS error attached to an OPTIONS request rather than the one you actually meant to make, that's this preflight failing, not a separate bug. A second variant worth knowing: for a request that includes credentials (cookies or HTTP authentication), the server can't respond with a wildcard Access-Control-Allow-Origin: *, since browsers require an exact origin match instead. Separately, a wildcard in Access-Control-Allow-Headers doesn't cover the Authorization header: if your request sends one, list Authorization explicitly.

If this didn't fix it

Not affiliated with the platforms we write about

AI Build South Africa is an independent resource. We're not endorsed by, or an official partner of, PayFast, Yoco, Peach Payments, Ozow, Meta, Lovable, Base44, Bolt.new or Anthropic. We do participate in affiliate and referral programmes with some of these providers, including Base44. See our Disclaimer for the full disclosure and our Terms of Service for the wider terms.

Frequently asked questions

Why does the API call work in Postman but not in my browser?

CORS is a browser-only protection. Postman, curl and server-to-server calls aren't subject to it at all, which is exactly why a call that works perfectly from Postman can still be blocked the moment the same request runs from your app's own frontend JavaScript. This is a normal, expected difference, not a sign something else is wrong.

Can I fix a CORS error from the frontend alone?

No, not for a third-party API you don't control. The fix has to happen on the server responding to the request, since it's the server's own headers that tell the browser which origins are allowed. If that server belongs to someone else, changing your own frontend code can't make it send different headers.

Is a CORS error a security bug in my app?

The opposite, in fact: it's the browser's Same-Origin Policy doing exactly what it's designed to do, stopping your page's JavaScript from reading a response it wasn't explicitly authorised to read. Seeing this error means a real security mechanism is working, not that your app has a hole in it.

What if the third-party API doesn't support CORS at all?

Many APIs, especially ones meant to be called server-side, simply never send CORS headers, since they were never designed to be called directly from a browser in the first place. Routing the call through your own backend function sidesteps this entirely, since server-to-server calls aren't subject to CORS.

Why do I sometimes see two requests for one API call?

For certain request types, the browser automatically sends a preflight OPTIONS request first, checking whether the actual request is allowed before sending it. If that preflight itself gets blocked, you'll see the CORS error attached to the OPTIONS request rather than the request you actually meant to make, which can look confusing until you know to expect it.

Should I use a public CORS proxy to fix this quickly?

Not for anything real. A public proxy routes your request, and potentially any API key or token attached to it, through a third party you don't control and have no relationship with. It's fine for a five-minute local experiment, never for a build handling real credentials or real user data.

Related reading