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

Канал + бот в Telegram: автопостинг и связка

Как соединить канал и бота: автопостинг, реакции на новых подписчиков через chat_member, обсуждения в чате и аналитика — без бана и спама.

  • Telegram
  • канал
  • автопостинг
  • интеграции

Связка «канал + бот» — это базовая инфраструктура любого медиа или продуктового проекта в Telegram. Канал даёт охваты и репост, бот — персонализацию и продажи. Соединить их правильно — значит автоматически постить новости, ловить новых подписчиков в DM, модерировать обсуждения и считать единую воронку «увидел пост → написал боту → купил».

Ниже — полный технический разбор: какие права нужны боту, как работает chat_member, как настроить автопостинг с очередью, как связать комментарии и DM, и какие подводные есть с лимитами Bot API.

Зачем соединять канал и бота

Канал в Telegram — это broadcast: один источник, тысячи получателей, нет интерактива. Бот — это диалог: 1-к-1, но без естественных охватов. Связка решает обе проблемы:

  • Канал собирает аудиторию через органику, репосты, Telegram Ads.
  • Бот персонализирует касание: пишет в DM приветствие, собирает заявки, продаёт.
  • Канал прогревает контентом, бот закрывает на действие.

CR из подписчика канала в платящего юзера в боте при грамотной связке — 3–8% против 0.5–1.5% при холодной рекламе сразу на бота.

Какие права нужны боту в канале

Чтобы бот мог постить, реагировать на подписчиков и читать обсуждения:

ПравоЗачемГде включается
Post MessagesПубликовать постыSettings → Administrators
Edit MessagesРедактировать опубликованноетам же
Delete MessagesУдалять старые постытам же
Add SubscribersНе нужно ботам
Manage Voice ChatsВести голосовыепо необходимости
Be AnonymousСкрыть бота как админапо желанию

Для чтения событий о новых подписчиках нужно дополнительно подписаться на апдейт chat_member через setWebhook(allowed_updates=["chat_member", "message"]) — иначе Telegram не пришлёт его, даже если бот админ.

Автопостинг с очередью

Простейший вариант — sendMessage в момент, когда прилетел webhook от CMS. Но это плохо масштабируется: если CMS захочет опубликовать 10 постов разом, бот упрётся в Flood control (1 сообщение в секунду на канал).

Правильный паттерн — очередь на Redis или PostgreSQL и воркер с пейсингом.

import asyncio
from aiogram import Bot
from arq.connections import RedisSettings

async def post_worker(ctx, post_id: int):
    bot: Bot = ctx["bot"]
    post = await db.get_post(post_id)
    msg = await bot.send_message(
        chat_id=CHANNEL_ID,
        text=post.text,
        parse_mode="HTML",
        disable_web_page_preview=False,
        reply_markup=build_keyboard(post),
    )
    await db.mark_posted(post_id, msg.message_id)
    await asyncio.sleep(1.1)  # пейсинг под Bot API limit


class WorkerSettings:
    functions = [post_worker]
    redis_settings = RedisSettings(host="redis", port=6379)
    max_jobs = 1  # последовательная отправка в один канал

max_jobs=1 гарантирует, что в один канал не уйдут два поста одновременно. На разные каналы можно делать max_jobs=10.

Реакция на новых подписчиков через chat_member

Когда юзер подписывается на канал, прилетает апдейт chat_member:

from aiogram import Router, F
from aiogram.types import ChatMemberUpdated

router = Router()

@router.chat_member(F.chat.id == CHANNEL_ID)
async def on_member(event: ChatMemberUpdated):
    new_status = event.new_chat_member.status
    old_status = event.old_chat_member.status
    if old_status in ("left", "kicked") and new_status == "member":
        await on_subscribed(event.from_user)
    elif old_status == "member" and new_status in ("left", "kicked"):
        await on_unsubscribed(event.from_user)

Дальше в on_subscribed пытаемся написать в DM. Важно: написать первым в личку получится, только если юзер раньше нажимал /start у бота. Если нет — Forbidden: bot can't initiate conversation with a user.

Как заставить юзера разрешить DM

Есть три рабочих сценария:

  1. Кнопка под постом «Получить чек-лист в боте» с deeplink t.me/yourbot?start=lead_magnet_42.
  2. Закрытый канал по chat_join_request — юзер подаёт заявку, бот её одобряет и сразу пишет в DM (это срабатывает: подача заявки = разрешение на DM).
  3. Кнопка на закрепе «Активировать бота» с deeplink на /start.

Без явного /start от пользователя автоматическое DM не работает — это защита Telegram от спама.

Комментарии в канале и обсуждения

Если к каналу привязан чат-обсуждение (linked chat), комментарии под постом летят туда. Бот может в этом чате модерировать, отвечать, ставить реакции:

@router.message(F.is_topic_message == False, F.reply_to_message.forward_from_chat.id == CHANNEL_ID)
async def comment_handler(message: Message):
    # это комментарий к посту в канале
    if await contains_spam(message.text):
        await message.delete()
        await ban_user(message.chat.id, message.from_user.id, hours=24)

