Comparison

Self-host vs managed CORS proxy: which one for which job?

You can use corsproxy.dev, the hosted API we run, or self-host our MIT-licensed open-source Go relay. They are two different programs with different behaviour, not one proxy in two packages. This post compares them and helps you pick.

· ~8 min read · Updated Oct 13, 2026

The two-line summary

For most "I just need to ship this prototype" situations, managed wins on time-to-first-request. For security-sensitive cases where requests must stay inside your own perimeter, self-hosting wins on control, but you take on its security defaults (below).

How the two actually differ

The hosted service is a TypeScript Cloudflare Worker. The open-source proxy is a separate, simpler Go program. They share the idea of passing a target URL as a query parameter and adding CORS headers, and not much else:

Managed (corsproxy.dev) Self-hosted Go relay
ProgramTypeScript Cloudflare WorkerGo binary (main.go), standard library only
Endpoint/proxy?url=… (or /v1/proxy)/?url=…
MethodsGET and POST (plus OPTIONS preflight)Any method
Auth to the proxyAPI key (?key= or X-API-Key)None
LimitsDaily request and bandwidth quota per accountOptional per-IP per-minute limit, off by default
Browser Cookie / AuthorizationStripped before the upstream callForwarded to the upstream
Upstream Set-CookieStrippedPassed back
Upstream authenticationManaged upstream headers, or reqHeadersWhatever headers the browser sends
Private-network targetsBlocked (literal IPs plus a DNS check that fails open)Blocked (DNS lookup that fails closed, re-checked on each redirect)
RedirectsNot followed; the 3xx is returnedFollowed, up to 10
CachingPro: ttl edge cachingNone
Oversized responses10 MB cap, fails with 502 RESPONSE_TOO_LARGE10 MB default, silently truncated

The header row matters most. The Go relay is a transparent pass-through: whatever cookies or tokens the browser attaches go to the upstream, and cookies the upstream sets come back. That is useful when you control both ends, and risky on a public deployment.

Self-hosted: what you get and what it costs

The OSS repo (github.com/melihbirim/corsproxy) is a single Go program with no dependencies outside the standard library, MIT licensed. Run it with:

git clone https://github.com/melihbirim/corsproxy
cd corsproxy
go run main.go

The README also covers Docker and one-click deploys for Railway, Render, Fly.io and Koyeb.

You get:

You take on:

Managed: what you get and what it costs

The hosted API at api.corsproxy.dev is its own program with accounts, quotas and a dashboard built in.

You get:

You take on:

The decision in four questions

  1. Is what I'm proxying sensitive enough that I want it inside my own perimeter? Yes → self-host. No → managed is fine.
  2. Do I need PUT, PATCH or DELETE, or cookies passed through? Yes → self-host. No → either works.
  3. Do I want to build API keys, quotas, and a usage dashboard myself? Yes → self-host. No → managed.
  4. Is "time to first proxied request" more important than long-term operational control? Yes → managed. No → either works; pick the one whose constraints match how your team already operates.

Switching between them

Switching is not a drop-in URL swap. The managed path is /proxy?url= and needs a key; the self-hosted path is /?url= with no key. Behaviour differs too, as the table shows, so test cookie, auth and method handling after you switch. Environment variables keep the difference in one place:

// Managed: https://api.corsproxy.dev/proxy?key=...&url=...
// Self-hosted: https://your-host/?url=...
const key = process.env.PROXY_KEY;
const proxied = key
  ? `https://api.corsproxy.dev/proxy?key=${encodeURIComponent(key)}&url=${encodeURIComponent(targetUrl)}`
  : `${process.env.PROXY_URL}/?url=${encodeURIComponent(targetUrl)}`;

fetch(proxied);

Try either in five minutes

Hosted account on the Free tier: create an account. Self-host: clone the repo.