Telegram Mini App позволяет пользователю работать с полноценным интерфейсом, не выходя из бота: смотреть каталог, собирать корзину, бронировать время или заполнять анкету. Технически это обычная веб-страница, которую Telegram открывает во встроенном браузере и которой через специальный JavaScript-объект даёт доступ к данным пользователя, цветам темы и кнопкам. Значит, для Mini App не нужен какой-то особый «сервер Telegram» — её можно разместить на хостинге, как обычный сайт. Разберём весь процесс на примере приложения для заказов пекарни из Самарканда.
Из чего состоит Mini App
Обычно Mini App состоит из двух частей. Первая — фронтенд: HTML, CSS и JavaScript, написанные на React, Vue или чистом JavaScript. Вторая — бэкенд: API, который принимает заказы, пишет их в базу и проверяет пользователя. В небольших проектах обе части живут на одном домене: например, фронтенд в корне app.misol.uz, а API по адресу app.misol.uz/api/. Такая схема избавляет от лишних проблем с настройкой CORS.
Фронтенд — это набор статических файлов, поэтому его можно разместить практически на любом хостинге. Если бэкенд написан на PHP, хватит и обычного shared-хостинга; если на Node.js или Python, для постоянно работающего процесса удобнее VPS. В примере с пекарней фронтенд собран через Vite, а бэкенд — несколько PHP-скриптов с базой MySQL.
Подготовка хостинга и HTTPS
Адрес Mini App обязательно должен быть HTTPS — обычный HTTP BotFather не примет. Поэтому первый шаг — создать поддомен и выпустить для него SSL-сертификат. На хостинге sayt.uz это делается через кабинет: добавляется поддомен, к нему подключается бесплатный сертификат Let's Encrypt, который автоматически продлевается до истечения срока. Если сертификат не продлится, у пользователей Mini App откроется белым экраном, поэтому автопродление здесь особенно важно.
После сборки фронтенда загрузите файлы из папки dist в корневой каталог поддомена. Если приложение использует маршрутизацию на стороне клиента, все неизвестные адреса нужно перенаправлять на index.html. На хостинге с Apache это делается файлом .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/api/
RewriteRule ^ index.html [L]
Фронтенд: работа с telegram-web-app.js
Связь с Telegram устанавливается через официальный скрипт, который добавляет на страницу объект window.Telegram.WebApp. Метод ready() сообщает Telegram, что приложение загрузилось, а expand() раскрывает окно на всю высоту. Главная кнопка внизу управляется через MainButton и выглядит в стиле Telegram.
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<script>
const tg = window.Telegram.WebApp;
tg.ready();
tg.expand();
tg.MainButton.setText("Оформить заказ").show();
tg.MainButton.onClick(async () => {
await fetch("/api/order.php", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Init-Data": tg.initData },
body: JSON.stringify({ items: cart })
});
tg.close();
});
</script>
Вместо того чтобы подбирать цвета вручную, используйте значения tg.themeParams. Тогда Mini App подстроится под светлую или тёмную тему пользователя и не будет выглядеть чужеродно внутри Telegram.
Самое важное: проверка initData на сервере
Фронтенд получает данные о пользователе в двух видах: объект initDataUnsafe и строку initData. Как видно из названия, первому доверять нельзя — любое значение в браузере можно подделать. Правильный путь — отправить строку initData на сервер и проверить её подпись с помощью токена бота. Согласно документации Telegram, ключ получается через HMAC-SHA256 от токена бота с ключом WebAppData, а затем этим ключом подписывается строка из отсортированных полей.
function tg_check_init_data(string $initData, string $botToken): ?array {
parse_str($initData, $data);
if (empty($data['hash'])) return null;
$hash = $data['hash'];
unset($data['hash']);
ksort($data);
$pairs = [];
foreach ($data as $k => $v) $pairs[] = $k . '=' . $v;
$secret = hash_hmac('sha256', $botToken, 'WebAppData', true);
$calc = hash_hmac('sha256', implode("\n", $pairs), $secret);
if (!hash_equals($calc, $hash)) return null;
if (time() - (int)($data['auth_date'] ?? 0) > 86400) return null;
return $data;
}
При верной подписи функция возвращает массив полей; поле user приходит в формате JSON и читается через json_decode. Проверка auth_date защищает от повторного использования старых перехваченных запросов. Токен бота должен храниться только на сервере — например, в конфигурационном файле вне веб-каталога.
Подключение к боту через BotFather
Когда приложение готово, остаётся связать его с ботом. Способов несколько, и их можно комбинировать:
- Кнопка меню: в настройках бота в BotFather настраивается кнопка меню с адресом
https://app.misol.uz. - Прямая ссылка: командой
/newappсоздаётся приложение, которым можно делиться по отдельной ссылке. - Кнопка клавиатуры: бот отправляет сообщение с кнопкой типа
web_app, и приложение открывается из конкретного диалога.
Во время тестов встроенный браузер Telegram может кешировать страницу, поэтому следите, чтобы после новой сборки в именах файлов был хеш — Vite и другие современные сборщики делают это автоматически. Для отладки загляните в официальную документацию: там описано, как включить инструменты веб-разработчика в Telegram Desktop и приложении для Android.