Если человек зашёл в ваше приложение через почту с компьютера, а основная жизнь продукта живёт в Telegram, то у вас по сути два разных аккаунта одного и того же человека, и связать их надо так, чтобы он не вводил ни паролей, ни кодов, ни прочей мути. Мы с нейросетью в Картаре сделали это через диплинк: пользователь жмёт «привязать», открывается окно с кнопкой «открыть в Telegram», бот ловит одноразовый токен из ссылки и склеивает два аккаунта в один. А чтобы человек вообще дошёл до этой кнопки, мы решили ловить его не тогда, когда он случайно долистал до низа страницы, а в тот момент, когда курсор уходит вверх к крестику вкладки, то есть на exit-intent. Вот про то, как это собиралось и зачем, я и хочу рассказать.
Зачем вообще тащить веб-юзера в Telegram
Картара — это AI-персонаж, который раскладывает и трактует расклады, и изначально она живёт как Telegram Mini App. Но люди приходят разными дверями, и часть заходит через веб по почте, вообще без Telegram. И вот тут возникает дурацкая ситуация: человек попробовал, ему зашло, он закрыл вкладку и забыл, и больше вы его не увидите, потому что напоминать о себе вам нечем — у вас нет ни его чата, ни возможности тихо лечь ему в уведомления утром.
А приложение в телефоне — совсем другая история, ведь оно напоминает о себе самим фактом своего существования на экране, да и можно слать персональные утренние расклады, которые человек открывает за кофе. Я себе это формулировал примерно так: «ваши практики всегда под рукой в телефоне в удобном приложении, плюс напоминания и персональные утренние расклады». Вот ради этого и нужен мост из веба в Telegram. Не ради галочки «у нас есть бот», а ради того, чтобы у человека был повод вернуться, и не один. Кстати, про то, как из одной Картары тихо выросло сразу два продукта — веб и Telegram Mini App, я уже отдельно рассказывал.
Как связать веб-аккаунт с Telegram-ботом через диплинк
Сам механизм привязки получился такой. Пользователь в вебе жмёт «привязать», и мы под него генерим одноразовый link-токен — короткоживущий ключ, который ничего не значит сам по себе и работает ровно один раз. Дальше открывается окно с кнопкой «открыть в Telegram», человек по ней проваливается в бота, бот видит токен в диплинке и понимает: ага, это тот самый веб-аккаунт, который надо приклеить к этому Telegram-аккаунту. По очень похожей схеме я раньше делал и вход на сайт через Telegram-бота без пароля — тот же диплинк, та же уникальная ссылка, только цель другая.
Чтобы токен нельзя было переиспользовать или дёрнуть дважды, после первого срабатывания ключ помечается как потраченный и больше не сработает. И вся операция сделана идемпотентной по ключу: если человек случайно нажал два раза, открыл ссылку повторно или у него моргнула сеть и запрос ушёл дважды, аккаунты не задвоятся и ничего не сломается, потому что повторный вызов с тем же ключом просто возвращает тот же результат. Это, кстати, та вещь, которую легко проспать на радостях «работает же», а потом ловить дубли и звонки в духе «у меня два профиля, почему».
Код тут писал Claude Code под моим управлением — я оркестрировал, держал в голове сценарии, где это может развалиться, и гонял по ним. Сам я код руками не пишу и никогда этого не скрывал, но именно на таких штуках видно, что вайбкодинг — это не «нажал кнопку и получил магию», а нормальная инженерия: одноразовость токена, идемпотентность, обработка повторов. Не подумаешь про это заранее — получишь красивую кнопку, которая в проде иногда делает не то.
Карточка «Что дальше» после расклада
Параллельно с мостом мы повесили карточку «Что дальше», которая показывается человеку сразу после того, как он завершил расклад. Логика простая: он только что получил ценность, он на пике интереса, он в моменте — и вот ровно тут уместно сказать ему, куда двигаться дальше, а не оставлять с пустым экраном и мыслью «ну и всё?». Маленькая штука, но она закрывает дыру, в которую раньше утекало внимание.
Где ловить пользователя: низ страницы или exit-intent
А вот дальше начался самый интересный спор с самим собой. Классический способ показать призыв «привяжи Telegram» — это когда человек долистал страницу до низа, и вроде логично: дочитал, значит вовлечён. Но если честно, это слабое место, потому что до низа долистывают далеко не все, и часто это происходит вообще случайно, когда человек просто крутанул колесо мыши, а не потому что он реально готов к следующему шагу.
И тут у меня родилась идея, которую я себе записал так: «может сделаем вызов этого попапа когда человек курсор уводит на вкладку браузера типа чтобы закрыть, а тут ему привяжи Telegram, не теряйся, у нас столько всего ещё». То есть ловить не долистывание, а exit-intent — момент, когда курсор резко идёт вверх, к крестику вкладки или к адресной строке. И это сигнал куда честнее: человек собрался уходить, и вот ровно в эту секунду имеет смысл сказать ему «эй, погоди, забери приложение в телефон, чтобы практики были всегда под рукой».
Почему это важнее именно для нас? Среднее время на сайте у нас — одна минута двадцать секунд, и это значит, что окно, в которое можно поймать человека, крошечное, а тратить его на сценарий «авось долистает» — роскошь, которой у меня нет. Exit-intent же бьёт ровно в тот момент, когда терять уже нечего: он всё равно уходит, так дай ему причину остаться, а не молчи в тряпочку, пока он закрывает вкладку.
Что я из этого вынес
Главный вывод даже не про код, а про то, где стоит ловушка удержания. Привязка через диплинк с одноразовым токеном — это базовая инженерия, её надо сделать аккуратно один раз: одноразовость, идемпотентность по ключу, защита от повторов, и дальше она просто работает. Это та часть, где «сделай правильно сразу» окупается, потому что чинить дубли аккаунтов задним числом — отдельный ад.
А вот триггер показа — это уже продуктовое решение, и стоит оно дороже, чем кажется, ведь именно от него зависит, увидит ли человек ваше предложение в тот единственный момент, когда он готов его принять. Долистывание до низа выглядит умно, но по факту ловит не тех и не тогда. Exit-intent при среднем времени на сайте в полторы минуты — это попытка использовать последнюю секунду внимания вместо того, чтобы надеяться на терпение, которого у людей нет.
И ещё одна мысль, которая для меня тут ключевая: удержание — это не «прислать пуш погромче», а перенести точку контакта туда, где она живёт сама. Веб закрыли и забыли, а приложение в телефоне напоминает о себе без вашего участия и даёт повод вернуться утром за персональным раскладом. Мост из веба в Telegram нужен ровно для этого — чтобы разовый заход через почту превратился в привычку, а не в ещё одну закрытую вкладку. Похожие развилки «как не потерять человека» я уже разбирал на примере приватности сессий в этой истории про Картару, и там, и тут вопрос один: вы думаете за пользователя заранее или ловите грабли потом. Я выбираю думать заранее, потому что переделывать всегда дороже.