Veil carries the reads your apps make through the Ethereum Foundation's anon-rpc over Tor, with one circuit per account, so the providers your apps talk to never see your IP or tell your accounts apart. And it keeps dapps working even when their providers block Tor.
With Veil off, every account exits from one IP, so a provider links them. With Veil on, each account gets its own Tor circuit and a distinct exit.
The real fix is apps integrating anon-rpc, but only a couple have, all opt-in, and until the rest do, you are the one who pays, with every read exposed. Veil moves the decision to you: no new app to learn, turn it on once, and every wallet and dapp you already use is private the moment you open it.
The apps you already open, private the moment you do.
Each dapp and wallet has to integrate privacy itself. Only a couple have, all opt-in. You wait, app by app, and most never do.
Turn it on once. Every wallet and dapp you already use is private, per account, with zero changes from them.
A VPN gives all your accounts one IP, so they still look like one person. Tor Browser isolates by site, not by account, so two wallets on the same dapp share an exit, and many providers block it outright. Veil gives each account its own circuit.
The extension is the part most people see: a single switch, a popup that shows exactly what each tab protected, a live feed of every read it carries over Tor, and an honest prompt when a site fights back.
One route per account over Tor. Re-routes around providers that block it - and never falls back to direct without asking.
We can't route this request privately and can't safely re-route it. You can allow a direct (non-private) connection for this site - or keep it blocked.
Privacy you don't actually have is worse than none.
Veil sits between the page and its RPC provider. No change to the dapp, no new endpoint - it catches the reads the app already makes and carries each one over Tor, hash-pinned and sandboxed.
At document_start, before the dapp's own scripts run, Veil wraps window.fetch and XMLHttpRequest. Every JSON-RPC read goes through one of those, so a single hook covers viem, ethers v5/v6 and raw XHR with no per-app integration. The rare read over a WebSocket or Web Worker isn't wrapped yet, a negligible slice of traffic.
Veil reads which account the request is for - from the params, or from inside eth_call calldata, ignoring the zero address - and gives it an anon-rpc isolation key. The same account always rides the same Tor circuit; two accounts never share one. The JSON-RPC id is blinded (viem numbers requests from one global counter) so a provider can't stitch routes back together by id.
The read is handed to the anon-rpc harness: a null-origin, sandboxed iframe running tor-js, a full Tor client compiled to WebAssembly. Its code is fetched at runtime but hash-pinned on-chain and verified before it runs, with no access to your keys, DOM or cookies. It builds a circuit through a blind KPS gateway that relays only encrypted bytes - never your traffic or destination - and reaches the provider from a Tor exit unique to that account.
If a provider refuses Tor (Aave's blocked all 16 of our test reads), Veil re-sends standard reads to a Tor-friendly provider on the same chain - but only after a real block, and only for endpoints it knows are a single standard RPC. A multichain gateway is never blindly re-routed (that would break it); it falls to your per-site choice.
A read that can't be made private is blocked, or asks you - per site - before any direct connection. Nothing leaves in the clear, and nothing leaks while the first circuit is still building.