SOCKS5 and plaintext HTTP CONNECT both put a fixed, recognizable handshake on the wire before a single byte of your traffic moves - wrapping that in TLS hides the bytes from a passive observer, but not from anything that terminates the TLS itself. The AntiBrow relay is a different shape: the browser engine opens one encrypted WebSocket connection and speaks an AEAD-sealed frame protocol inside it, with your own upstream proxy on the other end. It's open source, MIT licensed, and meant to be self-hosted on a domain you control.
Every cell below is something the protocol does today - the full frame format and key schedule are in the whitepaper.
| SOCKS5 | HTTPS proxy | AntiBrow relay | |
|---|---|---|---|
| What a passive observer sees | A SOCKS5 handshake | A plaintext CONNECT naming the target | A WebSocket connection to the host the relay runs on |
| Target hostname on the wire | In the handshake | In the CONNECT line | Inside the encrypted frame |
| Fixed-length protocol header to match on | Yes | Yes | No |
| Proxy credentials reach the page process | No | No | No |
| Runs without a local helper process | Yes | Yes | Yes |
The Engine runtime speaks this protocol natively - there is no local forwarder process and no browser extension involved, so chrome://extensions stays empty. The proxy credential reaches the network service process; it never reaches the page's renderer process.
Each connection derives two direction-independent keys from a client-chosen salt via HKDF-SHA256, and every frame is sealed on its own with AES-256-GCM under a strictly increasing counter nonce. It's the same primitive layer WireGuard and OpenVPN build on, just carried inside a WebSocket over TLS instead of its own transport.
Deployed as a Cloudflare Worker, the browser connects to the nearest Cloudflare point of presence and the long-haul leg back to your own upstream rides Cloudflare's own backbone from there. That's a property of the Worker deployment, not of the protocol - run the relay as a plain Node process instead and the browser just holds a WebSocket open to whatever host you put it on.
No plaintext CONNECT line, no SOCKS5 handshake bytes, no fixed-length protocol header, and a TLS SNI that names your own domain. Signature and heuristic matching for proxy or anonymizer traffic - the kind built into enterprise firewalls and DPI appliances - has nothing of that shape to match here.
Two limits worth knowing before you rely on this. A managed device running TLS inspection - a corporate root certificate doing deep packet inspection - sees the WebSocket upgrade and the sealed frames underneath it. It still finds no proxy-protocol signature, but that vantage point sees more of the connection than a passive network observer does. And domain-category filtering has nothing to do with any of this: it blocks a hostname before a single byte of any protocol is inspected, which is exactly why self-hosting on a domain you control - rather than a shared default one - is the point.
Three commands stand up a deployment: generate a key, deploy it, then create an account.
npx antibrow-relay keygen prints a pre-shared key for the deployment. Save it - it isn't stored anywhere by the relay itself.
wrangler deploy ships it as a Cloudflare Worker, or run it as a plain Node process. Bind it to a domain you control before pointing real traffic at it.
Open /admin and create an upstream and an account against it. The account credential is what a client passes in the relay:// URL below.
This is SDK usage, not something you type into a proxy field in a client UI. The JavaScript SDK's launch() takes the URL directly:
import { AntiDetectBrowser } from 'anti-detect-browser'
const browser = await new AntiDetectBrowser({ apiKey }).launch({
proxy: 'relay://alice:s3cret@relay.yourdomain.com?key=<relay key>',
}) ?key= is the deployment's pre-shared key from step 1, and it is what selects the encrypted protocol - for the browser, and for the exit-IP lookup the SDK runs before launch so that timezone and WebRTC follow the relay's exit. Without it the URL means the older plaintext protocol instead, which a relay serves only if its operator turns it on.
The Python SDK's launch() takes the same relay:// URL - both SDKs live at github.com/antibrow/antibrow. The full frame format, key schedule and deployment steps are in the whitepaper; the relay server's own source is at github.com/antibrow/relay.
Don't want to run one yourself? A hosted relay is available at bastion.antibrow.com.
Frame format, key schedule, and exactly what each of the three observers in the threat model can and can't see.