message.reply_to_message.forward_from_chat.id == CHANNEL_ID — главный признак, что сообщение в чате привязано к посту в канале.

Аналитика поста: охваты, клики, конверсия

Telegram отдаёт количество просмотров поста через getMessage (поле views) или экспорт статистики канала через @MTProxybot для каналов от 500 подписчиков. Клики по кнопкам считаются на стороне бота:

@router.callback_query(F.data.startswith("post_btn:"))
async def on_post_click(callback: CallbackQuery):
    _, post_id, btn_id = callback.data.split(":")
    await analytics.track("post_click", post_id=post_id, btn_id=btn_id, user_id=callback.from_user.id)
    await callback.answer()
    await callback.message.answer("Спасибо! Открываю...")

Финальная воронка:

ЭтапМетрикаИсточник
Просмотрviewsmessage.views
Клик по кнопкеclickscallback_query
Старт в ботеstarts/start payload
Лидleadsтаблица leads
Оплатаpaymentssuccessful_payment

Лимиты Telegram, о которых забывают

  • 30 сообщений в секунду на бота суммарно.
  • 1 сообщение в секунду в один канал/чат.
  • 20 сообщений в минуту в один и тот же канал группового чата.
  • Превышение → 429 Too Many Requests с заголовком Retry-After. Уважайте его, иначе Telegram временно банит бота.
from aiogram.exceptions import TelegramRetryAfter

try:
    await bot.send_message(CHANNEL_ID, text)
except TelegramRetryAfter as e:
    await asyncio.sleep(e.retry_after + 1)
    await bot.send_message(CHANNEL_ID, text)

Топ-6 ошибок при связке канал + бот

  1. Не подписаны на chat_member — пропускают новых подписчиков.
  2. Постят без очереди → 429 на третьем посте подряд.
  3. Пытаются написать в DM юзеру, который не запускал бота.
  4. Не различают пост в канале и комментарий в чате обсуждений.
  5. Удаляют посты по delete_messages без записи в БД — потом нечего восстановить.
  6. Размечают клики без post_id и не могут построить воронку.

Итого

Связка «канал + бот» — фундамент медийного и продуктового Telegram-проекта. Технически она держится на трёх вещах: правах бота в канале, очереди на постинг с пейсингом 1 мсг/сек и подписке на chat_member с грамотным переводом подписчиков в DM через лид-магниты. Сделайте это, и охваты канала превратятся в конкретные заявки и оплаты в боте.

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

Может ли бот писать в DM любому подписчику канала?

Нет. Telegram разрешает боту инициировать диалог только если пользователь когда-то нажимал /start у этого бота. Подписка на канал — это согласие читать канал, но не согласие на личные сообщения от бота. Универсальный обход — chat_join_request в закрытом канале: подача заявки трактуется как разрешение на DM.

Как часто можно постить, чтобы не словить бан?

Лимит Bot API — 1 сообщение в секунду в один чат и 30 в секунду суммарно. На практике посты в канал делают с интервалом 2–4 часа, чтобы не уставать аудиторию: больше 5–6 постов в день дают рост отписок 2–3% в неделю. Технических банов от Telegram при соблюдении 1 мсг/сек практически не бывает.

Как настроить автопостинг из RSS или CMS?

В боте делают эндпоинт POST /webhook/post, который принимает JSON {title, body, url, image} и кладёт задачу в очередь Redis. Воркер берёт задачу, рендерит HTML-сообщение и отправляет в канал через sendMessage или sendPhoto. С RSS работает связка n8n → Webhook → Redis или Zapier → Webhook → Redis.

Что такое linked chat и как им управлять?

Linked chat — это чат-обсуждение, привязанный к каналу. Когда выходит пост в канале, в чате автоматически появляется тред с комментариями. Бот, добавленный админом в чат, может модерировать комментарии: удалять спам, банить, ставить реакции. Привязка делается через настройки канала → Discussion → выбрать чат.

Как считать клики по кнопкам в постах канала?

Inline-кнопки с callback_data присылают callback_query боту, и вы пишете в БД {post_id, btn_id, user_id, ts}. Inline-кнопки с url= Telegram не отдаёт боту — клики по ним считаются только через переход на промежуточный URL с редиректом, где вы логируете клик и редиректите дальше. Поэтому для аналитики предпочтительны callback_data.

Можно ли удалять старые посты автоматически?

Да, метод deleteMessage работает на любых постах канала младше 48 часов. Старше — Telegram уже не даёт удалять через Bot API, нужна client-сессия (Telethon/Pyrogram) от имени админа. Перед удалением полезно помечать пост в БД как deleted_at, чтобы не пытаться его редактировать.

Как привязать UTM к посту канала?

Telegram не передаёт никаких параметров в клик по самому посту, поэтому UTM прячут в кнопках: каждый CTA → t.me/yourbot?start=post_<post_id>_<btn_id>. Бот парсит payload в /start и пишет в аналитику источник. Так вы видите, какой пост и какая кнопка реально приводят оплаты.