guides

@twa-dev/sdk: How to Build Telegram Web Apps That Actually Work

@twa-dev/sdk makes building Telegram Web Apps dramatically easier. Here's what it does, how to set it up, and when you actually need it.

Grow your business on Telegram

CRM, Outreach & Lead Research. Get started with 1-week free trial.

Grow your business on Telegram

CRM, Outreach & Lead Research. Get started with 1-week free trial.

Grow your business on Telegram

CRM, Outreach & Lead Research. Get started with 1-week free trial.

If you're building a Telegram Mini App and reading the official docs, you'll notice they reference a raw window.Telegram.WebApp object. It works — but it's verbose, untyped, and a pain to use in modern frameworks. That's where @twa-dev/sdk comes in.

The @twa-dev/sdk package is an unofficial but widely adopted TypeScript wrapper around the Telegram Web App API. It gives you full type safety, cleaner syntax, and a much better developer experience — without adding any real overhead. If you're building anything serious on Telegram Mini Apps, this is the SDK you want.

What @twa-dev/sdk Actually Does

The official Telegram Web App API is exposed through a global JavaScript object injected by the Telegram client. It works fine for simple scripts, but once you're in a React, Vue, or Svelte project, working with raw globals gets messy fast.

@twa-dev/sdk wraps that global into a typed, importable module. Here's what you get out of the box:

  • Full TypeScript types — autocomplete for every method, event, and property

  • Cleaner imports — use import WebApp from '@twa-dev/sdk' instead of reaching for window.Telegram.WebApp

  • Reactive-friendly — plays nicely with React, Vue, and other component-based frameworks

  • Always in sync — the package tracks the official Telegram API, so you're not left maintaining your own type declarations

It's a thin layer. It doesn't add magic or abstract away the core API. Think of it as a strongly typed interface, not a framework.

How to Install and Set It Up

Installation takes about 30 seconds:

npm install @twa-dev/sdk
npm install @twa-dev/sdk
npm install @twa-dev/sdk

Then import it wherever you need it:

import WebApp from '@twa-dev/sdk'
import WebApp from '@twa-dev/sdk'
import WebApp from '@twa-dev/sdk'

That's it. From here, you have access to the full Telegram Web App surface — user data, theming, buttons, popups, haptics, and more.

A minimal working example

Here's a basic React component that grabs the current user's info and signals the app is ready:

import WebApp from '@twa-dev/sdk'
import { useEffect } from 'react'

export default function App() {
  useEffect(() => {
    WebApp.ready()
    console.log(WebApp.initDataUnsafe.user)
  }, [])

  return <div>Hello, {WebApp.initDataUnsafe.user?.first_name}</div>
}
import WebApp from '@twa-dev/sdk'
import { useEffect } from 'react'

export default function App() {
  useEffect(() => {
    WebApp.ready()
    console.log(WebApp.initDataUnsafe.user)
  }, [])

  return <div>Hello, {WebApp.initDataUnsafe.user?.first_name}</div>
}
import WebApp from '@twa-dev/sdk'
import { useEffect } from 'react'

export default function App() {
  useEffect(() => {
    WebApp.ready()
    console.log(WebApp.initDataUnsafe.user)
  }, [])

  return <div>Hello, {WebApp.initDataUnsafe.user?.first_name}</div>
}

WebApp.ready() tells Telegram the app has loaded and the loading indicator can be dismissed. Always call it early. Skipping it leaves users staring at a spinner.

The Features You'll Use Most

The Telegram Web App API is broad. Here are the parts you'll reach for in almost every project:

MainButton

The MainButton is the prominent CTA button that appears at the bottom of the Mini App. You control it entirely:

WebApp.MainButton.setText('Submit Order')
WebApp.MainButton.show()
WebApp.MainButton.onClick(() => handleSubmit())
WebApp.MainButton.setText('Submit Order')
WebApp.MainButton.show()
WebApp.MainButton.onClick(() => handleSubmit())
WebApp.MainButton.setText('Submit Order')
WebApp.MainButton.show()
WebApp.MainButton.onClick(() => handleSubmit())

It's one of the most visible UI elements in a Mini App. Use it for primary actions — checkout, confirm, send — and hide it when it's not relevant to the current screen.

initDataUnsafe

This gives you the current Telegram user's data: ID, name, username, language code, and whether they have Premium. It's "unsafe" because it's client-side — always validate it on your server using initData and the bot token before trusting it for anything sensitive.

HapticFeedback

Small detail, big impact. Haptic feedback makes your app feel native on mobile:

WebApp.HapticFeedback.impactOccurred('medium')
WebApp.HapticFeedback.notificationOccurred('success')
WebApp.HapticFeedback.impactOccurred('medium')
WebApp.HapticFeedback.notificationOccurred('success')
WebApp.HapticFeedback.impactOccurred('medium')
WebApp.HapticFeedback.notificationOccurred('success')

Theme and Color Scheme

Telegram passes through the user's current theme (light/dark) and color variables. Use WebApp.colorScheme and the CSS variables Telegram injects (--tg-theme-bg-color, etc.) to match the native look without any extra config.

sendData and close

WebApp.sendData() sends a string payload back to your bot. Use it for simple form submissions where the bot needs to act on user input. WebApp.close() dismisses the Mini App — call it when a flow is complete.

@twa-dev/sdk vs Raw window.Telegram.WebApp — Which to Use?

Honestly? Use @twa-dev/sdk for any project with more than one developer or more than a weekend's worth of complexity.

  • If you're prototyping a tiny script — raw API is fine

  • If you're building in React, Vue, or any TypeScript project — use the SDK

  • If you care about catching bugs at compile time instead of runtime — use the SDK

The raw API isn't going away. But the SDK saves you from writing your own type declarations, from typos in method names, and from the kind of bugs that only show up on a user's device at 2am.

For a deeper look at how the underlying API works and what you can build with it, check out our article on the Telegram Mini App API.

Security: Don't Trust initDataUnsafe on the Server

This is the mistake that catches most people early. initDataUnsafe is client-provided data. Anyone can forge it. If you're using it to identify users on your backend, you're building on sand.

The right approach:

  1. Send the raw WebApp.initData string to your server (not initDataUnsafe)

  2. On the server, verify the HMAC signature using your bot token

  3. Only trust user data after that check passes

Telegram documents the verification algorithm in their official docs. It's not complex — a few lines in any backend language. Don't skip it. For a broader look at security considerations for Mini Apps, see our piece on Telegram Mini App security.

Building Production Telegram Apps

Once your Mini App is solid, the next challenge is connecting it to real sales and business workflows. That's where the gap between "cool demo" and "actually useful tool" shows up.

If you're building a Telegram-based sales or CRM workflow — not just a one-off Mini App — the CRMChat API is worth looking at. It lets you wire up custom Telegram integration flows: pushing leads from your Mini App into a CRM pipeline, triggering outreach sequences, or syncing conversation data without building all the infrastructure from scratch.

For broader context on how Telegram fits into a modern sales workflow, this piece on CRM Telegram integration covers the practical side well.

The Short Version

@twa-dev/sdk is the right default for anyone building Telegram Mini Apps in a modern JS/TS stack. Install it, import it, call WebApp.ready() early, validate initData on your server, and use MainButton for your primary CTAs.

The API surface is large but well-documented. You don't need to learn all of it upfront. Start with initDataUnsafe, MainButton, and sendData — that covers 80% of what most Mini Apps actually do.

Continue Reading

The latest handpicked blog articles