>How to Debug CORS Errors When Testing APIs Online
Understand why you get CORS and Preflight errors when testing APIs in the browser, and learn how to bypass the Same-Origin Policy using proxies.
"CORS errors occur because browsers aggressively block Javascript from reading data from different domains. To test an API in your browser without getting blocked by missing Access-Control-Allow-Origin headers, you must route your request through a backend proxy."
✓ Last tested: June 2026 · Verified against W3C Fetch Standards
1. Field Notes: The Preflight Panic
Every frontend developer remembers their first encounter with CORS.
You write a perfect fetch() script. You verify the URL, the headers, and the JSON payload. You hit save, check the browser console, and there it is—the dreaded red text:
Access to fetch at 'https://api.thirdparty.com/v1/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Years ago, I spent an entire Friday afternoon trying to debug this exact error while integrating a third-party analytics API. I assumed my API key was wrong. I assumed my JSON was malformed. I spent hours tweaking the request payload.
The reality was much simpler: my payload was perfect. The API server was actually processing my request successfully! But because the API server didn't explicitly return an Access-Control-Allow-Origin header authorizing http://localhost:3000, Google Chrome intercepted the response and hid it from my Javascript.
Understanding CORS (Cross-Origin Resource Sharing) is the difference between blindly guessing at API configurations and confidently debugging network boundaries.
2. Why CORS Exists: The Same-Origin Policy
Before we can debug CORS, we have to understand why it exists.
Browsers enforce a strict security mechanism called the Same-Origin Policy. This rule states that a script loaded from https://my-site.com is only allowed to read data from https://my-site.com.
Imagine if this rule didn't exist. You could visit a malicious website, and that website's Javascript could quietly make a GET request to https://mail.google.com/inbox or https://bank.com/balance. Because your browser automatically attaches your session cookies to those requests, the malicious site could read your emails and bank statements.
CORS is the designated exception to the Same-Origin Policy. It is a way for a server to say to the browser: "Yes, I know this script is coming from https://my-site.com, but I trust that origin. You are allowed to let the script read this response."
3. The Preflight Request (The OPTIONS Call)
When you make a "simple" request (like a standard GET with no custom headers), the browser just sends it.
However, when you make a "complex" request—such as a POST request with Content-Type: application/json or an Authorization: Bearer header—the browser gets paranoid. It doesn't want to send potentially destructive data to a server unless it is absolutely sure the server supports CORS.
So, the browser pauses your POST request and sends an invisible OPTIONS request first. This is the Preflight Check.
What the Browser Asks (The Preflight Request):
OPTIONS /v1/data HTTP/1.1
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type
What the Server MUST Answer:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: authorization, content-type
If the server does not return those exact Access-Control-* headers, the browser immediately kills the connection and throws the CORS error in your console. The actual POST request is never sent.
AIO Checklist
- Open the Network Tab in DevTools and filter by `Fetch/XHR`.
- Look for an `OPTIONS` request. Did it return a `200` or `204`?
- Check the Response Headers of the `OPTIONS` request. Does it contain `Access-Control-Allow-Origin`?
- Does the allowed origin exactly match your current domain (including the protocol and port)?
- Check `Access-Control-Allow-Headers`. Are the custom headers you are trying to send (like `Authorization`) listed there?
4. Why Postman Doesn't Get CORS Errors
One of the most confusing aspects of debugging APIs is that the exact same request will work perfectly in cURL or Postman, but fail miserably in the browser.
Why? Because Postman is not a browser.
cURL, Postman, and backend servers (like Node.js or Python) do not enforce the Same-Origin Policy. If a backend server makes a request to another server, it simply receives the data. There is no Preflight OPTIONS request. There is no checking of Access-Control-Allow-Origin headers.
CORS is strictly a Browser Security Feature. It exists to protect the user's session cookies.
5. How to Bypass CORS for API Testing
When you are rapidly testing third-party APIs (like Stripe, OpenAI, or GitHub), you often cannot modify their backend servers to add your localhost or testing domain to their allowed origins list.
So how do you test them from a web browser?
The Proxy Solution
You must route your request through a backend server.
- Your browser makes a request to your Proxy Server (which is on the same origin, so no CORS error).
- The Proxy Server acts like
cURL. It makes the request to the Third-Party API. (Servers don't care about CORS). - The Third-Party API returns the data to the Proxy Server.
- The Proxy Server returns the data to your browser, attaching an
Access-Control-Allow-Origin: *header.
This entirely bypasses the browser's restrictions safely.
The Instant Solution
Setting up a proxy server just to test a JSON payload is incredibly tedious. That's why we built the API Endpoint Verifier.
It is a browser-based testing client that automatically routes your requests through a secure, zero-persistence Edge Proxy.
- You get the speed of testing right in your browser tab.
- You never have to worry about CORS or Preflight failures.
- Unlike heavy desktop clients, it requires no installation and leaves no footprint.
The next time you see a red CORS error blocking your API testing, don't waste hours modifying payloads. Just proxy it.
Frequently Asked Questions
Q: Can I just use Access-Control-Allow-Origin: * everywhere?
A: You can, but only for purely public APIs. If your API relies on cookies, sessions, or Access-Control-Allow-Credentials: true, the browser explicitly forbids the use of the * wildcard. You must echo back the specific origin of the requester.
Q: Does setting mode: 'no-cors' in fetch() fix the error?
A: No! This is a massive misconception. Setting no-cors tells the browser to send an "Opaque Request." The request will be sent, but Javascript will be completely blinded from reading the response body or headers. It is only useful for things like pinging an analytics pixel, never for reading API data.
External Sources
- MDN Web Docs: Cross-Origin Resource Sharing (CORS)
- W3C Fetch Standard: CORS Preflight
- OWASP API Security Project
Abu Sufyan · Full-stack developer · Founder of WebToolkit Pro Github
Last updated: June 2026
Implementation Directives
- The Network tab in Chrome DevTools will often show a failed `OPTIONS` request before your actual `POST` request. This is the CORS Preflight check. If the Preflight fails, the POST never happens.
- Never use a wildcard `Access-Control-Allow-Origin: *` in production if your API also requires `Access-Control-Allow-Credentials: true`. Browsers strictly forbid this combination.
- If you control the API server, ensure it responds to `OPTIONS` requests with a `200 OK` or `204 No Content`, and that the `OPTIONS` route does not require authentication.
Docker Compose Generator
Generate a docker-compose.yml for any stack — guided and instant.
wtkpro.site
Abu Sufyan
Specialist in distributed systems architecture, V8 performance benchmarking, and cryptographic implementations.
PING AUTHOR