← Protocols
Tonkeeper
01Description

Tonkeeper is the leading self-custody wallet for The Open Network (TON), with mobile, desktop, browser-extension, and embedded Telegram-bot variants. Connects to dApps exclusively via TON Connect 2.0 (no `window.tonkeeper` injection on most platforms) — a bridge-based protocol that handles wallet-to-dApp messaging, transaction signing, and proof-based auth without ever exposing keys.

02Best for
  • 01TON dApps and Telegram Mini Apps
  • 02TON wallet auth (Tonkeeper, Tonkeeper Pro, Tonkeeper Web)
  • 03TON Connect 2.0 transaction signing
  • 04TON proof / Sign-In with TON flows
  • 05in-Telegram payment UX
03Install
  • pnpm add @tonconnect/ui-react @tonconnect/sdk
  • pnpm add @ton/ton @ton/core
04Environment variables
VariableScopeDescription
NEXT_PUBLIC_TONCONNECT_MANIFEST_URLClientPublic HTTPS URL to your `tonconnect-manifest.json` (name, url, iconUrl). Required by `TonConnectUIProvider` for Tonkeeper to render the app's identity in the connect modal.
TON_API_ENDPOINTClientTON HTTP API endpoint, e.g. https://toncenter.com/api/v2/jsonRPC (mainnet) or https://testnet.toncenter.com/api/v2/jsonRPC, for chain reads.
05Prompt snippet
Use Tonkeeper for TON wallet auth via TON Connect. Wrap the app in `<TonConnectUIProvider manifestUrl={NEXT_PUBLIC_TONCONNECT_MANIFEST_URL}>` from `@tonconnect/ui-react`. Read state with `useTonAddress()`, `useTonWallet()`, and `useTonConnectUI()`. To target Tonkeeper specifically, filter the wallets list passed to `<TonConnectButton walletsListConfiguration={{ includeWallets: [{ appName: 'tonkeeper' }] }} />` — `appName` is the canonical identifier published in the TON Connect wallets registry. For transactions, build `{ validUntil, messages: [{ address, amount, payload }] }` (amount in nanoTON, payload as base64 BoC) and call `tonConnectUI.sendTransaction(tx)`. For Sign-In with TON, request a `tonProof` payload at connect time: `tonConnectUI.setConnectRequestParameters({ state: 'ready', value: { tonProof: nonceFromServer } })` then verify the returned signed proof on the server using Tonkeeper's documented proof scheme. Note: there is no `window.tonkeeper` provider in browsers — TON Connect uses an HTTP bridge, not injection.
06Gotchas
  • Manifest URL constraints: `tonconnect-manifest.json` must be served over HTTPS with permissive CORS; Tonkeeper rejects http://, localhost (without tunneling like ngrok), and self-signed certs — the connect modal silently fails with no error in production builds.
  • Telegram Mini App context: when running inside Telegram, Tonkeeper-Telegram-Wallet is auto-prioritized over standalone Tonkeeper. Use `@telegram-apps/sdk` to detect `Telegram.WebApp` and explicitly include `'telegram-wallet'` in `includeWallets` if you want both options surfaced.
  • TON address format: Tonkeeper returns user-friendly base64url addresses (`UQ...` / `EQ...`) but contracts often expect the raw `0:hex` form — use `Address.parse(addr).toRawString()` from `@ton/core` before passing to RPC calls; mixing formats causes silent message routing failures.
  • Account model quirk: TON has no EOAs — every wallet is a smart contract that may not yet be deployed. Sending TON to a fresh Tonkeeper address requires the wallet to deploy itself on first outgoing tx; check `client.isContractDeployed(addr)` and surface a 'first-tx is deployment' UX.
  • Async cross-shard messages: a transfer's masterchain block (~5s) does not guarantee shard-level finality — poll by message hash, not sender tx, and expect 1-3 additional blocks for cross-shard settlement.
  • BoC serialization: Tonkeeper expects payloads as base64-encoded Bag of Cells, not JSON. Use `beginCell().storeUint(...).endCell().toBoc().toString('base64')` from `@ton/core` — passing JSON will be silently rejected by the wallet with no user-visible error.
  • Bridge timeouts: TON Connect's HTTP bridge times out user requests after ~5 minutes; show a UX that re-prompts if the user takes too long, and expect `UserRejectsError` for both explicit rejections and bridge expiries.
07Alternatives