Start a project

Tool 177 of 194 · HTTP

CORS Preflight Debugger

Paste the request your page makes and the headers your server sends back, and see exactly which CORS check fails and how to fix it.

CORS Preflight Debugger at a glanceIllustration: 1, fetch(); 2, processed in your browser; 3, CORS checks.CORS Preflight Debugger</>1fetch()3CORS checks2In yourbrowser
1 fetch() 2 processed on your device 3 CORS checks

CORS Preflight Debugger

Request and server headers

Nothing is sent: the browser's CORS rules are applied to what you paste. Copy headers from the Network tab, or from curl -i -X OPTIONS.

Step by step

    What the browser sends and says

    Preflight the browser sends
    Console error

    Request headers

    HeaderValueCORS

    Fixed server config

    nginx
    Express
    Cloudflare Workers

    01

    What it does

    Runs the browser's CORS checks on a pasted fetch() call or curl command and your server's headers, step by step, with the console error and fixed config.

    • Reads fetch() calls, including headers, credentials and body type, and curl commands
    • Simple request or preflight, from the Fetch standard's safelisting rules
    • The exact preflight the browser sends
    • Allow-Origin, credentials, Allow-Methods and Allow-Headers checks, including the * rules

    02

    Private by design

    Everything happens in your browser. Nothing you type, paste or upload is sent anywhere, and it keeps working offline once the page has loaded.

    03

    What you get

    A step-by-step CORS trace, the console error and fixed server config, with a Copy and a Download button on every result.

    • CORS
    • HTTP
    • Security
    • APIs

    Why it matters

    CORS errors are vague by design: the browser tells your JavaScript almost nothing, and the console message names one problem when there may be three. So developers change server headers by trial and error, often ending with Access-Control-Allow-Origin: * and a new error because the request sends cookies.

    This debugger applies the Fetch standard's rules to what you paste, without sending anything. It works out whether the request is simple or needs a preflight, and why (a PUT, an Authorization header, Content-Type: application/json), builds the preflight the browser would send, then checks the preflight and real responses in the browser's order. It knows the details that trip people up: * means a literal asterisk when credentials are included, * never covers Authorization, Chrome caps Max-Age at two hours, and a missing Vary: Origin lets a cache serve one site's response to another. You get the console error you'd see and server config that fixes it.

    How it works

    1. InputA fetch() or curl request and server headers
    2. In your browserThe Fetch standard's CORS checks in order
    3. OutputThe failing check, console error and fixed config

    Where it fits in a designer's workflow

    1. Plan
    2. Design
    3. Build
    4. Test
    5. Launch
    Fixing a CORS error without trial and error.

    By the numbers

    Preflights a day for one page calling an API every 10 secondsNo Max-Age (5 s): Chrome: 8,640 a day; No Max-Age (5 s): Firefox: 8,640 a day; No Max-Age (5 s): Safari: 8,640 a day; Max-Age 86,400: Chrome: 12 a day; Max-Age 86,400: Firefox: 1 a day; Max-Age 86,400: Safari: 144 a dayNo Max-Age (5 s): Chrome8,640 a dayNo Max-Age (5 s): Firefox8,640 a dayNo Max-Age (5 s): Safari8,640 a dayMax-Age 86,400: Chrome12 a dayMax-Age 86,400: Firefox1 a dayMax-Age 86,400: Safari144 a day
    Worked out by this tool from each browser's cap on Access-Control-Max-Age: Chrome 2 hours, Firefox 24 hours, Safari 10 minutes. Without the header, browsers keep a preflight for only 5 seconds, so nearly every request costs an extra round trip. Source: Fetch standard: CORS protocol; MDN: Access-Control-Max-Age.
    Show the numbers as a table
    Max-AgeChromeFirefoxSafari
    No Max-Age (5 s)8,6408,6408,640
    Max-Age 600144144144
    Max-Age 7,2001212144
    Max-Age 86,400121144

    How to use it

    1. Enter the origin of the page that makes the request.
    2. Paste the fetch() call or curl command.
    3. Paste the headers your server sends to the OPTIONS preflight and to the real request.
    4. Read the steps, then copy the fixed config for your server.

    FAQ

    When does a request need a preflight?

    When it uses a method other than GET, HEAD or POST, or sets any header outside a short safelist. Content-Type is only safelisted for form data, multipart and text/plain, so sending JSON with application/json always triggers a preflight.

    Why doesn't Access-Control-Allow-Origin: * work?

    If the request includes credentials (cookies or HTTP auth, credentials: "include"), browsers refuse a wildcard. The server has to echo back the exact origin, send Access-Control-Allow-Credentials: true and add Vary: Origin.

    Why is Authorization still blocked with Allow-Headers: *?

    The Fetch standard excludes Authorization from the wildcard, so it must be listed by name. And when credentials are included, * is treated as a header literally called *.

    Why does my preflight fail with 401 or 404?

    Browsers send the OPTIONS request without cookies or auth headers, so it must succeed unauthenticated, and your server or framework has to route OPTIONS for that path and return 2xx.

    Does CORS protect my API?

    No. CORS controls which pages can read responses in a browser. Simple requests still reach your server, and curl or a server ignores CORS entirely. Use authentication and CSRF protection for that.

    Work with me

    Want a site that gets these right?

    I build fast, accessible websites and web apps that pass these checks from day one. Tell me about your project and I'll reply personally with honest next steps.

    All developer tools · Back to leej.uk