Getting a CORS error from an API while developing? Add the missing headers in Chrome.
Short answer. Chrome blocks the response because the API does not send Access-Control-Allow-Origin. A header extension can add that response header in your own browser, for one domain only, without touching the server and without launching Chrome with --disable-web-security. One rule fixes simple GET requests. A JSON POST needs two more.
Every result on this page was checked on 2026-09-28 by an automated test that loads Headrule in Chromium 141 and makes real requests: test/guides.mjs.
Development only. These rules loosen a browser protection for one domain, in your browser. Scope them to the API you are working on, and pause Headrule with Alt+Shift+H when you are done. Your users still get the real headers, so the server needs fixing before you ship.
On this page: Why it happens The rules When it cannot work What we tested FAQ
Why the browser blocks it
When a page on http://localhost:3000 calls https://api.example.test, the request usually reaches the server and the server answers. Chrome then checks the answer for Access-Control-Allow-Origin. If it is missing, your code gets TypeError: Failed to fetch and the console shows a CORS error. The fix normally belongs on the server. While you wait for that, you can add the header on the way into your browser.
For some requests Chrome first sends an OPTIONS request, called a preflight, to ask whether the real request is allowed. That happens for methods other than GET, HEAD and POST, for a POST with Content-Type: application/json, and when your code adds its own headers. The preflight answer needs two more headers.
The rules
1. Simple GET requests. Open Headrule, click + Add rule, and fill in one row. Replace the URL filter with your API's domain.
| Type | Action | Header | Value | URL filter |
|---|---|---|---|---|
| Response | Set | Access-Control-Allow-Origin | * | ||api.example.test |
2. JSON POST, PUT, DELETE, or custom headers. Add two more rows for the preflight.
| Type | Action | Header | Value | URL filter |
|---|---|---|---|---|
| Response | Set | Access-Control-Allow-Origin | * | ||api.example.test |
| Response | Set | Access-Control-Allow-Headers | Content-Type, Authorization | ||api.example.test |
| Response | Set | Access-Control-Allow-Methods | GET, POST, PUT, PATCH, DELETE, OPTIONS | ||api.example.test |
List the request headers your code actually sends in Access-Control-Allow-Headers. Chrome also accepted * in our test, but the Fetch standard says * does not cover Authorization, so naming it is the safer habit.
3. Cookies or other credentials. If your code uses credentials: "include", Chrome refuses *. Use your exact origin and allow credentials:
| Type | Action | Header | Value | URL filter |
|---|---|---|---|---|
| Response | Set | Access-Control-Allow-Origin | http://localhost:3000 | ||api.example.test |
| Response | Set | Access-Control-Allow-Credentials | true | ||api.example.test |
A URL filter like ||api.example.test covers that domain and its subdomains. For a local API on a port, ||localhost:8080/ works.
When it cannot work
- The server rejects the preflight. An extension can add and change headers, but not status codes. If the API answers
OPTIONSwith 404, 405 or 500, the preflight fails no matter which headers you add. Our test confirms this. Options: have the backend answerOPTIONSwith 204, or call the API through your dev server's proxy so the request is same-origin. - The request never reaches the server. DNS errors, mixed content (an https page calling http), or a blocked port are not CORS problems, even though the console message can look similar.
What we tested
| Situation | Result |
|---|---|
| GET, no rules | Blocked |
| GET, rule 1 | Works |
| JSON POST, rule 1 only | Blocked (preflight has no Allow-Headers) |
| JSON POST, rules 1 to 3, server answers OPTIONS with 204 | Works |
| JSON POST, same rules, server answers OPTIONS with 404 | Blocked |
Request with credentials, * as origin | Blocked |
| Request with credentials, exact origin plus Allow-Credentials | Works |
Questions
Why not start Chrome with --disable-web-security?
That flag switches off the same-origin policy for every site in that browser profile, and it needs a separate profile to take effect. A header rule changes one domain, in your normal profile, and turns off with one switch.
Does this change anything on the server or for other people?
No. The headers are changed inside your browser as the response arrives. Nobody else is affected.
Do I need Pro for this?
No. Unlimited rules and domain filters are free. Pro adds more profiles, regex URL filters and sync.
Does it work in Edge, Brave or Arc?
Yes. Any Chromium-based browser that installs from the Chrome Web Store.
Related guides
Try it on your own API
Free to install. Every rule on this page works in the free version.