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.







