Legan Studio
Все статьи
~ 5 мин чтения

Тихие уведомления и sendable hours в Telegram-боте

Как использовать disable_notification, protect_content и quiet hours: бот не будит юзера ночью, не присылает спам и уважает таймзоны.

  • Telegram
  • уведомления
  • UX
  • ретеншен

Тихие уведомления — простой, но недооценённый инструмент Bot API. Один параметр disable_notification: true отключает звук и вибрацию, оставляя сообщение в чате как «прочитайте, когда удобно». Грамотное использование тихих уведомлений + сохранение тишины ночью (quiet hours) поднимает retention бота на 15–25%, потому что юзеры перестают видеть его как источник раздражения.

Параметры тишины в Bot API

Bot API даёт три механизма управления вниманием:

ПараметрЧто делает
disable_notification: trueбез звука и вибрации, без счётчика unread
protect_content: trueзапрет пересылки и сохранения
allow_paid_broadcastрасширенные лимиты для оплаченных рассылок (от 2025)

Применяются почти ко всем send* методам.

Когда отправлять тихо

Хорошие сценарии:

  • Не-критичные напоминания: «Завтра у вас бронь».
  • Дайджесты и саммари: ежедневная сводка по продажам.
  • Контент-посты в канал: без звука большинство юзеров читает с тем же CTR, но без раздражения.
  • Поздравления с праздниками — формальные, без ожидания реакции.
  • Логи и алерты в админ-чат — звуковые только для критичных, остальные тихо.

Громкие — только когда нужно немедленное действие: оплата прошла, заказ ждёт подтверждения, критический алерт.

Quiet hours: «не пиши с 22:00 до 9:00»

Bot API не имеет встроенного quiet hours — это бизнес-логика на стороне бота. Минимальная реализация:

from datetime import datetime, time
from zoneinfo import ZoneInfo

QUIET_START = time(22, 0)
QUIET_END = time(9, 0)

def in_quiet_hours(user_tz: str) -> bool:
    now = datetime.now(ZoneInfo(user_tz)).time()
    if QUIET_START < QUIET_END:
        return QUIET_START <= now < QUIET_END
    return now >= QUIET_START or now < QUIET_END


async def send_with_silence(user_id: int, text: str, **kwargs):
    user = await users.get(user_id)
    silent = in_quiet_hours(user.timezone or "Europe/Moscow")
    await bot.send_message(
        user_id, text,
        disable_notification=silent,
        **kwargs,
    )

Учёт таймзоны критичен: бот, написавший в 4:00 по местному, теряет юзера навсегда.

Как узнать таймзону юзера

Способов несколько, по убыванию точности:

  1. Mini App + JS: Intl.DateTimeFormat().resolvedOptions().timeZone → отправить в бэкенд.
  2. requestLocation: координаты → reverse-geocoding → таймзона.
  3. Спросить в боте: меню «Москва / Питер / Екб / Нск / другое».
  4. По языку клиента: user.language_code = "ru-RU" → дефолт Moscow (грубо).

Лучше всего работает Mini App: при первом открытии собрать таймзону и сохранить в профиль.

Частотные лимиты

Тихий ≠ безопасный. Если бот пишет 30 раз в день, юзер всё равно отпишется. Хорошие правила:

  • Не более 1 проактивного сообщения в день в среднем.
  • Не более 3 в неделю на одного юзера.
  • Транзакционные (ответ на действие) лимитом не считаются.
  • Между сообщениями одной серии — минимум 6 часов.

Реализация — таблица notifications_log:

CREATE TABLE notifications_log (
    user_id BIGINT,
    sent_at TIMESTAMPTZ DEFAULT now(),
    type TEXT,
    silent BOOLEAN
);
CREATE INDEX idx_notif_user_ts ON notifications_log (user_id, sent_at DESC);

Перед отправкой:

async def can_notify(user_id: int) -> bool:
    last = await db.fetchval(
        "SELECT MAX(sent_at) FROM notifications_log WHERE user_id=$1 AND type='marketing'",
        user_id,
    )
    if last and (datetime.now(UTC) - last).total_seconds() < 6 * 3600:
        return False
    return True

Опт-аут и предпочтения

