AllOrigins alternative: replacing api.allorigins.win
AllOrigins is a free, MIT-licensed CORS proxy, and its public instance at api.allorigins.win is in a lot of tutorials. It needs no key, which makes it easy to start with and hard to depend on. If yours has started timing out or returning 5xx errors, this covers the options and the code change for each.
How it behaves today
We requested both documented endpoints for https://example.com twice while writing this. Each endpoint succeeded once and failed once:
/raw:522after about 20 seconds, then200in 3 seconds./get:200in 5 seconds, then520after about 15 seconds.
We saw the same pattern a month earlier while writing about the codetabs shutdown. A 520 or 522 comes from the CDN in front of the server: the origin didn't answer in time. Your browser will report it as a CORS error, because the error page has no Access-Control-Allow-Origin header.
That isn't a criticism of the maintainer. A free proxy with no keys has no way to stop one heavy user from slowing it down for everyone else.
Your options
- Check you need a proxy at all. CORS is enforced only by browsers. If the request runs on a server, in a build step or a cron job, call the upstream directly.
- Self-host AllOrigins. It's open source:
git clone,npm install,npm start, and it listens on port 1458. Your code keeps the same/getand/rawcalls, and you own uptime and abuse handling. - Another free shared proxy. It has the same economics, so expect the same problems eventually. Our free CORS proxy comparison covers what's still running.
- A managed proxy with keys. Keys and per-account quotas are what keep one user from taking the service down for everyone. That's what corsproxy.dev is, so weigh this section accordingly.
The code change, if you pick us
AllOrigins has two shapes. /raw returns the upstream body as is, and /get wraps it in JSON with the body in contents. corsproxy.dev always returns the upstream response as is, with its status code, so /raw maps directly and /get loses a layer.
const target = encodeURIComponent('https://api.example.com/data');
// Before: AllOrigins /raw
const res = await fetch(`https://api.allorigins.win/raw?url=${target}`);
// After: corsproxy.dev
const res = await fetch(`https://api.corsproxy.dev/proxy?url=${target}&key=YOUR_KEY`);
// Before: AllOrigins /get
const data = await (await fetch(`https://api.allorigins.win/get?url=${target}`)).json();
const html = data.contents;
// After: corsproxy.dev, no JSON wrapper
const html = await (await fetch(`https://api.corsproxy.dev/proxy?url=${target}&key=YOUR_KEY`)).text();
A real difference with /get: an upstream 404 used to arrive as a 200 with the error inside the JSON. Now it arrives as a 404, so check res.ok.
Two AllOrigins parameters have no equivalent here. There's no callback for JSONP, so use fetch. There's no charset override either, so decode non-UTF-8 pages yourself with TextDecoder on res.arrayBuffer().
A free key covers 500 requests and 250 MB a day, no card. Pro is $5 a month for 20,000 requests and 10 GB a day. We accept GET and POST, and you can lock a key to your site's origin in the dashboard.
Moving off AllOrigins
Get a free key, swap the host, and drop the .contents unwrapping if you used /get.