Что это
Мини-приложение — это ваша веб-страница, которая открывается поверх чата с ботом. Пользователю не нужно ничего устанавливать и входить: Clouchat передаёт странице подписанные данные о пользователе и чате, тему оформления и размеры окна.
Подходит для магазинов, записи на услуги, форм, личных кабинетов и игр. Приложение работает в изолированном окне без доступа к аккаунту и данным Clouchat.
Домены
Сначала укажите домены приложения в «Моих ботах» — до 10 на бота. Clouchat откроет только адрес https:// на одном из этих доменов или их поддоменов. IP-адреса, внутренние зоны и домены Clouchat указать нельзя. Если домены изменились, кнопки со старыми адресами перестают открываться.
Способы запуска
| Откуда | Что получает приложение | Как вернуть результат |
|---|---|---|
Кнопка web_app под сообщением | initData с query_id | сервер бота вызывает answerWebAppQuery, сообщение уходит в чат от пользователя «через бота» |
| Кнопка меню | initData с query_id | answerWebAppQuery |
Кнопка web_app в клавиатуре вместо системной | initData без query_id | Clouchat.WebApp.sendData — один раз, до 4096 байт; бот получает message.web_app_data |
Ссылка ?startapp= и меню вложений | initData с start_param | answerWebAppQuery |
При первом запуске приложения бота Clouchat спрашивает у пользователя разрешение.
Подключение
Подключите скрипт моста в <head> страницы до своих скриптов. Он создаёт объект window.Clouchat.WebApp.
<script src="https://web.clouchat.org/clouchat-web-app.js"></script>
<script>
const app = window.Clouchat.WebApp;
app.ready();
app.expand();
document.body.style.background = app.themeParams.bg_color || "#ffffff";
app.MainButton.setText("Оформить заказ");
app.MainButton.onClick(async () => {
app.MainButton.showProgress();
await fetch("/api/order", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ initData: app.initData, items: cart }),
});
app.close();
});
app.MainButton.show();
</script>
Проверка данных запуска
initData — строка запроса с полями query_id, user, chat_type, chat_instance, start_param, auth_date и подписью hash. Готовые валидаторы данных запуска из библиотек для ботов подходят без изменений.
Не доверяйте initDataUnsafe на сервере. Отправляйте на свой сервер строку initData целиком и проверяйте подпись токеном бота.
import hashlib
import hmac
import time
from urllib.parse import parse_qsl
def check_init_data(init_data: str, token: str, max_age: int = 3600) -> dict:
fields = dict(parse_qsl(init_data, strict_parsing=True))
received = fields.pop("hash", "")
check_string = "\n".join(f"{key}={value}" for key, value in sorted(fields.items()))
secret = hmac.new(b"WebAppData", token.encode(), hashlib.sha256).digest()
expected = hmac.new(secret, check_string.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, received):
raise PermissionError("bad signature")
if time.time() - int(fields["auth_date"]) > max_age:
raise PermissionError("init data expired")
return fields
Ключ проверки — HMAC-SHA256 токена бота с ключом "WebAppData"; подпись — HMAC-SHA256 строки из отсортированных пар ключ=значение, соединённых переводом строки.
Объект Clouchat.WebApp
| Поле или метод | Назначение |
|---|---|
initData, initDataUnsafe | данные запуска: строка для сервера и разобранный объект для интерфейса |
version, platform, isVersionAtLeast() | версия моста и платформа клиента |
themeParams, colorScheme | цвета темы Clouchat и светлая или тёмная схема |
ready(), expand(), close() | готовность, раскрытие на всю высоту, закрытие |
MainButton | главная кнопка внизу: setText, show, hide, enable, disable, showProgress, setParams, onClick |
BackButton | кнопка «Назад» в шапке: show, hide, onClick |
HapticFeedback | impactOccurred, notificationOccurred, selectionChanged |
CloudStorage | хранилище ключ–значение на пользователя и бота |
sendData() | отправить данные боту (запуск из клавиатуры) |
openLink(), openClouchatLink() | открыть внешнюю ссылку в браузере или ссылку join.clouchat.org в Clouchat |
showPopup(), showAlert(), showConfirm() | системные окна, до трёх кнопок |
requestContact() | попросить пользователя поделиться номером |
setHeaderColor(), setBackgroundColor() | цвета шапки и фона окна |
enableClosingConfirmation() | спрашивать перед закрытием |
requestFullscreen(), exitFullscreen(), safeAreaInset, contentSafeAreaInset | полноэкранный режим и безопасные отступы |
addToHomeScreen(), checkHomeScreenStatus() | ярлык приложения на главном экране |
onEvent(), offEvent() | подписка на события |
События
themeChanged, viewportChanged, mainButtonClicked, backButtonClicked, popupClosed, contactRequested, fullscreenChanged, fullscreenFailed, safeAreaChanged, contentSafeAreaChanged, homeScreenAdded, homeScreenFailed, homeScreenChecked.
Тема
Clouchat передаёт цвета текущей темы в themeParams в формате #rrggbb: bg_color, secondary_bg_color, text_color, hint_color, link_color, button_color, button_text_color, header_bg_color, bottom_bar_bg_color, accent_text_color, section_bg_color, section_header_text_color, subtitle_text_color, destructive_text_color, section_separator_color. При смене темы приходит themeChanged.
CloudStorage
До 1024 ключей на пользователя и бота. Ключ — 1–128 символов A-Z a-z 0-9 _ -, значение — до 4096 символов. Хранилище доступно после того, как пользователь запустил мини-приложение бота.
const storage = window.Clouchat.WebApp.CloudStorage;
storage.setItem("theme", "dark", (error, saved) => {
if (error) return console.warn(error);
storage.getItem("theme", (error, value) => console.log(value));
});
Методы: setItem, getItem, getItems, removeItem, removeItems, getKeys.
Безопасность
- Проверяйте
initDataна своём сервере при каждом запросе и ограничивайте его возраст поauth_date. - Не храните токен бота в коде страницы: всё, что требует токена, делайте на сервере.
- Цены, остатки и права пересчитывайте на сервере, не доверяя данным со страницы.
- Если приложение обрабатывает персональные данные, опубликуйте свою политику обработки данных.
Методы Bot API для мини-приложений — answerWebAppQuery и setChatMenuButton — описаны в справочнике.