We have been integrating Tonkeeper and other TON wallets into dApps for over 5 years. Our track record includes 20+ projects where TON Connect operated under high load — from NFT marketplaces to DeFi farms with thousands of users. The most common mistake we see from clients: transferring EVM experience to TON. In Ethereum, the wallet communicates directly with a node via JSON-RPC, but here it does not. TON Connect uses a bridge server, deep links, and QR codes. Without understanding this architecture, integration breaks at the first production deployment — bridge loses connection, manifest fails to load, addresses get confused.
Why TON Connect Is More Complex Than EVM?
TON is not a blockchain in the classical sense, but an asynchronous network with an actor model. The state of a contract is changed not by calling a function, but by sending a message. Therefore, TON Connect does not provide an RPC method for sending transactions — instead, the dApp passes a message through a bridge, and the wallet processes it and sends it to the blockchain. This complicates debugging but offers interesting possibilities: a transaction can be signed offline and sent later. According to the official TON Connect documentation, this separation allows achieving a transaction confirmation time of 3-5 seconds, which is 3 times faster than MetaMask (12-15 seconds).
How TON Connect 2.0 Works?
The dApp initiates a session: generates a keypair (x25519), publishes its public key to a bridge server (bridge.tonapi.io or self-hosted). The wallet receives an invite via deep link (ton-connect://...) or QR. After handshake — an encrypted channel through the bridge. All requests (sendTransaction, signMessage) go through this channel, not a direct RPC to the node.
This means: integration works even if the TON node is unavailable — the bridge holds a connection with the wallet separately from reading the blockchain. The bridge buffers up to 1000 requests per second, which is critical for DeFi applications with high transaction frequency.
Implementation with @tonconnect/ui-react
The official library covers most use cases. Let's go step by step.
Step 1: Setting up manifest.json
manifest.json is a required file that the wallet shows to the user when connecting. It must be available over HTTPS on the same domain as the dApp. Example:
{ "url": "https://yourapp.com", "name": "Your dApp", "iconUrl": "https://yourapp.com/icon-256.png" } Common manifest errors
Incorrect iconUrl (not HTTPS), missing name field, file inaccessible at the specified URL — all lead to connection errors. We recommend checking the manifest via Tonkeeper test mode.Step 2: Connecting TonConnectProvider
import { TonConnectUIProvider, TonConnectButton, useTonConnectUI, useTonAddress } from '@tonconnect/ui-react'; // At the root of the app <TonConnectUIProvider manifestUrl="https://yourapp.com/tonconnect-manifest.json"> <App /> </TonConnectUIProvider> Step 3: Sending a Transaction
const [tonConnectUI] = useTonConnectUI(); const userAddress = useTonAddress(); // raw or friendly format async function sendTon(toAddress: string, amountNano: string) { await tonConnectUI.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 300, // 5 minutes messages: [ { address: toAddress, amount: amountNano, // in nanoTON (1 TON = 1e9 nanoTON) } ] }); } How to Send Jetton via TON Connect?
TON contracts accept messages with body — TL-B cell. To send a call to a Jetton contract (analogous to ERC-20):
import { beginCell, toNano } from '@ton/core'; // Transfer Jetton: op = 0xf8a7ea5 const body = beginCell() .storeUint(0xf8a7ea5, 32) // op code .storeUint(0, 64) // query_id .storeCoins(toNano('10')) // amount .storeAddress(destinationAddress) .storeAddress(responseAddress) .storeBit(0) // no custom payload .storeCoins(toNano('0.05')) // forward_ton_amount .storeBit(0) .endCell(); await tonConnectUI.sendTransaction({ validUntil: Math.floor(Date.now() / 1000) + 300, messages: [{ address: jettonWalletAddress, amount: toNano('0.1').toString(), // TON for gas payload: body.toBoc().toString('base64'), }] }); Getting Address and Balance
Reading data — via TonAPI or toncenter.com, not through TON Connect:
import { TonClient, Address } from '@ton/ton'; const client = new TonClient({ endpoint: 'https://toncenter.com/api/v2/jsonRPC', apiKey: process.env.TONCENTER_API_KEY, }); const balance = await client.getBalance(Address.parse(userAddress)); useTonAddress() returns the address in two formats: raw (0:abcd...) and friendly (base64url, bounce/non-bounce). For display — friendly. For comparison in code — raw or normalized via Address.parse().toString().
Comparison of TON Connect and EVM Wallets
| Characteristic | TON Connect | MetaMask (EVM) |
|---|---|---|
| Transport | Bridge + deep link | JSON-RPC directly |
| Transaction sending | Message via bridge | RPC call |
| Works without node | Yes (bridge buffers) | No |
| Integration complexity | Medium (TL-B cells) | Low (ABI) |
| Transaction speed | 3-5 seconds | 12-15 seconds |
TON Connect wins on speed and autonomy, but requires more attention to message format. In practice, this saves up to 40% of time on each transaction due to no need to wait for node confirmation.
What’s Included in Tonkeeper Integration?
| Stage | Result |
|---|---|
| Setting up manifest.json | Correct file on HTTPS |
| Connecting bridge (own or public) | Working channel |
| Sending TON transactions | sendTransaction function |
| Jetton support | Token transfers via TL-B |
| Reading balances | TonClient integration |
| Documentation | API spec for your team |
We also train developers in working with TON Connect and provide support during the testing phase. Get a consultation on integration — we will evaluate your task for free within a day.
Time Estimates
Basic TON Connect integration (connection + sending TON) — half a day. With Jetton transfers and balance reading — 1-2 days. A full wallet screen with transaction history via TonAPI — 2-3 days.
Contact us to discuss your project. Order a turnkey TON Connect integration — get a ready-made solution with compatibility guarantee.