Пользователь должен видеть, что управление тишиной у него:

  • Команда /notifications → меню «Все / Только важные / Тихий режим / Отключены».
  • Сохраняем выбор в профиле, бот учитывает при каждой отправке.
  • Кнопка «Меньше уведомлений» под каждым маркетинговым сообщением.
@router.callback_query(F.data == "notif:less")
async def less_notif(cb: CallbackQuery):
    await users.set_pref(cb.from_user.id, "notify_level", "important_only")
    await cb.answer("Отключили рекламные. Сервисные останутся.")

Юзер, которому дали такую кнопку, реже жмёт «Stop» в Telegram (что приравнивается к репорту).

Канал vs DM: разная стратегия

В DM тишина обычно полезна: каждое сообщение прерывает юзера, и тихие касания меньше его раздражают.

В канале наоборот — тихие посты получают на 10–15% меньше просмотров за первый час, потому что не пушат уведомление. Если пост важный — шлите со звуком; если фоновый контент 4 раза в день — тихо.

Telegram Premium и боты

Premium-юзеры могут отдельно настроить уведомления от бота: тихий чат, никаких звуков. Бот этого не видит, но имеет смысл уважать установку: если юзер нажал «Mute», не пытайтесь ловчить и отправлять с disable_notification=false для важного — это нарушение ожиданий.

Топ-5 ошибок

  1. Шлют ночью без учёта таймзоны → +30% к unsubscribe.
  2. Игнорируют префы юзера и шлют всё со звуком → жалобы и репорты.
  3. protect_content=true на маркетинге → юзер не может репостнуть скидку другу.
  4. Тихие алерты для саппорта, который должен реагировать срочно.
  5. Не считают суммарный частотный лимит → 5 уведомлений в день, отписка через неделю.

Итого

Тишина — это уважение. disable_notification + quiet hours + частотные лимиты + опт-аут = хороший бот, в котором юзер остаётся месяцами. Один параметр API и 50 строк бизнес-логики дают 15–25% к retention. Это самая дешёвая оптимизация UX, которую забывают сделать 80% разработчиков.

Частые вопросы

Как влияет disable_notification на доставку?

Никак — сообщение приходит мгновенно, как обычное. Отличие только в звуке и вибрации, плюс счётчик unread не увеличивается на пуше. Юзер увидит сообщение, когда сам откроет чат. Это идеально для дайджестов и не-срочных напоминаний.

Стоит ли использовать protect_content?

Только для контента, который не должен утекать (платные курсы, NDA-документы). На маркетинге — категорически нет: сами лишаете себя бесплатной виральности от репостов. На сервисных сообщениях (чек, бронь) — тоже не надо: юзер хочет переслать чек жене или коллеге.

Как часто можно слать пуши без отписок?

Зависит от ниши. Дейтинг — до 2 в день норма. SaaS — 3–5 в неделю. Магазин — 1–2 в неделю. Универсальное правило: следите за метрикой «отписки за 7 дней после первого пуша». Растёт — снижайте частоту. Не растёт — можно повысить.

Что важнее: тишина ночью или контент-актуальность?

Тишина. Сообщение в 7:00 утра воспринимается лучше, чем в 23:00 предыдущего дня — даже если контент менее свежий. Исключение — критичные алерты (платёж сорвался, заказ требует немедленного решения), но их в норме менее 1% всех уведомлений.

Можно ли узнать, прочитал ли юзер сообщение?

Bot API не отдаёт «прочитано» — это умеет только клиент-сессия (Telethon, Pyrogram). Аналог — следить за реакциями: если юзер взаимодействовал с сообщением (callback, ответ, реакция эмодзи) — прочитал. Если за 7 дней нет ни одной реакции — кандидат на «спящий», нужна реактивация или архив.

Как сегментировать тишину по типам уведомлений?

Введите типы: marketing, transactional, system, digest. Дайте юзеру отдельный тумблер на каждый тип. Большинство выбирает «маркетинг тихо, транзакционные со звуком». Это даёт более тонкий контроль и меньше отписок.

Что такое allow_paid_broadcast?

Это режим Bot API 2025+, где бот может слать рассылку быстрее обычного лимита 30 мсг/сек, оплачивая каждое дополнительное сообщение Stars. Полезно для крупных промо: миллион пушей за час вместо 9 часов. Стоит ~0.1 Star за сообщение сверх лимита.