Найти в Дзене
Записки сисадмина

Python. MAX бот. Создаем ссылки на бота. Deeplink

Февраль начался с того, что мои наработки по телеграм ботам теряют актуальность в виду замедления мессенджера. Грустно, но такова реальность. Изначально, я думал, что этот пост будет буквально на пару слов, кода все-таки немного, но придется сначала накидать информации. Что такое deeplink в боте? Если простыми словами - это ссылка, ведущая не просто на бота, а на конкретную его функцию, да еще и передающая в нее автоматически заложенные нами данные. В отличии от телеграмма, в MAX deeplink можно создать только на один метод - начало диалога с ботом. С одной стороны, это довольно неудобное ограничение, с другой - deeplink все равно может быть использован много раз в рамках одного диалога. Подробнее вы можете почитать здесь. Для чего нам это нужно? В моем конкретном случае - как замена utm метки для определения, из какой рекламной кампании пришел пользователь. Так я смогу собирать аналитику и обрабатывать данные с ID пользователей. Как создать deeplink? Генерируете ссылку формата: https:/

Февраль начался с того, что мои наработки по телеграм ботам теряют актуальность в виду замедления мессенджера. Грустно, но такова реальность.

Изначально, я думал, что этот пост будет буквально на пару слов, кода все-таки немного, но придется сначала накидать информации.

Что такое deeplink в боте?

Если простыми словами - это ссылка, ведущая не просто на бота, а на конкретную его функцию, да еще и передающая в нее автоматически заложенные нами данные.

В отличии от телеграмма, в MAX deeplink можно создать только на один метод - начало диалога с ботом. С одной стороны, это довольно неудобное ограничение, с другой - deeplink все равно может быть использован много раз в рамках одного диалога.

Подробнее вы можете почитать здесь.

Для чего нам это нужно?

В моем конкретном случае - как замена utm метки для определения, из какой рекламной кампании пришел пользователь. Так я смогу собирать аналитику и обрабатывать данные с ID пользователей.

Как создать deeplink?

Генерируете ссылку формата:

https://max.ru/<bot>?start=<payload>

Где bot - идентификатор вашего бота, начинающийся на @, а payload - строка символов, которая придет вам в payload при открытии ссылки пользователем.

Payload в этом варианте вы создаете какой захотите.

Также советую конвертировать ссылки в QR код перед тем, как передать их пользователям.

Итак, перепишем у нашего бота функцию начала диалога:

-2

Теперь если мы перейдем по нашей ссылке, бот сразу же отправит зашитый в ссылку токен в ответном сообщении:

-3

При этом, если мы очистим историю, и просто начнем диалог, ничего не произойдет.

Поэтому вернем тот функционал, который у нас был ранее в нашем приветственном сообщении и поместим его в то условие, когда пользователь нашел бота сам, а не пришел по ссылке с нашим диплинком:

-4

Добавляем еще логики.

Токен из диплинка не несет для нашего пользователя никакой смысловой нагрузки, но очень важен для нас. А также нам важен его ID в мессенджере, мы ведь собрались собирать данные.

С одной стороны, мы можем просто сделать так:

-5

Однако, в конкретном кейсе мы мало того, что нарушаем принцип работы ботов в мессенджерах (на каждое действие должна быть реакция), так еще и нарушаем закон (пользователь должен дать разрешение на хранение и обработку персональных данных).

Поэтому делаем все по уму и по закону:

-6
@dp.bot_started()
async def bot_started(event: BotStarted):
if event.payload:
data = {'token': event.payload, 'client_max_id': event.user.user_id}
start_kb = InlineKeyboardBuilder()
start_kb.row(CallbackButton(text='Согласен', payload=json.dumps(data)))
await event.bot.send_message(
chat_id=event.chat_id,
text='Для продолжения подтвердите согласие на обработку персональных данных',
attachments=[start_kb.as_markup()])
else:
await event.bot.send_message(
chat_id=event.chat_id,
text='''Ты начал диалог с ботом. Нажми:
/start для стартового меню
/id для вывода твоего id в MAX
''')
  • Заворачиваем и токен, и user_id в отдельный json объект, как показано выше.
  • Создаем Callback кнопку с подтверждением, в которую мы запихнем эти данные (будьте осторожнее, на payload есть лимит по символам)
  • Отправим пользователю сообщение с предложением принять условия.
-7

Осталось самое простое - обработать callback.

Тут сразу покажу решение:

-8
@dp.message_callback()
async def auth_callback(callback: MessageCallback):
data = json.loads(callback.callback.payload)
requests.post(url='API нашей CRM', json=data)
await callback.answer(notification='Благодарю')
await callback.message.edit(attachments=[])
  • Мы получаем json в виде строки из callback
  • Конвертируем строку обратно в json
  • Отправляем данные куда нам нужно
  • Отвечаем на callback пользователю
  • Изменяем наше изначальное сообщение
-9
-10

Для чего это нужно:

Если мы не ответим на callback, он зависнет в состояниях нашего бота. Что есть нехорошо и неправильно.

Также пользователь должен узнать, что не было никаких сбоев и он точно нажал на эту кнопку. Поэтому мы выдаем уведомление.

Отвечаем мы на callback строго перед тем, как изменяем сообщение (по личному опыту - есть баги мессенджера)

После ответа на callback мы передаем в сообщение пустые вложения, чтобы удалить клавиатуру. Не удалите - будет проблема с повторным нажатием, баг с пустым payload в callback после перезапуска и т.д.

Весь код из статьи как обычно выложил на своем github.