Developing Telegram Mini Apps for Crypto Projects
Telegram Mini Apps are not just "a website in Telegram". They provide access to 900+ million users with native identity verification through Telegram account, built-in payments, and the ability to work without requiring a Web3 wallet. For crypto projects, this means onboarding without seed phrases—the biggest barrier to mass adoption.
Architecture: What's Specific to Crypto Mini Apps
A standard Telegram Mini App is a WebView with access to the Telegram SDK. For a crypto project, several layers are added:
Wallet integration options:
- TON Connect — native integration with TON wallets (Tonkeeper, MyTonWallet). Telegram actively promotes TON with its built-in @wallet bot
- EVM via WalletConnect — user opens external wallet (MetaMask Mobile) to sign
- Custodial wallet — backend generates and manages keys, user interacts through Telegram identity. Acceptable for gaming, problematic for DeFi
Choice depends on audience: if targeting crypto-native users—WalletConnect. For mainstream—TON Connect or custodial.
Initialization and Verification
Telegram sends initData when opening the Mini App—a signed JWT with user data. Backend verification is mandatory:
// Frontend: get initData
import WebApp from "@twa-dev/sdk";
const initData = WebApp.initData;
const user = WebApp.initDataUnsafe.user;
// Send to backend for verification
const response = await fetch("/api/auth/telegram", {
method: "POST",
body: JSON.stringify({ initData }),
});
// Backend: verify initData
import crypto from "crypto";
function verifyTelegramInitData(initData: string, botToken: string): boolean {
const params = new URLSearchParams(initData);
const hash = params.get("hash");
params.delete("hash");
// Sort parameters and form check string
const checkString = [...params.entries()]
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}=${v}`)
.join("\n");
const secretKey = crypto
.createHmac("sha256", "WebAppData")
.update(botToken)
.digest();
const expectedHash = crypto
.createHmac("sha256", secretKey)
.update(checkString)
.digest("hex");
return hash === expectedHash;
}
Never trust initDataUnsafe on frontend without server verification—this is data the client could manipulate.
TON Connect Integration
import TonConnect from "@tonconnect/sdk";
const connector = new TonConnect({
manifestUrl: "https://yourapp.com/tonconnect-manifest.json",
});
// tonconnect-manifest.json must be publicly accessible:
// {
// "url": "https://yourapp.com",
// "name": "My Crypto App",
// "iconUrl": "https://yourapp.com/icon.png"
// }
// Connect wallet
const walletsList = await connector.getWallets();
await connector.connect({ universalLink: walletsList[0].universalLink });
// Send transaction
await connector.sendTransaction({
validUntil: Math.floor(Date.now() / 1000) + 600,
messages: [{
address: recipientAddress,
amount: "1000000000", // 1 TON in nanotons
}],
});
UI/UX: Adapting to Telegram
Telegram provides CSS variables for adapting to user theme:
body {
background-color: var(--tg-theme-bg-color);
color: var(--tg-theme-text-color);
}
.button-primary {
background-color: var(--tg-theme-button-color);
color: var(--tg-theme-button-text-color);
}
MainButton — button at the bottom of screen, a native Telegram element:
WebApp.MainButton.text = "Confirm Transaction";
WebApp.MainButton.color = "#6366f1";
WebApp.MainButton.show();
WebApp.MainButton.onClick(async () => {
WebApp.MainButton.showProgress(true);
await sendTransaction();
WebApp.MainButton.hideProgress();
WebApp.close();
});
Haptic feedback — important for mobile UX:
WebApp.HapticFeedback.impactOccurred("medium"); // on button press
WebApp.HapticFeedback.notificationOccurred("success"); // on successful transaction
Crypto-Specific Patterns
Transaction confirmation flow — unlike browser dApps, users don't have MetaMask showing details. You must explicitly display:
- What's happening (not "Confirm", but "Buy 100 USDT for 0.05 ETH")
- Current gas fees in understandable units
- Time estimate to confirmation
Balance display — use WebApp.expand() for fullscreen mode when displaying portfolio. Mini App's small screen isn't ideal for tables.
Deep links for transactions — Telegram bot can send messages with buttons that open Mini App with prefilled transaction:
https://t.me/yourbot/app?startapp=tx_0x1234
Backend reads startParam from WebApp.initDataUnsafe.start_param and restores transaction context.
Monetization and Payments
Telegram supports Telegram Stars (internal currency) and payments through providers. For crypto projects, native TON integration through @wallet is more interesting—users can pay TON/USDT directly from chat without installing a separate app.
Tech Stack
-
Frontend: React + TypeScript,
@twa-dev/sdkfor Telegram API types -
Wallet:
@tonconnect/sdkfor TON, WalletConnect v2 for EVM - Build: Vite (lighter and faster than Next.js for Mini Apps)
- Backend: Node.js/Fastify for initData verification and business logic
- Deploy: Cloudflare Pages or Vercel—HTTPS required, Telegram mandates it
- Bot: grammy or telegraf for bot wrapper
Platform Limitations
- No window.ethereum injection support in Telegram WebView—classic MetaMask doesn't work
- Limited localStorage (use sessionStorage or backend)
- Camera/NFC APIs unavailable—can't scan QR in iframe
- Stricter Content Security Policy than browsers—check inline scripts







