Step 1: Create the bot in BotFather
Open @BotFather, send /newbot, choose a name and a username ending in bot, and save the token. The token is the secret that signs every Mini App launch, so keep it on the server only.
Then run /newapp, pick the bot, give the Mini App a title, description and a 640×360 image, and provide the HTTPS URL where the app will live. BotFather returns a direct link in the form t.me/yourbot/yourapp. You can also set the app as the bot’s menu button with /setmenubutton.
Step 2: Set up the frontend project
Any web stack works; the fastest path is React with TypeScript and the official SDK:
npm create vite@latest my-mini-app -- --template react-ts
cd my-mini-app
npm install @telegram-apps/sdk-react
If you prefer the plain script, include https://telegram.org/js/telegram-web-app.js in index.html and use window.Telegram.WebApp.
Initialize the SDK, call ready() once the first screen is rendered, and read the theme and viewport so the app matches Telegram:
import { init, miniApp, themeParams, viewport } from '@telegram-apps/sdk-react';
init();
miniApp.ready();
themeParams.bindCssVars(); // exposes --tg-theme-* CSS variables
viewport.expand();
Use the CSS variables for backgrounds and text so light and dark themes work without extra code. Mount the Main Button for the primary action and the Back Button for navigation instead of custom controls.
Step 3: Serve it over HTTPS
Telegram only loads Mini Apps from HTTPS URLs. For development, expose the Vite dev server with a tunnel:
npx cloudflared tunnel --url http://localhost:5173
Put the tunnel URL into BotFather and open the app from the bot. For production, host the built files on any static host or CDN behind Cloudflare; the backend can live elsewhere.
Step 4: Verify initData on the backend
When the app opens, Telegram passes initData: a query string with the user object, auth_date and a hash. The hash is an HMAC-SHA256 over the sorted fields using a key derived from your bot token. Verify it on every request before trusting the user ID:
import crypto from 'node:crypto';
export function verifyInitData(initData: string, botToken: string): boolean {
const params = new URLSearchParams(initData);
const hash = params.get('hash');
params.delete('hash');
const dataCheckString = [...params.entries()]
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}=${v}`)
.join('\n');
const secret = crypto.createHmac('sha256', 'WebAppData').update(botToken).digest();
const computed = crypto.createHmac('sha256', secret).update(dataCheckString).digest('hex');
return computed === hash;
}
Also check that auth_date is recent (minutes, not days) and issue your own session token after verification so the client does not resend initData forever.
Step 5: Add the companion bot
The bot handles onboarding and notifications. A minimal bot with grammY:
import { Bot, InlineKeyboard } from 'grammy';
const bot = new Bot(process.env.BOT_TOKEN!);
bot.command('start', (ctx) =>
ctx.reply('Welcome! Open the app to get started.', {
reply_markup: new InlineKeyboard().webApp('Open app', 'https://app.example.com/'),
})
);
bot.start();
Use startapp parameters in links (t.me/yourbot/yourapp?startapp=ref_123) and read them in the app via initData.start_param for referrals and deep links.
Step 6: Payments
If you sell digital goods or subscriptions inside the app, create invoices in Telegram Stars (currency: 'XTR') through the Bot API, open them from the Mini App with openInvoice, answer pre_checkout_query within 10 seconds and grant the entitlement on successful_payment. Physical goods and off-platform services can use card providers through Telegram’s invoice API or an external checkout. Crypto payments use TON Connect. Details: Telegram Stars guide and payments integration.
Step 7: Test on every client
Mini Apps behave differently on iOS, Android, Telegram Desktop, macOS and the two web clients. Check viewport changes when the keyboard opens, safe areas in fullscreen mode, the Back Button, haptics, and theme switching. Enable debug mode on desktop to open DevTools; on Android use Chrome remote debugging; on iOS use Safari’s Web Inspector with the Telegram app in debug mode.
Step 8: Launch
Set the menu button, write the bot’s description and commands, add analytics events (PostHog or Telemetree work well with Telegram), create deep links for each channel, and announce through your channels and Telegram Ads. The promotion guide covers launch tactics; marketing services if you want help.
Common mistakes
- Trusting the user object from the client without verifying the hash.
- Building a custom header or back button instead of using Telegram’s.
- Ignoring the dark theme and the user’s accent color.
- Selling digital goods with card payments on mobile (violates Telegram’s rules).
- Shipping a 3 MB bundle; Mini Apps open cold from chats and must render in under a second.
- Broadcasting to users who did not opt in, which gets the bot restricted.
If you would rather hand this to a team that has shipped dozens of Mini Apps, see Telegram Mini App development or get a quote through the cost calculator.
* All prices and ranges on this page are indicative. The final cost is calculated for each project individually and depends on the complexity of the task, the number of developers and specialists required, and the delivery timeline you set. Use the ranges to understand the typical bracket, not as a fixed offer; the fixed price is confirmed in writing after scoping. Read our pricing terms.