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.

What is the 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.
Embed this tool on your site

Free to embed, no attribution required (but appreciated). Paste this where you want the tool to appear: