Migration

Migrating from cors-anywhere to corsproxy.dev

If you're hitting cors-anywhere.herokuapp.com and seeing requests blocked at 50 per hour, this is the drop-in alternative. Same request shape, no demo limits, and the option to self-host the same Go binary we run.

~5 min read

Why cors-anywhere stopped working for you

The public cors-anywhere.herokuapp.com instance was always meant as a demo of the open-source Rob--W/cors-anywhere project, not a production service. In 2021 the maintainer added a temporary-access gate after sustained abuse; today the demo instance is rate-limited to ~50 requests per hour per IP and rejects unrecognised origins with HTTP 403.

That's by design — the maintainer is right that an open proxy on the public internet shouldn't be free at scale — but it leaves a lot of frontends quietly broken.

The migration in one diff

The request shape is identical. You change the host and add an API key header:

// Before — cors-anywhere demo
fetch('https://cors-anywhere.herokuapp.com/' +
      'https://api.example.com/users')

// After — corsproxy.dev
fetch('https://api.corsproxy.dev/proxy?url=' +
      encodeURIComponent('https://api.example.com/users'), {
  headers: { 'X-API-Key': 'sk_live_...' }
})

Two differences worth flagging:

Common patterns and their replacements

1. Wrapper function in your codebase

If you abstracted cors-anywhere into a helper, the replacement is one line:

// Before
const corsFetch = (url, opts) =>
  fetch('https://cors-anywhere.herokuapp.com/' + url, opts);

// After
const PROXY = 'https://api.corsproxy.dev/proxy';
const KEY = import.meta.env.VITE_PROXY_KEY;
const corsFetch = (url, opts = {}) =>
  fetch(`${PROXY}?url=${encodeURIComponent(url)}`, {
    ...opts,
    headers: { ...opts.headers, 'X-API-Key': KEY }
  });

2. Axios baseURL

// Before
const api = axios.create({
  baseURL: 'https://cors-anywhere.herokuapp.com/https://api.example.com'
});

// After
const api = axios.create({
  baseURL: 'https://api.corsproxy.dev/proxy',
  headers: { 'X-API-Key': process.env.REACT_APP_PROXY_KEY }
});

// Then call like:
api.get('?url=' + encodeURIComponent('https://api.example.com/users'));

// Or wrap it more cleanly:
const proxied = (path) =>
  api.get('?url=' + encodeURIComponent('https://api.example.com' + path));

3. Background fetcher / server-side script

If the requests are coming from your backend (a cron job, a Lambda, anything not in a browser), you probably don't need a CORS proxy at all — CORS is a browser-only restriction. Drop the proxy entirely and call the upstream directly.

What you get that cors-anywhere doesn't have

What you give up vs running your own cors-anywhere

The original cors-anywhere supports response caching and a few header-forwarding modes that we deliberately don't ship for security reasons — see our security writeup. If you rely on those, the closest path is to fork our OSS binary and add the behavior you need.

One-line migration

Get a free key, swap the host, and you're back to working CORS proxying in five minutes.