Нюансы разработки бизнес-приложения на платформе Telegram Mini Apps: что я понял про Telegram как платформу
Примеры кода в серии — на C#/.NET, потому что так написан наш прод. Но всё описанное — про механику Telegram, а не про язык: то же самое собирается на Node, Python или Go без изменений. Собственно, ради этой переносимой механики статья и написана.
О чём статья? Мы вайб-кодингом построили мост из Telegram в Google Meet, Zoom и другие сервисы видеовстреч — и набили все шишки, которые можно набить о miniapp при разработке бизнес-приложения. В этой статье — четыре реальных лайфхака, которые стопроцентно пригодятся вам при написании любого бизнес-приложения на Telegram miniapp. Вот некоторые из них:
- готовый блок правил для памяти агента — ограничения веб-движка Telegram плюс требования каталогов (копируется в CLAUDE.md как есть);
- функция «где я?» — платформа и режим, без которой каждая страница будет полем чудес;
- туннель с первого дня — приём, который превращает деплой-на-каждый-чих в итерации по секундам;
- как хранить состояние между вызовами бота, miniapp и внешним браузером;
- бот, который «звонит» как телефон;
- и другие.
А это вся серия:
- Часть 1 (вы здесь) — история продукта и честный вердикт Telegram как платформе для бизнес-приложений: что дёшево, что больно, что прописать агенту до первой строчки кода.
- Часть 2 — механизм сессий: как передать параметры из инлайн-бота в miniapp, а потом прочитать их во внешнем браузере; аутентификация, обратная связь в чат и как не словить бан за редактирование сообщений.
- Часть 3 — UX-хаки: бот, который «звонит» как телефон, онбординг-воронка одним JSON-файлом и почему ссылки надо готовить до клика.
С чего всё началось
Звонки в Telegram работают — но именно как звонки: голос, видео, положил трубку. Встречи — другой жанр, и он в Telegram почти не развит. А вот в Google Meet и Zoom вокруг встречи выросла целая экосистема: транскрибация, AI-саммари, запись, расширения, интеграции с календарями и CRM. Когда разговор рабочий — хочется именно встречу, со всем этим обвесом.
Но переписка-то живёт в Telegram: там группа с коллегами, там клиент, которому «удобнее в телеге». И каждый раз, когда переписка дозревает до «давай голосом», начинается ритуал: открыть Google Meet или Zoom, создать встречу, скопировать ссылку, вернуться в чат, вставить, объяснить, куда нажимать.
Идея была наглая в своей простоте: пусть ссылку создаёт бот. Прямо в чате, одной кнопкой, в том сервисе, который доступен и у меня, и у собеседника. Так появился GoosleeBot — мост из Telegram в мир видеовстреч: Google Meet, Zoom, Teams, Jitsi, FaceTime и далее по списку.
Дальше был чистый вайб-кодинг: агент, промпты, итерации. Цифры такие: первый MVP — Google Meet, Zoom и Jitsi — был готов за два дня и честно доказал, что идея работает. А потом были четыре недели доводки. И вот что важно: главным расходом времени был не код — код агент пишет быстро. Время съело множество сценариев, которые пришлось охватить и протестировать: два собеседника или группа, первый звонок или сотый, подключён ли у автора провайдер, iOS или десктоп, свой чат или чужой — и каждую комбинацию надо прогнать руками в настоящем Telegram.
Именно поэтому статья устроена не как «смотрите, какие мы молодцы», а как список вещей, которые я бы прописал агенту в память до первой строчки кода. Потому что главный урок такой: Telegram — отличная платформа для продуктивити-приложений, но её веб-движок — не браузер, а Bot API — не REST-бэкенд. Если агент этого не знает, он уверенно нагенерит красивое неработающее.
Как это выглядит для пользователя
Сценарий: в любом чате вызываешь бота, жмёшь кнопку — бот создаёт комнату у доступного провайдера и кладёт в чат кнопку «Присоединиться». Если собеседник не реагирует — бот умеет «позвонить»: слать сообщение-звонок с повтором, как настоящий входящий вызов (как это сделано — в третьей статье серии, там простой и наглый трюк).
Ни один участник не устанавливает ничего нового. В этом вся ставка: дистрибуция через чат — фича Telegram, которой нет ни у одной «нормальной» платформы.
Правила, которые нужно прописать агенту в память до старта
Это центральная часть статьи. Если вы вайб-кодите под Telegram — скопируйте этот блок в CLAUDE.md / system prompt агента как есть. Каждое правило оплачено часами отладки «а почему на айфоне не так».
Блок А. Веб-движок Telegram — не браузер
1. Никогда не использовать `100vh`. Только `viewportStableHeight` / CSS-переменную `var(--tg-viewport-height)` и подписку на событие `viewportChanged`. Что сломается: на iOS низ страницы уедет под панель, на Android клавиатура «сожмёт» экран и разложит вёрстку.
2. Никаких `window.open` и `target="\_blank"`. Только `Telegram.WebApp.openLink()` для внешних ссылок и `openTelegramLink()` для внутренних. Что сломается: на части клиентов клик молча не сделает ничего.
3. Никаких `alert` / `confirm` / `prompt`. Только `showAlert` / `showConfirm` / `showPopup`. Что сломается: то же самое — молчание вместо диалога, причём не везде, а «у некоторых пользователей», что хуже.
4. Не полагаться на cookies для авторизации в miniapp. Webview теряет их непредсказуемо. Авторизация — токеном, переданным явно (заголовок или параметр). Что сломается: пользователь «разлогинивается» между открытиями, а вы неделю ищете несуществующий баг на сервере.
5. `localStorage` — это кэш, а не хранилище. Всё важное — на сервере (или в `CloudStorage`). Что сломается: состояние пользователя внезапно обнулится, и вы об этом не узнаете.
6. Навигация «назад» — через `BackButton` Telegram, а не через history браузера. Что сломается: системная кнопка «назад» на Android закроет miniapp целиком вместо возврата на шаг.
7. Первым делом на каждой странице — определить, где ты: платформа и режим (miniapp или обычный браузер). От этого ветвятся CSS и поведение. Функция ниже.
8. Всё, по чему пользователь кликает, должно быть готово до клика. Привычная веб-схема «клик → сервер обработал → сформировал URL → редирект» в Telegram не работает: переадресации нет. Конечный URL должен лежать в кнопке уже в момент её отрисовки — то есть всю «нагрузку редиректа» надо вычислить заранее (подробный разбор — в третьей статье).
9. Тестировать минимум на трёх клиентах: iOS, Android, Desktop. Это три разных webview с разным рендером и разным поведением. «Работает у меня на десктопе» — это ноль из трёх.
Блок Б. Требования публикации — с первого дня, а не «потом отполируем»
У каталогов (и у самого Telegram, и у витрин miniapp-ов) есть требования к приложению. Переделывать под них готовый продукт — самая дорогая работа в проекте. Поэтому в память агента, жёстко:
10. Мультиязычность с первого экрана. Ни одной строки текста в разметке — всё через локаль-файлы. Язык пользователя приходит сам: `initDataUnsafe.user.language\_code`. Добавить второй язык в проект, где строки зашиты в вёрстку, — это переписать проект.
11. Тема — только через `themeParams`. Все цвета — из CSS-переменных `--tg-theme-\*`, тёмная и светлая темы обязательны, подписка на `themeChanged`. Ни одного захардкоженного цвета. Что сломается: белый текст на белом фоне у половины аудитории — и отказ каталога.
12. Каталог проверяет: языки, обе темы, все платформы. Это требования релиза, а не полировка. Агент должен считать их частью definition of done каждой страницы.
Функция «где я?» — обязательный первый кирпич
Одна и та же страница у нас открывается на iOS, Android, десктопе — и иногда просто в браузере (пользователь скопировал ссылку). CSS и поведение различаются во всех четырёх случаях, поэтому первым в проекте появился вот такой помощник:
Где это стреляет на практике:
- CSS. Отступы под шапку/низ, safe area на iOS, реакция на клавиатуру на Android — всё вешается на классы `plt-\*`.
- Редиректы. После OAuth-авторизации у Google мобильного пользователя надо вернуть в Telegram диплинком `tg://`, а десктопного — обычным `https`-редиректом на страницу. Перепутаешь — получишь либо зависший браузер, либо выброшенного из миниаппа пользователя.
- Заглушка для «не-Telegram». Если `initData` пуст — это не miniapp, и вместо приложения показываем страницу «откройте через бота».
Мелочь? Мелочь. Но без неё каждая страница превращается в поле чудес.
Лайфхак: туннель с первого дня
Telegram не умеет «localhost»: и webhook бота, и URL miniapp-а должны быть публичными HTTPS-адресами. Поэтому первым инструментом в проекте — раньше базы, раньше CI — должен стать туннель: ngrok, cloudflared, dev tunnels в Visual Studio — что угодно, дающее постоянный публичный адрес на вашу локальную машину.
Рабочий цикл получается такой: бот и miniapp настроены на адрес туннеля, код правится локально с hot reload, а проверяешь — в настоящем Telegram на настоящем телефоне, сразу. Без туннеля каждая итерация — это деплой; с туннелем — секунды. Помните про количество сценариев, которое съело четыре недели? Без туннеля это были бы не недели.
Вердикт: Telegram как платформа для продуктивити-приложений
Что дёшево — неприлично дёшево:
- Дистрибуция. Продукт распространяется пересылкой кнопки в чат. Ноль установок, ноль лендингов на старте: собеседник видит кнопку — собеседник уже пользователь.
- Аутентификация из коробки. Telegram сам подписывает данные пользователя и отдаёт их miniapp-у. Не нужно ни регистрации, ни паролей, ни «войти через Google» — нужно только правильно проверить подпись (об этом — вся вторая статья).
- Inline-механика. Бот работает в любом чате, даже там, где его нет в участниках. Это и есть «мост»: продукт живёт внутри чужих разговоров, а не ждёт пользователей у себя.
- Realtime — работает, и его нужно делать. Мы сомневались, взлетит ли SignalR (WebSocket) внутри telegram-webview. Взлетел: полноценный хаб с группами живёт в бою на всех платформах. Обновление статуса звонка прилетает в miniapp мгновенно, без перезагрузок. Fallback на polling мы держим — но как страховку, а не как основной канал. Если ваш агент предлагает «давай просто поллинг каждую секунду» — не соглашайтесь, соединение честно работает.
Что больно:
- Зоопарк клиентов. iOS, Android, Desktop, web — четыре разных Telegram с разным webview. Отсюда правило №9 и функция «где я?».
- Веб-движок с характером. Весь блок А выше — это его портрет.
- Требования каталогов. Языки и темы — не опция. Кто узнаёт об этом в конце разработки, тот переписывает вёрстку.
- Из скучного: приём апдейтов от Telegram у нас переключается флагом между webhook и polling — удобно для отладки, и это всё, что стоит знать об этой теме.
Итого: если ваш продукт — про коммуникацию, координацию или «сделать что-то не выходя из чата», Telegram даёт фору любой платформе. Плата за это — дисциплина по отношению к webview. Дисциплину можно делегировать: просто отдайте агенту правила из этой статьи.
Что дальше в серии
Часть 2 — про самое неочевидное. Инлайн-кнопка в чате — одна на всех участников, и открывает она просто ссылку. Как передать в miniapp параметры конкретного звонка? Как понять, кто именно нажал, и не дать себя обмануть? Как вернуть ответ из miniapp обратно в чат? И отдельная ловушка: часть флоу неизбежно уходит во внешний браузер (например, OAuth-авторизация у Google) — а там переменные miniapp не работают вовсе, и из контекста Telegram остаётся только то, что вы сами положили в URL. Расскажу про механизм сессий, который закрывает всё это разом — причём это не трюк для проброса параметров, а полноценный серверный аналог сессии: типизированное хранилище значений, на котором держится вся серверная логика звонка. Бонус: как редактировать сообщения в чате асинхронной очередью и не словить бан от Bot API.
Часть 3 — про фокусы. Как заставить бота «звонить» — с повторными уведомлениями, как настоящий входящий вызов (спойлер: удаляем и переотправляем сообщение). Почему ссылки нужно готовить заранее — и это не про классическое «пре-генерите URL»: в обычном вебе вы кликаете, сервер обрабатывает запрос, формирует ссылку и делает переадресацию — в Telegram эта схема не работает в принципе, редиректа нет, и всю «нагрузку редиректа» приходится вычислять заранее, до клика. Как провести пользователя по продукту JSON-файлом вместо онбординг-движка: скрипт-чат, который печатает, показывает слайды и пишет воронку в аналитику.
Всё описанное написано для Telegram, но в большей части справедливо и для MAX — механика ботов, miniapp и сессий там строится по тем же принципам. Если есть желание сделать адаптацию под MAX и российские сервисы видеовстреч — велком в личку.
Потрогать сам мост: @GoosleeBot · gooslibot.com