CORS Header Tester (Preflight Simulator)

CORS errors are the #1 confusing fetch() error: the browser blocks the response but your server is returning 200 OK with the data. The trick is that CORS rules are enforced by the browser, not the server — the server only sets headers, and the browser decides whether to expose the response to JS. This tool simulates exactly that decision: you input the request origin, method, and headers, plus the server's response headers, and it tells you whether a real browser would allow the request — and which header is missing if not.

Request (browser side)

Server response headers

How to use the CORS Header Tester (Preflight Simulator)

Fill in the request (what your browser sends): the Origin header, HTTP method, custom headers, credentials mode. Then paste the server's response headers (use a tool like curl -v or browser DevTools → Network → Response Headers to grab them).

The tool checks each rule the browser enforces and lists what would pass / fail. If preflight is required (it usually is for POST + custom headers), it shows that step separately.

About CORS Header Tester (Preflight Simulator)

CORS (Cross-Origin Resource Sharing) is the W3C standard that lets browsers selectively relax the same-origin policy. By default, a page at https://app.example.com cannot read responses from https://api.example.com via fetch / XHR. The server can opt-in by sending response headers like Access-Control-Allow-Origin: https://app.example.com, telling the browser "this origin is allowed to read this response."

Two flavors:

  • Simple requests (GET/HEAD/POST with safe content types and no custom headers) — the browser sends the request directly, then checks the response's Access-Control-Allow-Origin.
  • Preflighted requests (everything else — PUT/DELETE/PATCH, custom headers like Authorization, content type other than application/x-www-form-urlencoded) — the browser sends an OPTIONS preflight first, asking "may I send method X with headers Y from origin Z?" If the server's preflight response allows it, the actual request goes out.

Credentials add complexity: credentials: "include" (cookies / Authorization sent cross-origin) requires Access-Control-Allow-Credentials: true AND Access-Control-Allow-Origin must be a specific origin (not *).

Common use cases

  • "Why is my fetch() failing?" — paste your request and server's headers, get a specific reason.
  • Configuring a new API — work out exactly which CORS headers you need.
  • Debugging preflight failures — many people miss that OPTIONS needs the same CORS headers as the actual request.
  • Verifying production matches dev — copy headers from prod and dev side-by-side.
  • Auditing CORS for security — checking that a permissive origin (*) isn't leaking sensitive data.

Frequently asked questions

Does this make actual HTTP requests?

No — it simulates the browser's CORS check logic locally. To test against a real server, use curl -H "Origin: ..." -v https://api.example.com/path.

When is OPTIONS preflight required?

When method is not GET/HEAD/POST, OR when custom headers (anything beyond a few "CORS-safelisted" ones like Accept, Content-Language) are sent, OR when Content-Type is anything other than the three safelisted forms.

Why does my API allow Origin: * but credentials still fail?

You cannot use Access-Control-Allow-Origin: * when Access-Control-Allow-Credentials: true. The browser refuses this combination by spec.

Is OPTIONS request cacheable?

Yes — Access-Control-Max-Age: N (seconds) tells the browser how long to cache the preflight response. Chrome caps this at 7200, Firefox at 86400.