Troubleshooting

CORS error on your Replit deployment? How to fix it

Short answer

  • If the frontend and API are the same Replit app, call /api/... with relative URLs and CORS disappears.
  • If they are separate, allow your exact frontend origins. With cookies, you cannot use a * origin.
  • A CORS error can hide a crash: a 500 or 502 response often has no CORS headers.

The browser console says has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present, and only on the published app. CORS is the browser protecting users: it blocks a page on one origin from reading responses from another origin unless that server allows it. Replit's help center gives the first fix: if frontend and backend are part of the same app, use relative URLs.

Symptoms

  • blocked by CORS policy in the browser console on the live app.
  • Requests work in Postman or curl but fail in the browser.
  • The preflight OPTIONS request fails.
  • The value of the 'Access-Control-Allow-Origin' header must not be the wildcard '*' when the request's credentials mode is 'include'.

Likely causes

  1. The frontend calls a hard-coded dev URL (replit.dev, localhost) instead of its own domain.
  2. The API allowlist contains the dev origin but not the production or custom domain.
  3. Cookies are sent (credentials: "include") while the server answers with *.
  4. The server does not answer OPTIONS preflight requests.
  5. The API crashed and the error response has no CORS headers.

Step-by-step fix

1. Check if it is really CORS

In DevTools → Network, click the failing request. If its status is 500 or 502, fix the server error first (see 502 and 500 errors on Replit). If the request went to a URL you did not expect, it is a URL problem.

2. Same app: use relative URLs

Replace absolute API URLs in the frontend with paths. The request then stays on the same origin and needs no CORS at all.

// before
fetch("https://abc123.replit.dev/api/orders")
// after
fetch("/api/orders", { credentials: "same-origin" })

3. Separate apps: allow exact origins

import cors from "cors";
const allowed = (process.env.CORS_ORIGINS || "").split(",");   // https://app.example.com,https://example.com
app.use(cors({
  origin: (origin, cb) => cb(null, !origin || allowed.includes(origin)),
  credentials: true,
}));

Keep the list in a deployment secret so dev and production can differ.

4. Do not open CORS to everyone with cookies

Reflecting any origin while allowing credentials lets any website call your API as your logged-in users. Only allow the domains you own.

5. Republish and clear caches

Publish again, then test in a private window. A cached old bundle may still call the old URL.

Copy-paste prompt for Replit Agent

Open a new Agent chat (a fresh chat keeps old attempts out of its context) and paste this:

My published Replit app shows "blocked by CORS policy" errors. Here is the console error and the failing request URL: [paste].
Please:
1. Find every absolute API URL in the frontend (replit.dev, localhost, http://) and replace same-app calls with relative /api paths.
2. If a separate API origin is really needed, configure cors with an allowlist read from a CORS_ORIGINS environment variable and credentials: true. Never use origin "*" or reflect any origin with credentials.
3. Make sure OPTIONS preflight requests are answered.
4. Check whether the failing endpoint actually returns a 500 and fix that first if so.

How to verify the fix

  • The console on the live URL has no CORS errors during a full user journey.
  • curl -I -H "Origin: https://evil.example" https://your-app/api/me does not return that origin in Access-Control-Allow-Origin.
  • Login and logged-in API calls still work.

Open CORS with credentials is one of the issues the free audit checks on live Replit apps, along with the rest of the security checklist.

FAQ

Why do I get a CORS error only after deploying on Replit?

The frontend usually still calls the dev URL, or the API's allowlist only contains the dev origin. Use relative URLs when frontend and API are the same app.

Is app.use(cors()) safe?

Without credentials it allows any site to read your public API responses. With credentials and a reflected origin it is dangerous. Allow only your own domains.

Can a server error look like a CORS error?

Yes. When the server crashes, the error response often lacks CORS headers, so the browser reports CORS. Check the status code in the Network tab first.

Get a free audit