Как определить, запущено ли фронтенд‑приложение внутри Telegram Mini App?

Я разрабатываю фронтенд-приложение с платежной формой, которое открывается из Telegram-бота как Telegram Mini App — бот по кнопке открывает ссылку на наш фронтенд. <br/> <br/> Нужно на стороне фронтенда надёжно определить, что приложение запущено именно внутри Telegram Mini App, чтобы включить специальную часть кода для корректной работы платежной формы (особенно на iOS). <br/> <br/> По документации и обсуждениям рекомендуют проверять initData, но в моём случае это поле всегда пустая строка, и я не могу использовать его для определения среды. <br/> <br/> Используемые библиотеки: <br/> 1) <a href="https://telegram.org/js/telegram-web-app.js" rel="nofollow">https://telegram.org/js/telegram-web-app.js</a> <br/> 2) vue-tg <br/> <br/> При этом все свойства возвращают одинаковые или пустые значения независимо от того, открыт ли фронтенд в обычном браузере или внутри Telegram Mini App. Примеры: <br/> window.Telegram.WebApp.initData <br/> window.Telegram.WebApp.initDataUnsafe <br/> window.Telegram.WebApp.platform <br/> <br/> Как корректно, надёжно и кросс-платформенно (включая iOS) определить на фронтенде, что приложение запущено именно внутри Telegram Mini App, а не в стандартном браузере?
  • 16 марта 2026 г. 8:04
Ответы на вопрос 2
Короткий ответ — надёжного «универсального» способа через только клиент‑скрипт нет: telegram-web-app.js может быть подключён на любой странице и не даёт 100% гарантии, а поля initData / platform могут быть пустыми. Надёжно определить, что вы запущены именно внутри Telegram Web App, можно только комбинацией мер — и лучше всего заранее передавать явный флаг из бота (рекомендую).

Что сделать (практическое руководство)

1) Самое надёжное (рекомендуемый способ)
- Когда бот формирует кнопку/ссылку на ваш фронтенд, добавляйте в URL явный параметр, например:
  https://example.com/?tg_webapp=1
- На фронтенде проверяйте этот параметр. Это кросс‑платформенно и надежно (даже на iOS).

Пример:
const urlParams = new URLSearchParams(window.location.search);
const fromTelegramParam = urlParams.get('tg_webapp') === '1';

if (fromTelegramParam) {
  // работа внутри Telegram Web App
}

2) Надёжная «вторичная» проверка — комбинированная эвристика
Если вы не можете изменить URL на стороне бота, используйте несколько признаков вместе (чтобы сгладить особенности iOS/Android):

- наличие объекта window.Telegram && window.Telegram.WebApp
- непустое window.Telegram.WebApp.initData (или initDataUnsafe)
- window.Telegram.WebApp.platform !== 'unknown'
- document.referrer содержит 't.me' / 'telegram.me' / 'web.telegram.org'
- navigator.userAgent содержит 'Telegram' (часто бывает в UA встроенного браузера)

Пример функции, объединяющей эвристики:
function isProbablyTelegramWebApp() {
  const params = new URLSearchParams(window.location.search);
  if (params.get('tg_webapp') === '1' || params.get('from') === 'telegram_webapp') return true;

  const hasWebApp = !!(window.Telegram && window.Telegram.WebApp);
  if (!hasWebApp) return false;

  const initData = window.Telegram.WebApp.initData || '';
  const platform = window.Telegram.WebApp.platform || '';
  const ua = navigator.userAgent || '';
  const ref = document.referrer || '';

  if (initData) return true;
  if (platform && platform !== 'unknown') return true;
  if (/telegram/i.test(ua)) return true;
  if (/t\.me|telegram\.me|web\.telegram\.org/.test(ref)) return true;

  return false;
}

Замечания по надёжности:
- UA и referrer можно подделать / они могут отсутствовать (особенно на iOS).
- telegram-web-app.js сам по себе может быть загружен на странице в обычном браузере — просто наличие window.Telegram.WebApp не гарантирует, что вы внутри telegram‑контейнера.
- initData — идеальный маркер, но он может быть пустым, если веб‑приложение не было открыто через веб‑контейнер telegram (например, открыто напрямую в браузере) или из‑за особенностей клиента.

3) Безопасность и серверная валидация (для платежей)
Если вы полагаетесь на initData для аутентификации/платежей — проверяйте initData подпись на сервере согласно официальной документации Telegram (похожая валидация как у виджета Telegram Login). Никогда не доверяйте только клиентской проверке при совершении критичных операций.

Почему лучше править бота (еще раз)
- Если вы контролируете бота — добавление простого GET‑параметра в URL (или использования web_app опции в KeyboardButton) — самый простой и кросс‑платформенный способ. Это решает проблему раз и навсегда и избавляет от ненадёжных эвристик, особенно на iOS, где поведение встроенного браузера может быть специфичным.

Если нужно — могу:
- подсказать, как добавить параметр в кнопку бота (пример для Bot API / python‑telegram‑bot),
- или помочь доработать функцию детекции под ваш Vue + vue‑tg стек и кейс с iOS.
<code>initData</code> пустой потому, что бот открывает ссылку через обычную кнопку с типом <code>url</code> , а не <code>web_app</code> . Переключи на <code>web_app</code> (или <code>MenuButtonWebApp</code> , или deep link с <code>startapp</code> ) — тогда и <code>initData</code> , и <code>platform</code> начнут приходить корректно. Для детекта среды без <code>initData</code> проверяй launch-параметры в <code>location.hash</code> — при запуске как Mini App туда попадают <code>tgWebAppVersion</code> и <code>tgWebAppPlatform</code> .
Похожие вопросы