Zero Signup ToolsFree browser tools

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.

Credentials mode

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

    Pass

    Allow-Origin matches the request origin exactly (https://app.example.com).

    Reference: Fetch step: CORS check

  • Access-Control-Allow-Credentials

    Pass

    Allow-Credentials is true and Allow-Origin names an exact origin.

    Reference: Fetch step: CORS check + credentials mode

  • Access-Control-Allow-Methods

    Pass

    Allow-Methods explicitly lists POST.

    Reference: Fetch step: CORS-preflight fetch

  • Access-Control-Allow-Headers

    Fail

    Allow-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

    Pass

    Browsers 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

    Pass

    Vary: 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

    Pass

    Allow-Origin matches the request origin exactly (https://app.example.com).

    Reference: Fetch step: CORS check

  • Access-Control-Allow-Credentials

    Pass

    Allow-Credentials is true and Allow-Origin names an exact origin.

    Reference: Fetch step: CORS check + credentials mode

  • Access-Control-Expose-Headers

    Pass

    Scripts may read these response headers in addition to the safelisted ones: X-Request-Id.

    Reference: Fetch: CORS-safelisted response-header name

  • Vary: Origin

    Pass

    Vary: 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

  1. Pick a preloaded example (Default, Simple GET, Method not allowed, or Wildcard + cookies) or start from scratch with your own values.
  2. On the Browser request card, set the method, target URL, page origin, credentials mode, and any extra request headers your client sends.
  3. On the Server response card, paste in or type your Access-Control-* response headers exactly as the server returns them.
  4. Read the Verdict panel for the top-line outcome and an explanation of why the request was treated as simple, preflighted, or same-origin.
  5. 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.
  6. 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

All tools
All toolsDeveloper Tools