Спросить ИИ
Русский RU
Перейти в Watbot

Код в приложении

Почти всё в мини-приложении собирается без кода. Когда готовых элементов и блоков не хватает, свой код можно добавить в трёх местах:

Где Когда выполняется Для чего
Блок «JavaScript» Когда сценарий дошёл до блока Действие по нажатию: скопировать текст, открыть ссылку, посчитать значение, поговорить с мостом мессенджера
Код приложения Один раз при запуске, до первого экрана, и дальше — по событиям Счётчики аналитики, свои стили, внешние виджеты
«HTML-код» — элемент или весь экран Пока экран открыт Своя вёрстка, калькулятор, виджет стороннего сервиса

Код выполняется на устройстве человека. Поэтому человек, который разбирается в браузере, может увидеть его и подделать то, что код отправляет на сервер. Не храните в коде секретные ключи и ограничивайте, какие переменные и теги код может менять, — об этом ниже.

Блок «JavaScript»

Блок из категории «Данные и логика». Когда приложение доходит до блока, оно выполняет код и идёт дальше по выходу «Выполнено» или «Ошибка».

Настройка Что задаёт
«Код» Тело асинхронной функции: пишите с await и объектом app. До 20 000 символов
«Время на выполнение, секунд» От 1 до 60, по умолчанию 10. Не уложился — сценарий пойдёт по выходу «Ошибка», а сам код может доработать в фоне
«Переменная результата» Что вернул return. Объект запишется как JSON
«Переменная ошибки» Текст ошибки — для экрана после выхода «Ошибка»
«Что может менять код» Список разрешённого — см. ниже
Настройки блока «JavaScript»Настройки блока «JavaScript»

Подстановки {{ имя }} в коде не работают: значения переменных читайте через app.variables.get().

Переменные, записанные через app.variables.set(), и изменённые теги уходят на сервер вместе с выходом блока.

«Что может менять код»

Переключатель «Менять только перечисленное» включён у нового блока. С ним сервер принимает от кода только:

  • переменные из списка «Переменные»;
  • теги из списков «Теги контакта бота» и «Теги пользователя приложения» — пустой список значит, что эти теги код не меняет вовсе;
  • переменные результата и ошибки — они разрешены всегда.

Остальное сервер отбросит и запишет в журнал ошибок «Блок отбросил записанное кодом». Если код пишет имена, которых нет в списках, настройки блока предупредят об этом и предложат «Добавить в списки».

Выключайте ограничение, только если от переменных и тегов ничего не зависит: иначе человек сможет записать себе, например, тег VIP или скидку.

Объект app

Вызов Что делает
app.variables.get('name') Значение переменной
app.variables.set('name', value) Записать переменную — уйдёт на сервер с выходом блока
app.variables.all() Все переменные объектом
app.tags.has('vip') / add('vip') / remove('vip') / all() Теги пользователя приложения — есть у каждого, даже без чат-бота
app.contact?.name Контакт чат-бота: id, name, first_name, last_name, username, phone, email, address, source, created_at, telegram_id, max_id. null, если приложение открыли не из бота
app.contact.variables.get('name') / set('name', value) Свои переменные контакта, отдельно от переменных приложения. Записанное уйдёт в контакт с выходом блока
app.contact.tags.has('vip') / add / remove / all() Теги контакта бота
app.platform Откуда открыто: telegram, max, webchat, pwa или browser
app.startParam Параметр ссылки запуска (startapp)
app.user language, name и username в мессенджере
app.device mode (ios или md), dark, standalone, width, height, userAgent
await app.toast(message) Всплывающее сообщение
await app.alert(message, title) Сообщение с кнопкой OK — ждёт, пока закроют
await app.confirm(question) Вопрос «да или нет» — вернёт true или false
app.openLink('https://…') Открыть ссылку: в мессенджере — его средствами, иначе в новой вкладке
await app.copy(text) Скопировать в буфер обмена
await app.share({title, text, url}) Системное меню «Поделиться», без него — копия ссылки
app.vibrate('success') Вибрация: light, medium, heavy, success, warning или error
app.localStorage.setItem('key', 'value') Хранилище пользователя на сервере — см. ниже
app.storage.get('key') / set / remove Хранилище на устройстве, своё у приложения
await app.sleep(500) Подождать указанное число миллисекунд
app.close() Закрыть приложение
app.telegram Telegram.WebApp как есть, вне Telegram — null
app.max Мост MAX как есть, вне MAX — null

Пример из настроек блока:

// Тема и ширина экрана — в переменные
const device = app.device
app.variables.set('theme', device.dark ? 'dark' : 'light')

if (app.platform === 'telegram') {
    app.vibrate('success')
}

// Что вернули — попадёт в переменную результата
return device.width

Ошибки кода видны в консоли браузера в предпросмотре и попадают в журнал ошибок — «Ошибка в коде JavaScript».

Код приложения

Код на всё приложение: выполняется один раз при запуске, до первого экрана, и слушает события. Открывается кнопкой «Код приложения» (значок «</>») на панели над схемой. Если код задан, значок окрашен.

В окне «Код приложения»:

  • «Код» — до 100 000 символов;
  • «Переменные, которые код может записать» — до 50 имён. Остальные переменные сервер не примет;
  • шпаргалка событий и «Пример» с кнопкой «Вставить пример».
