When Does a CORS Preflight (OPTIONS) Fire? — The 3 Conditions
While generating cURL/fetch/axios code with the HTTP Request Builder, you may have noticed that the exact same request throws a CORS error when actually run in a browser, or that an OPTIONS request you never sent shows up in the DevTools Network tab. That's a preflight request. Instead of trying to intuit when it happens, there are exactly 3 conditions worth memorizing.
1. Why the Browser Asks First, Before the Real Request
A cross-origin (different-domain) request carries a risk: an arbitrary site could send a request carrying the user's credentials (like cookies) to a server that never prepared for it. To guard against this, browsers split requests into two categories. Requests that stay within what a plain HTML form could always do are classified as simple requests and sent immediately. Anything beyond that scope gets an OPTIONS request sent first, asking the server "is it okay to send this?" before the real request goes out — that's the preflight. Only if the server grants permission via Access-Control-Allow-* headers does the actual request follow.
2. The 3 Conditions That Push You Outside "Simple Request"
If any one of the three below applies, a preflight fires — no exceptions. You have to avoid all three to stay a simple request.
| # | Condition | Concrete example |
|---|---|---|
| ① | Method isn't GET/HEAD/POST | PUT, DELETE, PATCH, etc. |
| ② | Content-Type is outside the 3-value safelist | Anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain — most notably application/json |
| ③ | A custom header outside the CORS-safelisted set is added | Authorization, X-Custom-Header, etc. |
These 3 conditions are also spelled out in the FAQ on the HTTP Request Builder page itself. But checking the actual tool code confirms it only presents this as text guidance — the builder doesn't run your current input values against these conditions and warn you in real time that "this request will trigger a preflight." You have to consult the table and judge for yourself.
3. The Combination You'll Hit Most Often in Practice
Almost any REST API call made with a JSON body triggers a preflight. The POST method itself is on the safelist, but Content-Type: application/json falls under condition ②. Add an Authorization: Bearer token header on top of that, and you now also trip condition ③ — doubling up on reasons for a preflight.
| Request configuration | Conditions triggered | Preflight fires? |
|---|---|---|
| POST + Content-Type: application/x-www-form-urlencoded + no extra headers | None | No (simple request) |
| POST + Content-Type: application/json + Authorization header | ② and ③ both | Yes (OPTIONS fires first) |
Both look like "just one POST" on the surface, but if you open the Network tab, only the second request has an extra OPTIONS request logged ahead of the real one. Checking whether the server's response headers actually include Access-Control-Allow-Methods and Access-Control-Allow-Headers with the CORS Header Checker is a fast way to narrow down why a preflight is failing.
4. You Can't Turn Off a Preflight — Only Design Around It
There's no client-side option to "disable" a preflight. It's the browser automatically judging your request's configuration, so the only thing a developer can actually do is design the request to avoid all 3 conditions in the first place. In practice, though, JSON APIs and auth headers are the norm, so a more realistic fix is usually configuring the server to respond to OPTIONS requests with the correct CORS headers, rather than trying to dodge the preflight altogether.
Frequently Asked Questions
Q. Do GET requests trigger a preflight too?
GET itself doesn't trip condition ① (allowed methods). But if you add a custom header like Authorization to a GET request, that trips condition ③ and a preflight fires.
Q. Can I avoid a preflight by switching Content-Type to text/plain?
As far as condition ② goes, yes. But if you send a JSON string as text/plain, the server won't automatically parse it as JSON, so you'll need extra handling. And you still need to avoid the other conditions (method, custom headers) for it to actually count as a simple request.
Q. Do same-origin requests need a preflight?
No. A preflight is a concept that only applies to cross-origin requests. If the domain, port, and protocol all match, CORS never even comes into play.
Q. Does the HTTP Request Builder automatically tell me if a preflight will fire?
No. Right now this builder only generates cURL/fetch/axios code and offers FAQ guidance — it doesn't evaluate your current request configuration against the 3 conditions in real time. You need to compare it against the table yourself.
Q. What error shows up when a preflight fails?
Usually you'll see a console message along the lines of "has been blocked by CORS policy," and the Network tab will show the OPTIONS request as failed (or returning something like 403). The browser never sends the actual request at all.