Open-source, end-to-end encrypted onchain group chat protocol on Base. Spaces are owned as onchain assets with programmable membership (ERC-20 / NFT / ETH / address gating). Formerly River Chat — rebranded from River Protocol to Towns Protocol in early 2025, $RVR token became $TOWNS.
- 01token-gated group chats / Spaces
- 02DAO and community comms with onchain memberships
- 03E2E encrypted messaging on Base
- 04in-chat tipping, trading, and bots
- 05permissioned communities with programmable rules
- pnpm add @towns-protocol/sdk @towns-protocol/web3 viem
- bunx towns-bot init my-bot # scaffold a Towns bot using the official template
| Variable | Scope | Description |
|---|---|---|
| NEXT_PUBLIC_TOWNS_ENV | Client | Towns network environment: 'gamma' (testnet) or 'omega' (mainnet on Base). |
| TOWNS_BOT_PRIVATE_KEY | Server | Private key for the bot/agent identity that signs into Towns river nodes. Server-only. |
| NEXT_PUBLIC_TOWNS_BASE_RPC_URL | Client | Base RPC URL — Towns smart contracts (Space Factory, memberships) are deployed on Base mainnet. |
Use Towns for E2E encrypted, token-gated group chat. Instantiate the client with `const client = await Client.create({ env: NEXT_PUBLIC_TOWNS_ENV, signer })` from `@towns-protocol/sdk`, then create or join a Space (`client.createSpace({ name, membershipRules })` or `client.joinSpace(spaceId)`). Channels live under spaces — `space.createChannel({ name })`, send via `channel.sendMessage({ content })`, and stream with `channel.on('message', handler)`. Memberships are onchain ERC-721s on Base, mintable via the Space Factory contract; gate access by ERC-20 balance, NFT ownership, ETH amount, or specific addresses. For bots, run `bunx towns-bot init` then `bun run start` with `TOWNS_BOT_PRIVATE_KEY` to handle events through the bot SDK.
- ⚑Rebrand: 'River Protocol' / 'River Chat' became 'Towns Protocol' in early 2025 and $RVR became $TOWNS. Old `river.build` references redirect; update package names from `@river-build/*` to `@towns-protocol/*`.
- ⚑Smart contracts are on Base, but messages flow through custom 'river nodes' — chat history is not on Base directly. If the node operator set goes down, history availability degrades even though memberships remain onchain.
- ⚑End-to-end encryption (MLS-based) means lost device keys lose history — Towns provides recovery via stream re-keying, but require users to back up keys or they are locked out after wiping a device.
- ⚑Onchain vs offchain content: only memberships, space metadata, and gating rules are onchain (Base). Message bodies live on river nodes encrypted client-side — do not promise 'permanent immutable history' the way an Arweave-backed system would.
- ⚑Content moderation surface: each Space owner sets its own moderation rules via programmable contracts; there is no protocol-level moderation. Plan abuse handling per-space (mods, role NFTs, kick contracts).
- ⚑EVM-only on Base; cross-chain memberships require bridges. Solana / non-EVM users cannot join without a Base address.
- ⚑Bot SDK uses Bun (`bunx`, `bun install`) by default — works on Node but the templates assume Bun.