LocalCORS pre-launch
Pre-launch — Chrome Web Store submission in progress

CORS errors on localhost shouldn’t disappear on refresh or die when you close Chrome.

LocalCORS is scoped to localhost + 127.0.0.1 by default, uses declarativeNetRequest dynamic rules that persist across browser restart, and never touches YouTube. Free, open source, no email wall.

No spam. One email at launch, plus occasional build updates. Unsubscribe anytime.

LC
LocalCORS
v1.0.0
ON
Current host
localhost:3000
Rule scope
localhost/*
Survived refresh
✓ yes
Survived browser restart
✓ yes (dynamic rules)
YouTube impact
none (not in scope)

Every CORS extension silently fails the first 60 seconds of real dev.

We audited all three incumbents side by side on a fresh Vite + React project. They all failed in the same way.

HMR breaks.

The extension intercepts the WebSocket upgrade handshake; your Vite / Webpack HMR disconnects mid-session. You restart the dev server 5 times before realising the extension is the problem.

Page refresh disarms it.

CORS Unblock “automatically turns off if I refresh any page” — GitHub issue #24, open for nearly a year with no fix committed.

YouTube collateral damage.

Every incumbent defaults to <all_urls>. Multiple 1-star reviews cite broken YouTube, buffering, and SPA breakage as the side-effect of a CORS extension you installed for one localhost project.

The MV3 session-rules bug, in one snippet:

// Vite dev server running on localhost:3000
// CORS extension injects declarativeNetRequest SESSION rules via service worker

// ...30 seconds of idle...
//    Chrome kills the MV3 service worker (by spec)
//    Session rules die with it; dynamic rules would have persisted

await fetch('https://api.staging.myco.com/users'); // 403 CORS - session rule is gone
// You toggle the extension off and on again. It works. For 30 seconds.

LocalCORS fixes every failure mode by design, not by patch.

  +--------------------------+
  |  declarativeNetRequest   |
  |  DYNAMIC rules           |
  |                          |
  |  Persist across:         |
  |   ✓ SW eviction (~30s)|
  |   ✓ browser restart   |
  |   ✓ Chrome update     |
  |                          |
  |  No heartbeat. No alarm. |
  |  No cold-start re-arm.   |
  +------------+-------------+
               |
               ▼
  +--------------------------+
  |  Rules registered once   |
  |  on onInstalled +        |
  |  rebuilt on settings     |
  |  change. That’s it.     |
  |                          |
  |  + localhost/*           |
  |  + 127.0.0.1/*           |
  |  + (host you added)      |
  |                          |
  |  NOT <all_urls> ever   |
  +--------------------------+
            
  • 1

    Dynamic rules persist across SW eviction and browser restart.

    We use chrome.declarativeNetRequest dynamic rules, not session rules. Chrome guarantees they survive the ~30s service-worker idle timeout, browser restart, and Chrome update. Allow CORS and CORS Unblock both lose their rule state in contexts where LocalCORS keeps it.

  • 2

    Localhost-scoped by default — never <all_urls>.

    The manifest declares explicit http://localhost/* + http://127.0.0.1/* host permissions. YouTube, Gmail, your bank — all physically out of scope. Adding a staging host is an explicit runtime grant, one click, visible in the popup.

  • 3

    Echoes the exact origin for credentialed requests.

    When the browser sends cookies, we set Access-Control-Allow-Origin: http://localhost:5173 (the exact origin, port included) — never *. ACA-O: * alongside credentials: 'include' is spec-illegal and every incumbent ships that bug.

LocalCORS vs. every CORS tool devs actually use today.

No cherry-picked features. Every cell traces to a verbatim 1-star review, a GitHub issue, or the official CWS listing.

What ships on day one.

Five features. No bloat. Free forever — the paid tier (V2) adds request modification and response overrides, never core CORS bypass.

Auto-scope by default

Permissions limited to localhost/*, 127.0.0.1/*, *.local/*. No <all_urls> at install. Add hosts explicitly in the popup.

Persist across browser restart + SW eviction

declarativeNetRequest dynamic rules (not session rules). Chrome guarantees they survive the ~30s service-worker idle timeout, browser restart, and Chrome update. No heartbeat, no alarm hacks.

Per-tab badge state

Badge reads ON localhost:3000 or ON api.staging.myco.com. Zero guessing — you always see exactly what’s active.

Preflight OPTIONS, first-class

Handle OPTIONS with Access-Control-Allow-Origin + Allow-Methods: * + status-200 override, built-in. No toggle.

Config export / import (JSON)

One-click export of per-host rules; import the same JSON in another profile or on a teammate’s machine. No account, no cloud sync, no surveillance.

Frequently asked.

Is this open source?
Yes. MIT-licensed, public repo from day 1. GitHub link coming at launch — you’ll be able to read every line, fork it, or build from source.
Will this break YouTube?
No. LocalCORS is scoped to localhost/*, 127.0.0.1/*, and *.local/* at install time. YouTube, Gmail, and your company intranet are all out of scope by default. If you want to enable rules for another host, it’s an explicit, visible action in the popup — not a silent <all_urls> default.
Why not just run Chrome with --disable-web-security?
The flag disables all origin protection for the whole browser — it doesn’t just lift CORS. You lose HTTPS cookie isolation, same-site cookies, the Intelligent Tracking Prevention tooling, and safety on every tab you have open. That’s fine for a disposable profile, but terrible for your actual dev browser where you’re also logged into GitHub, staging admin panels, and your bank. LocalCORS lifts CORS only, only on hosts you’ve opted in, and leaves every other security feature intact.
How does LocalCORS handle the MV3 service-worker respawn?
Dynamic rules persist across SW eviction and browser restart — Chrome guarantees this. Our service worker only re-registers rules when you change settings. No heartbeat, no alarms, no periodic wake-up hacks. The incumbents mostly use session rules (which die with the SW), broken 25s alarms (Chrome clamps alarms to a 30s minimum since Chrome 120, so they fire at the eviction boundary, not before), or abandoned static manifest rules — all of which produce the CORS Unblock issue #24 failure pattern.
Why should I trust this over Allow CORS / CORS Unblock / Moesif?
Three concrete differences, each a bug the incumbents still ship:
  • Persistent dynamic rules. The incumbents use session rules (die with the SW) or broken heartbeat alarms (mathematically clamped by Chrome). LocalCORS uses dynamic rules that Chrome persists across SW eviction, browser restart, and Chrome update.
  • Runtime host permission grants. The incumbents either default to <all_urls> (Allow CORS, CORS Unblock — collateral damage on YouTube) or gate per-site enable behind an email form (Moesif). LocalCORS ships localhost-scoped and grants additional hosts as explicit runtime grants.
  • Credentials-mode correctness. Every incumbent sets Access-Control-Allow-Origin: *, which is spec-illegal alongside credentials: 'include' — the browser silently drops the response. LocalCORS echoes the exact request origin (scheme + host + port) so cookie-authed dev workflows actually work.
When does it ship?
Pre-launch. The extension is under active development; Chrome Web Store submission is scheduled in 4–6 weeks. Join the waitlist below and you’ll get one email on launch day with the install link and the open-source repo.

Stop fighting your CORS extension. Join the waitlist.

One email at launch. No spam. No reselling. No nonsense.

Jump to the form ↑