Сквозная аналитика MAX на Yandex Cloud: как связать рекламный визит с обращением и сделкой
⚠ В этой статье я просто делюсь своим практическим опытом и показываю, как решил конкретную задачу.
Ниже описан пошаговый план реализации, но это концептуальный разбор того, что подобная интеграция в принципе возможна, а не универсальная инструкция под любой бизнес.
У каждого проекта свой стек: разные коннекторы мессенджеров (Wazzup, Chat2Desk, Открытые линии), разные CRM и свои кастомные поля.
Обратите внимание: предложенный код универсален — он рассчитан не только на MAX, но и на Telegram и WhatsApp, а помимо metrika_client_id автоматически передает ещё и параметр roistat_visit.
Если какие-то из этих мессенджеров или сервисов аналитики вы не используете — самостоятельно почистите и адаптируйте код под свой проект, чтобы всё работало ровно так, как вы ожидаете.
Недавно я столкнулся с классической задачей: нужно было связать обращения из мессенджера MAX с источниками трафика на сайте UTM-метками, ClientID Яндекс Метрики и Roistat ID и передать эти данные в CRM Битрикс24.
Казалось бы, стандартная задача сквозной аналитики. Но при погружении обнаружилась проблема: готовые решения для MAX уже существуют в сценариях с ботами и мини-приложениями, где можно использовать штатные механизмы передачи параметров.
Но для моего сценария переход с сайта непосредственно в чат с менеджером в MAX с последующей передачей источника в CRM готового решения, которое закрывало бы задачу целиком, я не нашел.
В других мессенджерах подобные задачи часто решаются за счёт передачи идентификатора прямо в ссылке или первом сообщении. В MAX для ботов есть механизм start-параметров, а для шеринга текста - отдельный диплинк :share?text=...
Но в моём случае требовалось сохранить исходные данные рекламного визита и связать их именно с последующим обращением пользователя в MAX.
Поняв, что готового решения под мой сценарий нет, я решил разработать собственное. При этом не хотелось нанимать бэкендера или поднимать полноценный сервер ради одного скрипта - это дополнительные затраты и необходимость постоянного обслуживания.
Почему для этой задачи я выбрал Yandex Cloud?
1. Низкая стоимость. При небольших объёмах такой стек может полностью укладываться в бесплатные лимиты Yandex Cloud. Для Cloud Functions предоставляется 1 млн вызовов и 10 GB×hour вычислений в месяц, а для Object Storage - бесплатные лимиты на хранение и операции. Yandex Message Queue также входит в Free Tier.
2. Минимум инфраструктурного обслуживания. Не нужно поддерживать постоянно работающий сервер, обновлять ОС, следить за Docker-контейнерами и самостоятельно восстанавливать упавшие процессы.
3. Гибкость. Можно реализовать собственную логику сопоставления визита, клика по MAX и сделки в CRM.
Как я решил проблему атрибуции MAX: Логика работы
Раз я не могу передать ID в самом сообщении MAX, я решил связывать визит и сделку по временному окну:
- Фиксация визита (при входе на сайт): При загрузке страницы JS-скрипт генерирует уникальный visit_id и сохраняет полный архив сессии (UTM-метки, clientID, roistat_visit, тип устройства, реферер) в S3-бакет в папку visits/visit_id.json.
- Логирование клика (при нажатии на MAX): При клике на кнопку перехода в мессенджер скрипт отправляет легкий сигнал, где фиксирует метку времени (ts) и тот самый visit_id этого пользователя. Этот лог сохраняется в S3 в папку clicks/max_timestamp_visitId.json.
- Переход в мессенджер: Пользователь переходит в MAX и начинает диалог. Интеграция (Wazzup, Chat2Desk, Открытые линии) создает Сделку в Битрикс24 с источником MAX.
- Обработка вебхука и склейка: Битрикс24 отправляет вебхук в Yandex Cloud Function. Функция проверяет папку clicks/ (где хранятся логи только тех, кто реально кликнул на MAX, а не всех посетителей сайта), берет свежий клик, считывает зафиксированный в нем visit_id и по этому ключу забирает из visits/visit_id.json точный файл конкретного визита. После этого обработанный клик сразу удаляется из S3, исключая ошибки и повторные совпадения.
Разворачиваем бэкенд в Yandex Cloud
Шаг 1. Регистрация и активация платежного аккаунта
- Перейдите на официальный сайт https://yandex.cloud/ru и войдите под своим Яндекс ID.
- Перейдите в Консоль управления (кнопка в правом верхнем углу).
- Создайте Платежный аккаунт (Billing Account) в разделе «Биллинг».
Шаг 2. Создаем сервисный аккаунт
Для того, чтобы все функции работали без вашего участия, необходимо создать сервисный аккаунт: Перейдите в «Identity and Access Management» и создайте аккаунт
Задайте имя для сервисного аккаунта, например analytics-sa и назначьте для него следующие роли:
- storage.editor (для записи и чтения файлов S3)
- ymq.writer и ymq.reader (для работы с очередью)
- functions.functionInvoker (для вызова функций)
Создайте статический ключ доступа (Access Key / Secret Key) для этого аккаунта - он понадобится для переменных окружения.
❗ Сохраните ключ доступа в удобном месте, он пригодится на этапе создания переменных окружения Cloud Functions.
Шаг 3. Создаем очередь в Message Queue
- В левом меню консоли Yandex Cloud перейдите в раздел Message Queue.
- Нажмите «Создать очередь».
- Имя: bitrix-lookup-queue
- Тип очереди: Стандартная.
- Стандартный таймаут видимости: 30 секунд (важно: это время должна отрабатывать ваша фоновая функция №2 до того, как сообщение снова станет видимым в очереди).
- Срок хранения сообщений: 4 дня (по умолчанию).
- Время ожидания при получении: 20 секунд (по умолчанию).
Остальные параметры оставьте по умолчанию и нажмите Создать
❗ После создания откройте очередь и скопируйте её URL (он выглядит так: https://message-queue.api.cloud.yandex.net/b1g.../dj6.../bitrix-lookup-queue).
Этот URL вы подставите в переменные окружения Cloud Functions под именем YMQ_QUEUE_URL
Шаг 4. Создаем бакет в Object Storage
Для того чтобы сохранять JSON-файлы с визитами пользователей и кликами по кнопкам, нужно создать бакет в сервисе Object Storage.
Как настроить бакет:
- В консоли Yandex Cloud в левом меню перейдите в Object Storage и нажмите «Создать бакет».
- Имя бакета: Задайте уникальное имя латинскими буквами (например, analytics-data-bucket).
- Максимальный размер: Можно ограничить (например, 10 ГБ). JSON-файлы логов весят килобайты, поэтому 10 ГБ хватит на сотни тысяч визитов.
- Класс хранилища: Выберите Стандартное.
- Для раздела «Доступ» в настройках создания бакета для всех операций (чтение объектов, чтение списка объектов, чтение настроек) выберите «с авторизацией», чтобы защитить данные пользователей и UTM-метки от публичного доступа в интернете. Cloud Function будет безопасно читать и записывать файлы через секретные ключи сервисного аккаунта.
Шаг 4.1. Загружаем скрипт для будущих функций Cloud Functions в Object Storage
Yandex Cloud Functions позволяет загружать код функции напрямую из файла ZIP-архива, сохраненного в вашем бакете.
Чтобы скачать архив нажмите тут
⚠ Важно: Внутри файла index.js указаны стандартные текстовые заглушки.
Чтобы скрипт корректно записывал данные в вашу CRM, вам нужно указать ID пользовательских полей из вашего Битрикс24.
Создаем поле для Client ID Яндекс Метрики в Битрикс24: Перейдите в Битрикс24: CRM → Настройки → Настройки CRM → Настройки полей → Сделка (список общих полей).
Нажмите Добавить поле: Название: metrika_client_id (или любое удобное вам).
Показывать в фильтре: Да.
Сохраните поле, а затем нажмите на него, чтобы открыть окно редактирования.
Посмотрите на адресную строку браузера (URL). Ссылка будет выглядеть примерно так: https://project.bitrix24.ru/crm/configs/fields/CRM_DEAL/edit/UF_CRM_1773915910/
Значение UF_CRM_1773913410 — это уникальный код вашего поля в CRM.
В файле index.js найдите строку: const ymField = process.env.BITRIX_YM_FIELD || 'UF_CRM_YM_CLIENT_ID'; И замените заглушку 'UF_CRM_YM_CLIENT_ID' на полученный код поля: const ymField = process.env.BITRIX_YM_FIELD || 'UF_CRM_1773913410';
Если вам нужно передавать параметр roistat_visit, выполните аналогичную операцию: создайте поле в Битрикс24, скопируйте его ID и подставьте в строку: const roistatField = process.env.BITRIX_ROISTAT_FIELD || 'UF_CRM_ROISTAT_VISIT';
Если сервис Roistat вы не используете — просто оставьте эту строку как есть или удалите блок кода, связанный с Roistat.
После того, как вы внесли изменения в файл index.js, необходимо заархивировать файлы index.js и package.json обратно и загрузить архив в Object Storage
- Зайдите созданный бакет.
- Нажмите кнопку «Загрузить».
- Выберите ваш файл function.zip и загрузите его.
Шаг 5. Создаем функции в Cloud Functions
Теперь, когда у нас подготовлены хранилище Object Storage с архивом function.zip, очередь сообщений YMQ и сервисный аккаунт, переходим к разворачиванию бэкенда.
В нашей архитектуре используются две функции (обе поднимаются из одного и того же архива function.zip, но имеют разные точки входа и настройки):
- HTTP-приемник (index.handler): Общедоступная функция. Принимает логи визитов/кликов с сайта и быстрые исходящие вебхуки от Битрикс24.
- Обработчик очереди (index.queueHandler): Приватная фоновая функция. Запускается триггером очереди сообщений, делает паузы, ищет визиты в CRM и обогащает сделки.
Шаг 5.1. Создаем Функцию №1: HTTP-приемник (analytics-http-handler)
В левом меню Yandex Cloud перейдите в Cloud Functions и нажмите «Создать функцию».
Имя: analytics-http-handler
Среда выполнения: Node.js 22.
Способ добавления кода: выберите «Из Object Storage».
Бакет: выберите ваш бакет (созданный на шаге 4).
Объект: укажите function.zip (загруженный на шаге 4.1).
Точка входа: index.handler. Таймаут: 3–5 секунд (эта функция должна отвечать мгновенно).
Память: 128 МБ. Сервисный аккаунт: выберите созданный analytics-sa.
Важно: Переключите тумблер «Публичная функция» в положение Включено.
❗ После того как вы создадите функцию - зайдите в нее, найдите поле «Ссылка для вызова» и сохраните его значение, оно будет в формате https://functions.yandexcloud.net/YOUR_FUNCTION_ID
Эта ссылка потребуется на следующих этапах: создание исходящего вебхука в битрикс24 и использование его в скрипте который будет установлен на сайте
Шаг 5.2. Создаем функцию №2: Обработчик очереди (analytics-queue-processor)
Снова нажмите «Создать функцию».
Имя: analytics-queue-processor.
Среда выполнения: Node.js 22.
Способ добавления кода: «Из Object Storage» (укажите ваш бакет и function.zip).
Точка входа: index.queueHandler.
Таймаут: 30 секунд (функция выполняет повторные запросы в CRM, ей нужно время).
Память: 256 МБ.
Сервисный аккаунт: analytics-sa.
Важно: Тумблер «Публичная функция» оставьте Выключенным (вызывать эту функцию напрямую из интернета не нужно).
Шаг 5.3. Создаем исходящий вебхук в Битрикс24
- В Битрикс24 перейдите: Разработчикам → Другое → Исходящий вебхук.
- Адрес обработчика: укажите публичный URL вашей Функции №1 (HTTP-приемника) с добавлением /bitrix-hook на конце:https://functions.yandexcloud.net/YOUR_HTTP_FUNCTION_ID/bitrix-hook
- События: выберите из списка: Создание лида (ONCRMLEADADD), Создание сделки (ONCRMDEALADD), Обновление лида (ONCRMLEADUPDATE), Обновление сделки (ONCRMDEALUPDATE)
- Нажмите Сохранить
Шаг 5.4. Настройка переменных окружения
В настройках каждой из двух функций прокрутите вниз до блока «Переменные окружения» и добавьте следующие ключи:
Название: BITRIX_WEBHOOK_URL / Значение переменной: URL входящего вебхука из Битрикс24 (получен на шаге 5.3)
Название: BUCKET_NAME / Значение переменной: Имя вашего бакета в Object Storage
Название: YMQ_QUEUE_URL / Значение переменной: URL очереди Yandex Message Queue (получен на шаге 5.1)
Название: YC_S3_KEY_ID / Значение переменной: Key ID статического ключа сервисного аккаунта (получен на шаге 2)
Название: YC_S3_SECRET_KEY / Значение переменной: Secret Key статического ключа сервисного аккаунта (получен на шаге 2)
Название: BITRIX_YM_FIELD / Значение переменной: Код поля Битрикс24 для Client ID (например, UF_CRM_1773915910)
Название: BITRIX_ROISTAT_FIELD / Значение переменной: Код поля Битрикс24 для Roistat ID
Название: ENABLE_DEBUG_LOGS / Значение переменной: true (включает подробные логи в консоли Yandex Cloud для отладки)
Шаг 5.5. Настройка триггера для функции 2
Чтобы сообщения из очереди YMQ автоматически отправлялись на обработку в функции №2:
В консоли Yandex Cloud в левом меню перейдите в Cloud Functions → раздел «Триггеры».
Нажмите «Создать триггер».
Имя: analytics-queue-trigger
Очередь: выберите созданную ранее очередь bitrix-lookup-queue.
Сервисный аккаунт: выберите ваш сервисный аккаунт (analytics-sa).
Время ожидания: 0 минут (сообщения должны уходить на обработку без задержек).
Размер группы сообщений: 1 (каждая сделка обрабатывается отдельно сразу при появлении).
Функция: выберите Функцию №2 (analytics-queue-processor).
Сервисный аккаунт: выберите analytics-sa.
Нажмите «Создать триггер».
Шаг 6. Установка скрипта на сайт
Финальный этап — подсоединение нашего сайта к созданной экосистеме Yandex Cloud.
Скрипт устанавливается в код всех страниц сайта перед закрывающим тегом : </head>
Проверяем работу
После того как все компоненты настроены, проведите итоговое тестирование цепочки:
- Зайдите на ваш сайт в режиме Инкогнито (желательно добавить тестовую метку к ссылке, например: ?utm_source=test_yandex).
- Откройте панель разработчика браузера (клавиша F12) и перейдите во вкладку Сеть (Network).
- В списке запросов вы должны увидеть успешное обращение к вашей Yandex Cloud Function вида functions.yandexcloud.net/YOUR_FUNCTION_ID со статусом 200 OK.
- Перейдите в консоль Yandex Cloud → Object Storage → ваш бакет → папку visits/. Там должен появиться новый .json файл с сохраненной сессией и вашими UTM-метками.
- Вернитесь на сайт, нажмите кнопку перехода в MAX и напишите первое сообщение в чат компании.
- Зайдите в Битрикс24 и откройте созданную Сделку. Через пару секунд в карточке автоматически заполнятся поля UTM-меток, Client ID Метрики, а в комментариях появится системный отчет сквозной аналитики