Окно «Код приложения»Окно «Код приложения»

Код хранится в версии: новая версия и шаблон получают его копию. После сохранения открытый предпросмотр перезапускается.

События

Подписка Когда срабатывает
app.on('start', ({platform, startParam}) => {}) Приложение запустилось
app.on('screen', ({id, name, type}) => {}) Показан экран или окно поверх него
app.on('event', ({blockId, eventId}) => {}) Нажатие на кнопку, пункт или элемент — до отправки на сервер
app.on('field', ({variable, value}) => {}) Человек изменил поле ввода
app.on('error', ({message}) => {}) Приложение показало ошибку
app.on('hide', () => {}) / app.on('show', () => {}) Приложение свернули и вернули
app.on('theme', ({dark}) => {}) Сменилась светлая или тёмная тема
app.on('storage', ({key, newValue}) => {}) Код элемента «HTML» записал в localStorage
  • Подписка на start, screen и theme сразу получает текущее значение — даже если подписались после await.
  • app.on() возвращает функцию отписки: const stop = app.on(…); stop(). Есть и app.off(name, handler).
  • await app.loadScript('https://…') подключает внешний скрипт: счётчик, виджет, библиотеку. Адрес — только http:// или https://.

Остальное — как у блока «JavaScript»: app.variables, app.toast, app.alert, app.openLink, app.storage, app.localStorage, app.telegram и другие. app.contact и app.tags здесь только для чтения: менять теги — дело блоков тегов.

Переменные, записанные через app.variables.set(), уходят на сервер со следующим событием.

Пример из окна — Яндекс Метрика:

// Подключаем Яндекс Метрику
await app.loadScript('https://mc.yandex.ru/metrika/tag.js')
ym(12345678, 'init', {defer: true})

// Каждый экран — просмотр страницы
app.on('screen', ({id, name}) => {
    ym(12345678, 'hit', '/screen/' + id, {title: name})
})

// Нажатия — цели
app.on('event', ({eventId}) => {
    ym(12345678, 'reachGoal', 'click_' + eventId)
})

Ошибки кода приложения — при запуске и в обработчиках — видны в консоли и попадают в журнал ошибок с причиной «Ошибка в коде приложения» и стеком вызовов. Одна и та же ошибка записывается один раз.

«HTML-код»: элемент и экран

Свой HTML со скриптами и стилями бывает двух видов:

  • элемент «HTML-код» — в группе «Виджеты», встаёт в область экрана рядом с другими элементами;
  • экран «HTML-код» — третий вид экрана после «Стандартного окна» и «Вкладок снизу»: весь экран — ваш код, без шапки и областей. Новый такой экран сразу получает пример с кнопкой и выход next. Модальным окном его сделать нельзя.

Код работает в изолированном фрейме: сессия, данные приложения и остальной экран ему недоступны. Скрипты и стили — внутри кода. Цвет текста фрейм берёт из темы приложения.

Настройка Что задаёт
«Код» HTML до 100 000 символов
«Высота» (у элемента) «По содержимому» — подстраивается под код, в том числе когда он меняет содержимое сам; «Задать» — от 40 до 2000 пикселей, всё, что не поместится, прокручивается внутри
«Выходы» До 20. У выхода — «Ключ» (латиница, цифры, _ и -) и «Название на схеме». Выход — переход на другой блок схемы
«Переменные, которые код может записать» До 50 имён. Остальные сервер не примет
Элемент «HTML-код»: код, выходы и переменныеЭлемент «HTML-код»: код, выходы и переменные

Что доступно коду во фрейме

Вызов Что делает
app.event('next') Перейти по выходу с этим ключом
app.event('next', {name: 'value'}) Перейти и записать разрешённые переменные
app.variables.set('name', 'value') Записать разрешённую переменную сразу, без перехода: экран не меняется
localStorage.setItem('key', 'value') Хранилище пользователя на сервере — см. ниже. sessionStorage живёт, пока открыт экран
app.openLink('https://…') Открыть ссылку в браузере. Обычные ссылки <a> открываются так же
{{ name }} Подставить значение переменной прямо в код — как текст, с экранированием

На схеме код не запускается — вместо него заглушка. В редакторе экрана фрейм показывает результат и перезапускается после правки кода.

Хранилища

localStorage на сервере app.storage
Где доступно localStorage во фрейме «HTML-код», app.localStorage в блоке «JavaScript» и коде приложения Блок «JavaScript» и код приложения
Где лежит На сервере, у пользователя приложения В браузере человека
Переживает Перезапуск, очистку телефона, смену устройства в том же мессенджере Пока не очищены данные браузера
Общее Для всех элементов «HTML-код», кода приложения и блоков «JavaScript» одного приложения Своё у каждого приложения
Значения Только строки, до 100 000 символов вместе с ключами Любые значения, сохраняются как JSON

Хранилище на сервере своё у каждой площадки: у одного человека в Telegram, MAX и браузере оно разное.

Ограничения

  • Код блока «JavaScript» — до 20 000 символов, код приложения и HTML-кода — до 100 000.
  • Время на выполнение блока «JavaScript» — до 60 секунд.
  • В журнал попадает не больше 20 ошибок в минуту с одного блока.