Mini Apps 2.0: новые возможности платформы
В ноябре 2024 года Telegram выпустил Bot API 8.0 — крупнейшее обновление платформы Mini Apps с момента её запуска. Маркетингово оно получило название Mini Apps 2.0: полноэкранный режим, ярлыки на домашний экран, геолокация, биометрия, акселерометр, гироскоп, эмодзи-статусы, подписки через Stars и обмен медиа. Чуть позже Bot API 9.0 добавил DeviceStorage и SecureStorage — персистентное локальное хранилище и секрет-стор поверх Keychain / Keystore.
Этот урок покрывает практический набор новых API, схемы версионирования (isVersionAtLeast), миграцию с Mini Apps 1.x и типичные подводные камни.
Контекст: что такое Mini Apps 2.0
Mini Apps 1.x (Bot API 6.0—7.x, 2022—2024) — это web_app-объект внутри Telegram WebView с минимальным набором примитивов: MainButton, BackButton, HapticFeedback, тема, initData, CloudStorage. Такого набора достаточно для типовых лендингов, маркетплейсов и платежей через Stars, но недостаточно для игр, нативноподобных утилит и подписок.
Mini Apps 2.0 закрывает почти все системные пробелы:
| Категория | Mini Apps 1.x | Mini Apps 2.0 |
|---|---|---|
| Окно | expand() до 90% экрана | requestFullscreen() — настоящий полный экран в портретной/ландшафтной ориентации |
| Установка | Только через бота | addToHomeScreen() — ярлык на рабочем столе устройства |
| Доступ к датчикам | Нет | LocationManager, Accelerometer, Gyroscope, DeviceOrientation |
| Биометрия | Нет | BiometricManager — Face ID / Touch ID / отпечаток |
| Кнопки | MainButton, BackButton | + SecondaryButton, SettingsButton |
| Платежи | Stars (разовые) | + рекуррентные подписки через subscription_period |
| Хранилище | CloudStorage (1024 ключа, до 4 КБ) | + DeviceStorage (5 МБ), SecureStorage (Keychain/Keystore) |
| Расширения чата | Нет | Эмодзи-статусы, shareMessage, downloadFile |
Версии и устройства
Большинство фич Mini Apps 2.0 требует Bot API 8.0+ и свежих клиентов Telegram (iOS 11.x, Android 11.x, Desktop 5.x). Проверяйте поддержку через WebApp.isVersionAtLeast('8.0') перед вызовом любого нового метода — иначе на старом клиенте получите тихий no-op или исключение.
Feature detection: version и isVersionAtLeast
Главное правило Mini Apps 2.0 — никогда не вызывайте новые методы вслепую. Используйте guard:
const tg = window.Telegram.WebApp;
console.log(tg.version); // например, "8.0"
if (tg.isVersionAtLeast('8.0')) {
// безопасно вызывать requestFullscreen, BiometricManager, LocationManager и т. д.
}
if (tg.isVersionAtLeast('9.0')) {
// DeviceStorage, SecureStorage
}
isVersionAtLeast сравнивает строку версии лексикографически по компонентам, поэтому '10.0' корректно считается старше '9.0'.
Шаблон capability detection
const supports = {
fullscreen: tg.isVersionAtLeast('8.0'),
biometry: tg.isVersionAtLeast('7.2'),
geolocation: tg.isVersionAtLeast('8.0'),
homeScreen: tg.isVersionAtLeast('8.0'),
deviceStorage: tg.isVersionAtLeast('9.0'),
};Сохраните такую таблицу в одном месте и обращайтесь к ней через флаги — легче поддерживать и тестировать.
Full-Screen Mode
В 1.x максимум, что давал API, — это expand(): окно занимало около 90% высоты экрана. В 2.0 появился настоящий полный экран — без хедера Telegram, в обеих ориентациях. Это критично для игр, видеоплееров и иммерсивных интерфейсов.
API крутится вокруг трёх методов и нескольких событий:
const tg = window.Telegram.WebApp;
// Войти в fullscreen
tg.requestFullscreen();
// Выйти из fullscreen
tg.exitFullscreen();
// Текущее состояние
console.log(tg.isFullscreen); // true | false
Дополнительно WebApp получил два состояния — isActive (приложение в фокусе) и isFullscreen — и события:
| Событие | Когда срабатывает |
|---|---|
fullscreenChanged | Успешный переход в/из полноэкранного режима |
fullscreenFailed | Запрос не выполнен (например, платформа не поддерживает) |
activated | Mini App стал активным (например, пользователь вернулся в чат) |
deactivated | Mini App ушёл в фон |
safeAreaChanged | Изменилась safe area (челка, индикатор времени и т. п.) |
contentSafeAreaChanged | Изменилась область контента внутри safe area |
Полный пример с обработкой ошибок:
tg.onEvent('fullscreenChanged', () => {
document.body.classList.toggle('is-fullscreen', tg.isFullscreen);
});
tg.onEvent('fullscreenFailed', (event) => {
// event.error: ALREADY_FULLSCREEN | UNSUPPORTED | другая строка
console.warn('Fullscreen failed:', event.error);
});
document.querySelector('#go-fs').addEventListener('click', () => {
if (!tg.isVersionAtLeast('8.0')) {
return alert('Обновите Telegram до версии с Bot API 8.0+');
}
tg.requestFullscreen();
});
Safe area обязательна
В fullscreen Telegram отдаёт всю площадь экрана, включая зоны под челкой, динамическим островом и нижней полосой жестов. Используйте CSS-переменные var(--tg-viewport-safe-area-inset-top) и аналоги, иначе UI прячется под системные элементы.
Home Screen Icon
Mini App теперь можно установить как иконку на рабочем столе устройства — получится PWA-подобный опыт без выхода из экосистемы Telegram. Запуск происходит без открытия чата с ботом, что критично для retention.
Основные методы:
// Запросить добавление на домашний экран (открывает системный диалог Telegram)
tg.addToHomeScreen();
// Проверить статус ярлыка
tg.checkHomeScreenStatus((status) => {
// status: 'added' | 'missed' | 'unsupported' | 'unknown'
console.log('Home screen status:', status);
});
События:
| Событие | Описание |
|---|---|
homeScreenAdded | Пользователь подтвердил добавление иконки |
homeScreenChecked | Пришёл ответ на checkHomeScreenStatus |
tg.onEvent('homeScreenAdded', () => {
analytics.track('home_screen_added');
});
tg.onEvent('homeScreenChecked', (event) => {
if (event.status === 'missed') {
showInstallPrompt();
}
});
iOS возвращает unknown
На Telegram for iOS checkHomeScreenStatus стабильно отдаёт unknown — система не позволяет надёжно определить, добавлен ли уже ярлык. На Android логика работает корректно. Не делайте бизнес-логику, зависящую от added на iOS.
Иконку и цвета loading screen Mini App можно настроить через BotFather (команды /newapp, /editbotinfo) или через tgWebAppHeaderColor / tgWebAppBackgroundColor.
Geolocation API: LocationManager
Mini Apps 2.0 даёт явный, обёрнутый Telegram API доступ к координатам — через LocationManager. Это не navigator.geolocation: WebView в Telegram не отдаёт браузерный геолокационный API, потому что Telegram сам контролирует разрешения и UX.
Жизненный цикл:
const lm = tg.LocationManager;
// 1. Инициализация (запрашивает поддержку у клиента)
lm.init(() => {
if (!lm.isInited) return;
// 2. Если access ранее не был дан -- открыть настройки
if (!lm.isAccessGranted && !lm.isAccessRequested) {
lm.openSettings();
return;
}
// 3. Запросить координаты
lm.getLocation((location) => {
if (location === null) {
console.warn('Доступ к геолокации не выдан');
return;
}
console.log(location.latitude, location.longitude, location.altitude);
console.log(location.course, location.speed, location.horizontal_accuracy);
});
});
Поля объекта LocationData:
| Поле | Описание |
|---|---|
latitude | Широта |
longitude | Долгота |
altitude | Высота над уровнем моря, м |
course | Направление движения, градусы |
speed | Скорость, м/с |
horizontal_accuracy | Точность по горизонтали, м |
vertical_accuracy | Точность по высоте, м |
course_accuracy | Точность направления, градусы |
speed_accuracy | Точность скорости, м/с |
Поведение на Android
На Android LocationManager.getLocation обновляется только тогда, когда другая системная служба триггерит геолокацию в фоне (например, Карты). На iOS обновления приходят примерно раз в секунду, как и ожидается. Для рилтайм-трекинга на Android закладывайте polling и явное информирование пользователя.
Security model
Доступ к геолокации выключен по умолчанию для каждого Mini App отдельно. Пользователь явно подтверждает разрешение в системном диалоге Telegram, и его можно отозвать через LocationManager.openSettings(). Никогда не пытайтесь обходить это через сторонние HTML5-API — они заблокированы.
Biometric Authentication: BiometricManager
BiometricManager — обёртка над Face ID / Touch ID на iOS и сканером отпечатка/лица на Android. Позволяет реализовать локальную авторизацию (разблокировка кошелька, подтверждение платежа) без передачи секретов на сервер.
Базовый flow состоит из четырёх шагов: init, requestAccess, authenticate, опциональная работа с токеном.
const bm = tg.BiometricManager;
// 1. Инициализация (узнаём, поддерживается ли биометрия на устройстве)
bm.init(() => {
if (!bm.isInited) return;
console.log(bm.isBiometricAvailable); // false на старых Android
console.log(bm.biometricType); // 'finger' | 'face' | 'unknown'
// 2. Запросить доступ один раз (Telegram покажет диалог)
bm.requestAccess({ reason: 'Защитить ваш кошелёк биометрией' }, (granted) => {
if (!granted) return;
// 3. Аутентифицировать пользователя (отдельный вызов на каждое действие)
bm.authenticate({ reason: 'Подтвердите перевод 100 USDT' }, (success, token) => {
if (success) {
// token -- строка, которую можно использовать как локальный proof
unlockWallet(token);
}
});
});
});
Полезные дополнительные методы:
// Сохранить серверный токен в системном Keychain через Telegram
bm.updateBiometricToken('server-issued-jwt', (saved) => { /* ... */ });
// Открыть системные настройки биометрии Telegram
bm.openSettings();
Не доверяйте success без серверной проверки
success === true лишь означает, что пользователь приложил палец/посмотрел в камеру и устройство приняло биометрию. Это не аутентификация для бэкенда. Для серверных решений всё равно используйте initData и HMAC, а биометрию — как дополнительный локальный фактор (например, разблокировка приватного ключа в SecureStorage).
Secondary Button и Settings Button
В 1.x была одна MainButton внизу экрана — удобно для CTA («Купить», «Подтвердить»), но мало для двух равнозначных действий. В 2.0 добавили SecondaryButton (вторая кнопка, рядом или над MainButton) и SettingsButton (пункт меню в шапке).
// Secondary Button
tg.SecondaryButton
.setParams({
text: 'Отмена',
color: '#FF3B30',
text_color: '#FFFFFF',
has_shine_effect: false,
position: 'left', // 'left' | 'right' | 'top' | 'bottom'
})
.show()
.onClick(() => {
history.back();
});
// Settings Button (пункт «Настройки» в context-меню Mini App)
tg.SettingsButton
.show()
.onClick(() => {
location.hash = '#/settings';
});
События:
| Событие | Источник |
|---|---|
secondaryButtonClicked | Клик по SecondaryButton |
settingsButtonClicked | Клик по «Settings» в шапке (если включено через BotFather) |
Включите Settings в BotFather
SettingsButton.show() сработает только если в BotFather для Mini App активирован пункт меню «Settings» (/setmenubutton или соответствующий пункт у /newapp). Иначе кнопка не появится и событие не придёт.
Star Subscriptions: рекуррентные платежи
В 1.x Mini Apps умели принимать только разовые платежи в Stars. В Bot API 8.0 появились подписки — автопродление каждые subscription_period секунд. На сегодня единственное допустимое значение периода — 2592000 (30 дней), то есть месячная подписка.
Создание ссылки на подписку (со стороны бота, серверный код):
// Bot API
await bot.createInvoiceLink({
title: 'Pro план',
description: 'Расширенная аналитика и приоритетная поддержка',
payload: 'sub_pro_v1',
currency: 'XTR', // обозначение Telegram Stars
prices: [{ label: 'Pro', amount: 250 }], // 250 ⭐ в месяц
subscription_period: 30 * 24 * 60 * 60, // 30 дней
});
Открытие инвойса из Mini App:
tg.openInvoice(invoiceLink, (status) => {
// status: 'paid' | 'cancelled' | 'failed' | 'pending'
if (status === 'paid') {
showThankYou();
}
});
Важные хуки на стороне бота:
| Update | Когда приходит |
|---|---|
pre_checkout_query | Перед списанием — бот должен подтвердить или отклонить |
successful_payment | После успешной оплаты (включая каждое автопродление) |
transaction_partner updates | Списания, возвраты, отмены через payments.cancelStarsSubscription |
Stars — единственный способ для цифровых товаров
Согласно гайдлайнам App Store / Play Store, любые платежи за цифровые товары и услуги внутри Telegram Mini App обязаны идти через Stars. Подключать Stripe, ЮKassa и т. п. для цифрового контента нельзя — бота забанят. Для физических товаров и услуг (доставка, ивенты) обычные платежные провайдеры разрешены.
Cloud Storage: ключ-значение в облаке Telegram
CloudStorage существует с Bot API 6.9, но в контексте Mini Apps 2.0 он остаётся базовым primitive для синхронизации состояния между устройствами одного пользователя — работает поверх MTProto, без своего сервера.
const cs = tg.CloudStorage;
// Записать
cs.setItem('theme', 'dark', (err, ok) => { /* ... */ });
// Прочитать
cs.getItem('theme', (err, value) => {
console.log(value); // 'dark' или '' если ключа нет
});
// Прочитать пачкой
cs.getItems(['theme', 'lang'], (err, values) => {
console.log(values); // { theme: 'dark', lang: 'ru' }
});
// Список всех ключей
cs.getKeys((err, keys) => { /* ... */ });
// Удалить
cs.removeItem('theme', (err, ok) => { /* ... */ });
cs.removeItems(['theme', 'lang'], (err, ok) => { /* ... */ });
Лимиты:
| Параметр | Значение |
|---|---|
| Максимум ключей | 1024 на пользователя на бота |
| Длина ключа | 1—128 символов, [A-Za-z0-9_-] |
| Длина значения | 0—4096 символов |
| Шифрование at rest | На стороне Telegram, прозрачно для приложения |
| Доступ | Только тот бот, который записал данные |
Не храните секреты в CloudStorage
CloudStorage доступен Telegram-серверам (хоть и приватен для других ботов). Для приватных ключей TON, JWT и подобного используйте SecureStorage (см. ниже) или сервер-side хранилище с проверкой initData.
DeviceStorage и SecureStorage (Bot API 9.0)
CloudStorage синхронизируется через сервер — это медленно и облагается лимитом 4 КБ на значение. Для офлайн-кеша и тяжёлых данных в Bot API 9.0 добавили DeviceStorage, для секретов — SecureStorage.
DeviceStorage
Аналог localStorage, но интегрирован в Telegram-клиент и переживает обновления WebView:
const ds = tg.DeviceStorage;
ds.setItem('cache', JSON.stringify(payload), (err) => { /* ... */ });
ds.getItem('cache', (err, value) => { /* ... */ });
ds.removeItem('cache', (err) => { /* ... */ });
ds.clear((err) => { /* ... */ });
Лимиты: до 5 МБ на пользователя на бота. Данные не уходят с устройства и недоступны другому боту.
SecureStorage
SecureStorage использует системный безопасный стор: iOS Keychain и Android Keystore. Значения шифруются at rest на уровне ОС, недоступны другим приложениям и сохраняются между переустановками Mini App (но не Telegram).
const ss = tg.SecureStorage;
// Поддерживается ли безопасный стор на устройстве?
ss.isSupported((err, supported) => {
if (!supported) return fallbackToServerOnly();
ss.setItem('wallet_seed', encryptedSeed, (err) => { /* ... */ });
ss.getItem('wallet_seed', (err, value) => { /* ... */ });
ss.removeItem('wallet_seed', (err) => { /* ... */ });
});
Лимит: до 10 ключей на пользователя на бота.
| Хранилище | Доступ | Лимит | Шифрование | Use case |
|---|---|---|---|---|
CloudStorage | Все устройства | 1024 × 4КБ | Telegram | Настройки, прогресс, фичефлаги |
DeviceStorage | Текущее устройство | 5 МБ | OS-level | Кеш, офлайн-данные, тяжёлый стейт |
SecureStorage | Текущее устройство | 10 ключей | Keychain/Keystore | Приватные ключи TON, JWT, секреты |
Связка BiometricManager + SecureStorage
Канонический паттерн для криптокошелька в Mini App: приватный ключ (или его обёртка) лежит в SecureStorage, разблокировку даёт BiometricManager.authenticate. Сервер в этой схеме не видит seed-фразу вообще.
Дополнительные API: датчики, эмодзи, обмен медиа
Mini Apps 2.0 включает ещё несколько менее обсуждаемых, но полезных API.
Accelerometer, Gyroscope, DeviceOrientation
Для игр и AR-эффектов:
tg.Accelerometer.start({ refresh_rate: 60 }, () => {
console.log(tg.Accelerometer.x, tg.Accelerometer.y, tg.Accelerometer.z);
});
tg.onEvent('accelerometerChanged', () => { /* читать tg.Accelerometer.* */ });
tg.onEvent('accelerometerStopped', () => { /* очистка */ });
// Аналогично: tg.Gyroscope.start(...), tg.DeviceOrientation.start(...)
Также добавили lockOrientation('portrait' | 'landscape') и unlockOrientation() — полезно в комбинации с fullscreen, чтобы поворот не ломал UI.
Эмодзи-статус
tg.requestEmojiStatusAccess((granted) => {
if (!granted) return;
tg.setEmojiStatus('5170233102089322756', { duration: 3600 }); // на час
});
Telegram Premium-пользователи могут установить эмодзи-статус прямо из Mini App (например, показывая, что они в игре или едут в такси).
Обмен медиа и документами
shareMessage(msg_id, callback) отправляет ранее сгенерированное ботом сообщение в произвольный чат — удобно для реферальных ссылок и кастомных мемов. downloadFile(params, callback) позволяет Mini App инициировать сохранение файла (PDF, аудио, картинка) в галерею пользователя.
Миграция Mini App 1.x → 2.0
Полностью переписывать приложение не нужно — 2.0 обратно совместима с 1.x. Стратегия миграции:
- Подключить актуальный
telegram-web-app.js— скрипт сам обновляется на стороне Telegram, но если вы используете bundler (@telegram-apps/sdk), обновите пакет до>=3.x(поддержка Bot API 8.0/9.0). - Ввести capability map — одна структура с
isVersionAtLeastдля всех новых фич, чтобы не разбрасывать guard’ы по коду. - Поэтапно подключать API, начиная с самых ценных для UX:
- SecondaryButton, SettingsButton — 1 час работы, заметный эффект.
- Fullscreen — если у вас игра/видео/иммерсивный UI.
- Home Screen Icon — для retention.
- BiometricManager + SecureStorage — если есть кошелёк или платежи.
- LocationManager — если есть LBS-механика.
- Star Subscriptions — если хотите рекуррентную монетизацию.
- Тестировать на iOS, Android и Telegram Desktop — поведение разное (например,
checkHomeScreenStatusна iOS, частота обновленийLocationManagerна Android).
// Пример обёртки с graceful degradation
function tryRequestFullscreen() {
const tg = window.Telegram.WebApp;
if (!tg.isVersionAtLeast('8.0')) {
// Fallback на 1.x: разворачиваем как раньше
tg.expand();
return;
}
tg.requestFullscreen();
}
Третьесторонняя валидация initData
Bot API 8.0 также позволяет третьим сторонам (например, Mini App-конструкторам) валидировать initData без знания токена бота — через схему с signature и публичным ключом Telegram. Это снимает старое ограничение, по которому SaaS-сервис обязан был хранить bot_token клиента.
Частые ошибки
- Вызов новых методов без
isVersionAtLeast— на клиентах с Bot API младше 8.0 такие вызовы выбрасывают исключение или тихо ничего не делают. Всегда проверяйте версию. - Игнорирование safe area в fullscreen — интерфейс налезает на челку и системные жесты. Используйте CSS-переменные
--tg-viewport-safe-area-inset-*. - Доверие
BiometricManager.authenticate(success)на сервере — это локальный сигнал. Серверная авторизация всё равно черезinitData+ HMAC. - Хранение приватных ключей в
CloudStorage— эти данные доступны Telegram-серверам и не зашифрованы end-to-end. ИспользуйтеSecureStorage. - Подписка через любой способ кроме Stars — App Store / Play Store требуют использовать Stars для цифровых товаров. Stripe для подписок на контент в Mini App = бан бота.
- Сборка без feature detection для подписок —
subscription_periodподдерживается только начиная с Bot API 8.0. На старых клиентах бот должен предложить разовый платёж. - Обновление
LocationManagerна Android в реальном времени — координаты приходят только когда другой сервис триггерит локацию. Для трекинга реализуйте polling или предложите пользователю открыть Карты.
Итоги
| Область | API | Версия |
|---|---|---|
| Окно | requestFullscreen, exitFullscreen, isFullscreen | 8.0 |
| Установка | addToHomeScreen, checkHomeScreenStatus | 8.0 |
| Геолокация | LocationManager.init/getLocation/openSettings | 8.0 |
| Биометрия | BiometricManager.init/requestAccess/authenticate/updateBiometricToken | 7.2 / 8.0 |
| Кнопки | SecondaryButton, SettingsButton | 8.0 |
| Платежи | createInvoiceLink({subscription_period}) + openInvoice | 8.0 |
| Хранилище | CloudStorage (стабильно), DeviceStorage, SecureStorage | 6.9 / 9.0 |
| Датчики | Accelerometer, Gyroscope, DeviceOrientation | 8.0 |
| Прочее | Эмодзи-статус, shareMessage, downloadFile | 8.0 |
Mini Apps 2.0 закрывают разрыв между web-приложением в чате и нативным приложением: пользователь получает почти полноценный нативный опыт (полный экран, ярлык, биометрия, датчики), а разработчик — единый API без необходимости публиковаться в App Store / Play Store. Связка BiometricManager + SecureStorage + Star Subscriptions особенно сильна для криптокошельков и подписочных сервисов на TON.
В следующих модулях курса мы соберём всё это в production-приложение — с TON Connect для платежей в TON, биометрической разблокировкой и подпиской через Stars.