Web app
app.cowlprotocol.com runs the whole protocol in a browser tab. Shield, private send, receive, private swap, and your shielded portfolio — same pool, same proofs, same contracts as the CLI. Nothing to install and no toolchain.
What is in it
zcowl1… address from your shielded balance. No token transfer appears on the explorer, and the recipient never signs anything.Your keys, derived from a signature
Connect a wallet, then unlock. Unlocking asks your wallet for one signature and derives your shielded spending and viewing keys from those bytes. The keys live in the tab for the session. They are never uploaded, never escrowed, and no part of Cowl can reconstruct them — the same wallet on any machine derives the same shielded account, and a different wallet derives a different one.
The derivation is deterministic, so that signature is your shielded account. The same bytes open the same book from anywhere.
Cowl asks for it on app.cowlprotocol.com and nowhere else. If another site asks you to sign the unlock message, treat that the way you’d treat a site asking for your seed phrase and walk away. Your wallet shows you the text before you approve, so read it.
Want harder separation? Run a keystore account from the CLI instead. It derives from your private key, never from a signature.
cowl config set shieldedAccount sig-v1. Check that cowl receiveprints the address on the app’s Receive tab before you move anything.Proving happens in your tab
Every spend is a zero-knowledge proof, and the app builds it in a web worker on your own machine. A transfer proof takes about 2.3 seconds and a shield proof about 0.9. The first run of a session is slower because the proving system fetches its reference string once and caches it; after that the cards prove at full speed.
Nothing about your amounts, assets, or counterparty leaves the tab in the clear. What reaches the chain is a proof, two commitments, and two nullifiers.
Who pays the gas
Every spend surface carries a gas payer chip. Gasless is the default: the relayer submits the transaction and takes its fee from inside the same proof, so your wallet never appears as the gas payer. Pick you instead and your own wallet submits it and pays gas in ETH. Someone always pays the gas; gasless just means it is not you.
If a relayer is unreachable, or an asset has no route to price a fee against, the card falls back to self-paid and says so rather than failing.
Amounts leave in shared sizes
Boundary amounts default to shared denomination sizes, so what you withdraw looks like what everybody else withdraws. An exact opt-out is one toggle away when a counterparty needs a precise figure. Private sends between two shielded accounts are not on the boundary at all and carry no such constraint.
Errors say what happened
Rate limits, a relayer running low, a stale root, a spent note, venue slippage, a gas shortfall — each one gets a sentence naming what happened and what to do about it, with the raw line underneath for when you want it. Runs that outlive their sync deadline republish balances when the chain catches up, so a green run never leaves stale numbers on screen.
Limits worth knowing
| Rule | Why |
|---|---|
| Private sends are capped during beta | A single private send tops out at $200 of value, priced on chain. Withdrawals and swaps are not capped — the door out is always open. |
| Shield is never gasless | A relayer fee comes out of notes already inside the pool, and a deposit has none yet. See the relayer. |
| One spend reads two notes | So the most you can move at once is the sum of your two largest notes, not your balance. Merge first — the app offers it exactly when it matters. |