Developer Tools
CORS Preflight Simulator
Simulate the browser CORS algorithm on any cross-origin request. See whether a preflight is required, the exact OPTIONS request, and rule-by-rule pass or fail.
Examples
Pick an example to load a common CORS scenario, then tweak any field to see how the verdict changes. Every check updates live as you type.
Browser request
What your page is sending
Target origin resolves to https://api.example.com.
The browser sends this as the Origin header. Use scheme + host (+ port) only, no path. The literal value null is also valid.
The mode passed to fetch (or set on XHR.withCredentials). Same-origin behaves like omit on the cross-origin call.
Safelisted values that do not trigger a preflight: application/x-www-form-urlencoded, multipart/form-data, text/plain.
One header per line in Name: value form. The browser auto-includes Origin, Host, Referer, User-Agent etc., so do not list those here.
Server response
CORS headers the server returns
Sent only on preflight responses. Comma-separated, or * on credentialless requests.
Sent only on preflight responses. Must cover every non-safelisted request header.
Sent on the main response. Adds extra readable headers beyond the CORS-safelisted set.
Sent only on preflight responses. Seconds the browser may cache the preflight result.
Verdict
Preflight fails, main request never sent
Preflight (OPTIONS)
Browser rejects the preflight response, so the main request is never sent and the fetch rejects with a CORS error.
Main response
Skipped because the preflight failed.
Why a preflight was required
- Request includes non-safelisted headers: authorization, content-type, x-request-id.
- Content-Type application/json is not in the CORS-safelisted list (application/x-www-form-urlencoded, multipart/form-data, text/plain).
Step 1
Browser preflight (OPTIONS)
Sent automatically before the real request. The browser uses the response to decide whether the real request may run.
OPTIONS /v1/orders HTTP/1.1 Host: api.example.com Origin: https://app.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: authorization, content-type, x-request-id
Server response (configured)
HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.example.com Vary: Origin Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 600 Access-Control-Allow-Credentials: true
Preflight checks
Access-Control-Allow-Origin
PassAllow-Origin matches the request origin exactly (https://app.example.com).
Reference: Fetch step: CORS check
Access-Control-Allow-Credentials
PassAllow-Credentials is true and Allow-Origin names an exact origin.
Reference: Fetch step: CORS check + credentials mode
Access-Control-Allow-Methods
PassAllow-Methods explicitly lists POST.
Reference: Fetch step: CORS-preflight fetch
Access-Control-Allow-Headers
FailAllow-Headers is "Content-Type, Authorization" and does not cover: X-Request-Id.
Fix: Extend the header list: Access-Control-Allow-Headers: Content-Type, Authorization, X-Request-Id.
Reference: Fetch step: CORS-preflight fetch
Access-Control-Max-Age
PassBrowsers may cache the preflight result for up to 600 seconds (Chromium caps at 7200, Firefox at 86400, Safari at 600).
Reference: Fetch: preflight result cache
Vary: Origin
PassVary: Origin is set, so shared caches keep the response per-origin. No cross-origin cache poisoning.
Reference: RFC 7234 Vary
Step 2
Actual request (POST)
The browser only sends this once the preflight (if any) passes.
POST /v1/orders HTTP/1.1 Host: api.example.com Origin: https://app.example.com Cookie: (sent by the browser when present) Content-Type: application/json Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.payload.signature X-Request-Id: 9b8e
Server response (configured)
HTTP/1.1 200 OK Access-Control-Allow-Origin: https://app.example.com Vary: Origin Access-Control-Expose-Headers: X-Request-Id Access-Control-Allow-Credentials: true
Response checks
Access-Control-Allow-Origin
PassAllow-Origin matches the request origin exactly (https://app.example.com).
Reference: Fetch step: CORS check
Access-Control-Allow-Credentials
PassAllow-Credentials is true and Allow-Origin names an exact origin.
Reference: Fetch step: CORS check + credentials mode
Access-Control-Expose-Headers
PassScripts may read these response headers in addition to the safelisted ones: X-Request-Id.
Reference: Fetch: CORS-safelisted response-header name
Vary: Origin
PassVary: Origin is set, so shared caches keep the response per-origin. No cross-origin cache poisoning.
Reference: RFC 7234 Vary
How the browser decides
Simple request rules
The browser skips the preflight only when all three rules are true: the method is GET, HEAD, or POST, every custom header is CORS-safelisted, and the Content-Type (if any) is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain. Anything else triggers an OPTIONS preflight.
Credentials and wildcards
When fetch is called with credentials: include or XHR with withCredentials = true, the browser refuses * in Allow-Origin, Allow-Methods, and Allow-Headers. Each value must be the exact origin or an explicit list. Allow-Credentials must be true on both the preflight and main response.
Reading custom response headers
Even when CORS passes, scripts can only read the CORS-safelisted response headers (Cache-Control, Content-Language, Content-Length, Content-Type, Expires, Last-Modified, Pragma). Everything else needs to be listed in Access-Control-Expose-Headers.
Vary: Origin and caching
If the server echoes the request origin into Allow-Origin (instead of returning a static wildcard), shared caches must keep responses per-origin. Add Vary: Originso a CDN does not serve one origin's allowance to a different origin.
How to use
- Pick a preloaded example (Default, Simple GET, Method not allowed, or Wildcard + cookies) or start from scratch with your own values.
- On the Browser request card, set the method, target URL, page origin, credentials mode, and any extra request headers your client sends.
- On the Server response card, paste in or type your Access-Control-* response headers exactly as the server returns them.
- Read the Verdict panel for the top-line outcome and an explanation of why the request was treated as simple, preflighted, or same-origin.
- Scroll through the per-rule checks under the preflight and main response cards. Pass and Fail badges show what the browser would accept, and the Fix line under each Fail tells you the exact header change to make.
- Copy the OPTIONS request, the actual request, or either server response block straight into a curl command, a backend test, or a bug report.
About this tool
CORS Preflight Simulator runs the browser's Cross-Origin Resource Sharing algorithm from the Fetch standard against a request you describe and a server response you configure, so you can see exactly why a cross-origin fetch will succeed or fail before you ship it. Pick the method, target URL, page origin, credentials mode, body Content-Type, and any custom request headers your client sends. Pick the server's Access-Control-Allow-Origin, Allow-Methods, Allow-Headers, Allow-Credentials, Expose-Headers, Max-Age, and Vary: Origin settings. The simulator decides whether the browser will treat the request as a simple request or one that requires an OPTIONS preflight by checking the method against the simple-method list (GET, HEAD, POST), the Content-Type against the CORS-safelisted media types (application/x-www-form-urlencoded, multipart/form-data, text/plain), and every custom header against the CORS-safelisted request header names. When a preflight is required, the tool shows the exact OPTIONS request the browser would emit, including Access-Control-Request-Method and a sorted lowercase Access-Control-Request-Headers list. The verdict panel calls out the three outcomes you can land in: same-origin so CORS does not apply, simple-request that goes direct and is allowed or blocked on the response, or preflighted where either the OPTIONS check or the main check can fail. Every rule is reported as a pass or fail card with the spec reference and a plain-language fix recommendation, so you stop guessing at things like why Allow-Origin: * stops working the moment you set credentials: include, why Allow-Methods: * is treated as a literal string when credentials are involved, why your custom X-Auth-Token header triggers a preflight even on a GET, why scripts cannot read X-Request-Id without Access-Control-Expose-Headers, and why a missing Vary: Origin lets a CDN poison your response cache across origins. Three preloaded scenarios cover the most common debugging traps: a simple GET that needs no preflight, a wildcard + cookies misconfiguration, and a missing Allow-Methods entry on a PATCH request. Useful for backend engineers configuring CORS on a new API endpoint, frontend developers debugging a CORS error in the browser DevTools console, security reviewers auditing a permissive Allow-Origin policy, and platform teams writing a CORS proxy or middleware. Everything runs in the browser. Your URLs, origins, header lists, and example payloads never leave the page.
Free to use. Works in your browser. No signup, no login.
Related tools
You may also like
CORS Headers Generator
Build Access-Control headers with live validation and Apache, Nginx, Vercel, Netlify, Next.js, Worker, and Express snippets.
Open tool
DeveloperHTTP Headers Parser
Parse, classify, and decode HTTP headers, with a missing security headers audit.
Open tool
DeveloperURL Parser
Break a URL into protocol, host, path, query params, and fragment with decoded values.
Open tool
DevelopercURL Command Builder
Form-driven builder that emits curl, PowerShell, HTTPie, wget, fetch, and raw HTTP/1.1.
Open tool
DeveloperCSP Header Generator
Visual builder for the Content-Security-Policy HTTP header.
Open tool