Подробный гайд по созданию собственного чат-бота в Telegram с использованием n8n для получения статистики из вашего счетчика Яндекс Метрики.
Этот материал был специально подготовлен для онлайн-курса «n8n для маркетологов».
Перед тем, как повторять нижеприведенные шаги, вы должны использовать экземпляр n8n в n8n Cloud или же установить n8n на своем собственном сервере. Подробнее о том, как это сделать, читайте в этом руководстве. В нем я использовал решение selfhost-ai (ex. n8n-install, Автор - Yury Kossakovsky) - готовый инсталлятор для развертывания n8n Community Edition и целого набора дополнительных сервисов на собственном сервере под управлением Docker Compose.
Основные этапы настройки автоматизации, которые вам предстоит выполнить, следующие:
- создать бота в Telegram;
- получить токен доступа для работы с API Яндекс Метрики;
- создать рабочий процесс в n8n.
Давайте рассмотрим каждый шаг подробнее.
Содержание
- Импорт шаблона n8n
- 1. Создание Telegram-бота
- 2. Получение токена для Яндекс Метрики
- 3. Создание рабочего процесса n8n
#### Импорт шаблона n8n
Скачать итоговый шаблон n8n из этого руководства вы можете на моей образовательной платформе edu.osipenkov.ru, в разделе Материалы.
#### 1. Создание Telegram-бота
Подробнее про создание бота в Telegram и получение токена читайте здесь.
#### 2. Получение токена для Яндекс Метрики
Для этого используйте инструкции:
#### 3. Создание рабочего процесса n8n
Создав бота в Telegram и сохранив его chat_id и токен, а также создав приложение Яндекса и получив токен доступа для работы с счетчиками Яндекс Метрики, мы наконец можем перейти к основной части - созданию workflow в n8n.
Для этого перейдите в интерфейс своего инстанса (экземпляра) n8n и создайте новый рабочий процесс:

Create workflow
В открывшемся окне нажмите на холсте и в строке поиска введите Telegram:

Telegram Trigger
В n8n триггеры Telegram определяют, на какое именно событие внутри мессенджера будет реагировать ваш бот, чтобы запустить сценарий автоматизации.

Триггеры в Telegram
Доступны варианты:
- On callback query - срабатывает, когда пользователь нажимает на инлайн-кнопку (кнопку, прикрепленную прямо к сообщению);
- On channel post - запускает сценарий при публикации нового поста в канале, где ваш бот является администратором;
- On edited channel post - срабатывает в момент, когда кто-то редактирует уже существующий пост в канале;
- On edited message - реагирует на редактирование обычного сообщения пользователем в чате или группе;
- On inline query - активируется при использовании инлайн-режима. Это когда пользователь вводит юзернейм бота (например, @gif hello) в поле ввода любого чата, и бот должен «на лету» предложить варианты ответов (картинки, статьи и т.д.);
- On message - самый популярный триггер, срабатывающий на любое новое входящее сообщение (текст, фото, файл, стикер, голосовое) в личном чате с ботом или группе;
- On Poll Change - запускается, когда изменяется состояние опроса (например, кто-то проголосовал или опрос был остановлен). Бот должен быть автором опроса или админом чата;
- On pre checkout query - срабатывает на этапе финальной проверки платежа в Telegram. После того как пользователь нажал «Оплатить», Telegram отправляет этот запрос боту, чтобы тот подтвердил наличие товара и актуальность цены перед списанием денег;
- On shipping query - активируется, когда пользователь оформляет заказ через платежную систему Telegram и выбирает адрес доставки. Триггер нужен, чтобы рассчитать стоимость доставки на основе указанного адреса.
Для нашего бота подойдет самый популярный триггер - On message, который срабатывает на любое новое входящее сообщение. Выберите его:

Telegram Trigger - On message
В настройках триггера нажмите на кнопку Set up credential, чтобы добавить данные от вашего чат-бота Telegram:

Credential - Set up credential
В открывшемся окне в поле Access Token добавьте токен, который бот прислал после его создания (см. выше):

Учетные данные (Credential) для Telegram
Сохраните свои учетные данные, нажав на кнопку Save.
После этого вернитесь в настройки триггера Telegram. Вы должны увидеть, как в разделе Credential подставились ваши учетные данные от бота Telegram:

Credential - Telegram account
Теперь мы должны немного изменить настройки триггера. Для этого в разделе Trigger On раскройте список и выберите дополнительно Callback Query:

Trigger On - Callback Query
Поскольку мы планируем создать чат-бота для получения статистики из Яндекс Метрики и для ввода настроек использовать inline-кнопки, то нам обязательно нужно выбрать этот вариант, поскольку именно триггер On callback query срабатывает, когда пользователь нажимает на инлайн-кнопку (кнопку, прикрепленную прямо к сообщению).

Trigger On - Message и Callback Query
На этом настройки триггера Telegram завершены. Теперь нужно продумать дальнейшую логику работы нашего рабочего процесса и правила, по которым бот в Telegram будет нам отвечать. Для этого я предлагаю использовать узел-действие (action node) Switch, который позволяет создать несколько развилок/ветвлений и выполнять разные сценарии в зависимости от выбранного действия на предыдущем шаге.
Как правило, первую команду, которую вводят боту в Telegram, является команда /start. Но это только в самом начале. Далее вы уже можете общаться с ним без всяких вводных сообщений. Таким образом, для активации следующих шагов нам необходимо предусмотреть три правила:
- start - если пользователь (вы) написал в чате команду /start, бот показывает нам меню с кнопкой получения отчета по Яндекс Метрике (report);
- report - после нажатия на inline-кнопку весь основной процесс будет проходить далее по этому узлу (ввод данных счетчика Яндекс Метрики и получение итогового отчета);
- Fallback - если пользователь написал в чате любое другое сообщение (ни /start, и ни выбрал создание отчета), то бот отправляет подсказку по созданию отчета.
Давайте реализуем такие правила. Для этого рядом с триггером Telegram нажмите на иконку + и в окне выбора следующего узла введите в поиске Switch. Выберите этот узел:

Switch
Для того, чтобы настроить правила в этом узле, нам необходимо понять, какие данные и в каком виде приходят в n8n от предыдущего узла (триггера Telegram) в текущий, чтобы дальше настроить правила распределения по веткам Switch. Для этого нажмите слева (в разделе Input) на кнопку Execute previous nodes:

Execute previous nodes
Вернитесь в своего бота Telegram и напишите что-нибудь в чат. Например, выполните команду /start. После этого во входных данных узла должен появиться результат этого сообщения.

Результат отправленного сообщения
Теперь мы можем использовать схему полученных данных для составления правил в Switch. Первое правило - это ветка start. Выбрав в настройках узла режим Rules (по правилам), перетащите в Routing Rules в value1 поле text из объекта message. В ней хранится текст сообщения пользователя в чате:

Перетащите поле text в value1
Если перетащить из схемы именно это поле, в условии получится что-то вроде:
<table><tbody><tr><td data-settings="show"><div><p>1</p></div></td><td><div><p><span>{</span><span>{</span><span> </span><span>$</span><span>json</span><span>.</span><span>message</span><span>.</span><span>text</span><span> </span><span>}</span><span>}</span></p></div></td></tr></tbody></table>
А поскольку эта ветка будет работать только с командой /start, то в поле value2 вставьте значение /start:

/start в value2
Условие в правиле можно оставить таким - is equal to (равно). При желании вы можете переименовать название самой ветки в Rename Output, указав свое собственное значение в поле Output Name. Например, написать просто start:

Переименование ветки Switch (Rename Output)
Закройте пока настройки узла и вернитесь на холст. Ваш рабочий процесс должен выглядеть примерно так. Он будет состоять всего из одной ветки start:

Промежуточный вариант workflow
Для настройки ее логики нажмите на иконку + и в строке поиска введите Telegram. Выберите Action - Send a text message:

Action - Send a text message
Нам нужно, чтобы после выполнения команды /start бот отправлял нам сообщение с inline-кнопкой, с помощью которой мы можем создать отчет Яндекс Метрики.
В настройках этого узла проверьте, чтобы:
- в разделе Credential автоматически подставили ваши учетные данные от аккаунта Telegram;
- в меню Resource был выбран Message;
- в настройках Operation было выбрано Send Message.

Настройки узла-действия Send a text message
В поле Chat ID перетащите значение переменной id, которая является частью объекта chat внутри другого объекта message (message.chat.id), чтобы оно автоматически подставилось:

Заполнение поля Chat ID
Если перетащить из схемы именно это поле, в условии получится:
<table><tbody><tr><td data-settings="show"><div><p>1</p></div></td><td><div><p><span>{</span><span>{</span><span> </span><span>$</span><span>json</span><span>.</span><span>message</span><span>.</span><span>chat</span><span>.</span><span>id</span><span> </span><span>}</span><span>}</span></p></div></td></tr></tbody></table>
В поле Text напишите текст сообщения бота, которое будет отображаться вместе с inline-кнопкой. Например: Привет! Нажми на кнопку, чтобы получить отчет Яндекс Метрики:

Сообщение для бота
Чтобы добавить кнопку в сообщение, в разделе Reply Markup из выпадающего списка выберите Inline Keyboard:

Reply Markup - Inline Keyboard
Так можно показать кнопку и передать скрытые данные через дополнительные настройки (callback_data).
Выбрав Inline Keyboard, нажмите на кнопку Add Keyboard Row, а затем на Add Button. В поле Text введите название кнопки. Например, 📊 Отчет по Яндекс Метрике:

Название inline-кнопки
В Additional Fields нажмите кнопку Add Field и выберите из выпадающего списка Callback Data. Это обязательный шаг, без которого ваша основная логика получения статистики из Яндекс Метрики не будет работать:

Add Field - Callback Data
Callback Data - это скрытое значение, которое отправляется вашему чат-боту при нажатии inline-кнопки. Пользователь его не видит, но оно дает возможность далее выполнять определенные действия в боте по заданному сценарию. В нашем workflow это нужно, чтобы узел Switch понял, какую кнопку нажали, и запустил нужную ветку.
В моем примере поле Callback Data имеет значение ym_report, но вы можете задать любое другое. Главное, чтобы оно дальше использовалось в рабочем процессе. Если вы работаете по моему шаблону n8n, это значение лучше не менять:

Callback Data - ym_report
На этом настройка узла-действия Telegram по ветке start завершена. Вы можете попробовать запустить этот узел, чтобы посмотреть, как сообщение с inline-кнопкой будет выглядеть в боте Telegram:

Настроенное сообщение с inline-кнопкой
Если вам не нравится системное уведомление This message was sent automatically with n8n, вы можете его скрыть. Для этого вернитесь в настройки узла и в самом низу в настройках Additional Fields добавьте поле Add Field - Append n8n Attribution:

Add Field - Append n8n Attribution
И просто отключите эту настройку:

Отключите опцию Append n8n Attribution
Теперь сообщения будут приходить без этого уведомления.
Закройте настройки узла Telegram. Нажмите снизу кнопку Execute workflow, чтобы выполнить тестовый запуск вашего рабочего процесса:

Execute workflow
Откройте вашего бота и нажмите на inline-кнопку 📊 Отчет по Яндекс Метрике. Вы должны увидеть, как по цепочке запустилось несколько узлов и выполнение остановилось на Switch:

Процесс остановился на Switch, пока следующая ветка не настроена
Примечание: если меню еще не было: отправьте /start, а затем нажмите inline-кнопку 📊 Отчет по Яндекс Метрике.
Откройте настройки узла Switch. Для создания еще одного правила внутри Switch нажмите на кнопку Add Routing Rule:

Добавить новое правило
Теперь вам нужно заполнить правила для основной ветки, по которой и будет происходить вся логика работы вашего чат-бота Telegram - создание отчета с заданными параметрами и получение статистики из Яндекс Метрики.
На предыдущем шаге в Callback Data кнопки мы указали ym_report. Чтобы Switch направил выполнение в нужную ветку, добавьте новое правило - из входных данных возьмите поле data объекта callback_query (callback_query.data) и перетащите его в value1:

Перетащите поле data в value1 нового правила
Именно в этом поле приходит значение Callback Data нажатой кнопки. В value2 укажите ym_report - то же скрытое значение, которое вы задали кнопке в узле Telegram. Если вы его изменили, то добавьте свое. В правиле можно оставить условие is equal to (равно), но саму ветку переименовать, указав в Rename Output - Output Name собственное имя. Например - report.
Таким образом, итоговое второе правило, где будет происходить вся основная работа вашего workflow n8n, выглядит так:

Настройки основного правила в узле Switch
Нам осталось добавить последнее правило, которое бы срабатывало в боте тогда, когда пользователь (или вы) не выполнил команду /start и не нажал на inline-кнопку (ym_report), а сделал что-то другое. Для этого в настройках узла Switch в разделе Options нажмите на кнопку Add option и добавьте Fallback Output:

Options - Add option - Fallback Output
В представленном списке выберите Extra Output:

Fallback Output - Extra Output
Fallback Output - это запасной выход Switch. Сюда попадает все, что не подошло ни под одно правило (в нашем случае - не /start и не ym_report), а это Extra Output - вариант этого запасного выхода. n8n создает отдельную дополнительную ветку Fallback (ее можно переименовать, но мы этого делать не будем).

Созданные правила и ветки в узле Switch
Именно на нее мы повесим узел с подсказкой, который будет напоминать пользователю (нам) о том, как запустить рабочий процесс по основному сценарию и получить статистику из счетчика Яндекс Метрики.
Для этого рядом с дополнительной веткой Fallback нажмите на иконку + и в строке поиска введите Telegram. Выберите Action - Send a text message:

Action - Send a text message
В настройках этого узла укажите Chat ID. Обновления Telegram бывают разными, поэтому идентификатор чата может лежать в разных полях: у текстового сообщения - в message.chat.id, у нажатия кнопки - в callback_query.message.chat.id. Ветка Fallback как раз может получить и то, и другое. Поэтому здесь лучше использовать конструкцию:
<table><tbody><tr><td data-settings="show"><div><p>1</p></div></td><td><div><p><span>{</span><span>{</span><span> </span><span>$</span><span>json</span><span>.</span><span>message</span><span>.</span><span>chat</span><span>.</span><span>id</span><span> </span><span>||</span><span> </span><span>$</span><span>json</span><span>.</span><span>callback_query</span><span>.</span><span>message</span><span>.</span><span>chat</span><span>.</span><span>id</span><span> </span><span>}</span><span>}</span></p></div></td></tr></tbody></table>
Ее смысл достаточно простой - взять id из message.chat.id, а если его нет - из callback_query. Символ || означает логическое условие ИЛИ.

Заполненное поле Chat ID
Последняя настройка узла - это поле Text. В него введите то, что вы хотите, чтобы отображалось тогда, когда пользователь отправил не /start или не нажал на inline-кнопку. Например: Напиши /start, а затем нажми кнопку 📊 Отчет по Яндекс Метрике:

Текст сообщения
Примечание: не забудьте отключить опцию Append n8n Attribution, чтобы не отображалось системное сообщение от n8n.
В итоге, если отправить в чат что угодно, кроме /start, и не нажать кнопку отчета, бот ответит вам сообщением-подсказкой:

Сообщение-подсказка
На этом этапе я рекомендую переименовать названия узлов, чтобы вы потом не запутались. Например, так:

Переименование узлов
Теперь мы можем двигаться дальше, по центральной ветке, и настраивать основную логику workflow.

Ветка report - основная ветка, на которой будет формировать итоговый отчет Яндекс Метрики
Следующее, что нужно сделать, после того как вы нажмете на кнопку 📊 Отчет по Яндекс Метрике, это создать узел, в котором будут задаваться настройки конфигурации отчета - диапазоны дат, модель атрибуции и тип отчета.
В качестве демонстрации статистики из Яндекс Метрики я буду использовать шаблоны (presets) API отчетов. Через них можно собрать отчет прямо из интерфейса Telegram-бота без лишней сложности. Другие варианты настройки сильно усложняют workflow в n8n. А я всегда в своих материалах стараюсь идти по пути наименьшего сопротивления, что вы все вышеприведенные шаги смогли повторить самостоятельно.
Для этого на ветке report нажмите на иконку + и в строке поиска введите Telegram. Выберите Action - Send message and wait for response:

Send message and wait for response
Этот узел отправляет пользователю сообщение и ставит выполнение workflow на паузу, пока не придет ответ. В отличие от обычной отправки текста, он не идет дальше по цепочке сразу. Сценарий ждет, пока человек заполнит форму или нажмет кнопку ответа. Когда данные получены, n8n возобновляет процесс и передает ответ в следующие узлы. Так бот в одном запуске и запускает сценарий, и собирает параметры отчета (период, шаблон, модель атрибуции) без отдельной логики хранения состояния.
Повторно запустите узел Показ inline-кнопки и нажмите в своем чат-боте на нее. В результате дальше по цепочке через Switch они попадут в Input только что созданного узла Send message and wait for response:

Данные с предыдущего узла
Теперь нам необходимо заполнить настройки нужными данными. Во-первых, перетащите поле id из объекта chat (chat.id), который является объектом message, а тот, в свою очередь является частью callback_query, в поле Chat ID:
Перетащите поле id из объекта chat в поле Chat ID. Оно лежит в callback_query.message.chat.id (callback_query - message - chat - id):

Перетащите поле id в Chat ID
Если перетащить из схемы именно это поле, в условии получится:
<table><tbody><tr><td data-settings="show"><div><p>1</p></div></td><td><div><p><span>{</span><span>{</span><span> </span><span>$</span><span>json</span><span>.</span><span>callback_query</span><span>.</span><span>message</span><span>.</span><span>chat</span><span>.</span><span>id</span><span> </span><span>}</span><span>}</span></p></div></td></tr></tbody></table>
В поле Message добавьте свое сообщение, которое будет напоминать вам о выборе конфигурации отчета. Например: Выбери шаблон отчета (preset), период и модель атрибуции:

Заполнение поля Message
В разделе Response Type измените значение на Custom Form:

Response Type - Custom Form
В режиме sendAndWait бот отправляет сообщение и ждет ответ. Response Type как раз задает, в каком виде этот ответ собрать:
- Custom Form - форма с полями (текст, списки и т.д.) по ссылке n8n. Удобно использовать, когда нужно сразу несколько параметров, как в нашем примере;
- Approval - кнопки подтверждения вроде Approve / Decline (да/нет). Тут нет формы, только решение пользователя. Для нашего примера не подойдет;
- Free Text - свободный текстовый ответ: пользователь просто пишет сообщение в чат, а бот ждет этот текст. Подходит для одного значения (например: введи номер счетчика Яндекс Метрики), но не для нескольких полей сразу.
Другими словами, Custom Form - анкета, Approval - да/нет, а Free Text - один текстовый ответ.
Следующая настройка - это Define Form - Using Fields Below. Это означает, что мы сами создаем форму прямо в этом узле со своим набором полей и опций. Поочередно добавим несколько таких полей для заполнения:

Add Form Element
Задайте для первого поля такие настройки:
- Field Name - counter_id
- Element Type - Text type
- Required Field - включено

Пример первого поля (counter_id)
В это поле вы будете вводить ID счетчика Яндекс Метрики, из которого планируете получить статистику.
Снова нажмите на кнопку Add Form Element и добавьте еще одно поле с такими настройками:
- Field Name - preset
- Element Type - Dropdown
- Option - по очереди: sources_summary, search_engines, sources_sites, tech_browsers, tech_devices, traffic, geo_country, content_entrance;
- Required Field - включено

Пример второго поля (preset)
Этот список - шаблоны Яндекс Метрики. В API отчетов параметр preset автоматически задает метрики и группировки, которые необходимы для того или иного отчета. Вы можете задать свою собственную конфигурацию из параметров (dimensions) и показателей (metrics), а можете использовать другой список шаблонов (не мой из этого руководство), который подробно представлен в официальной документации Яндекса.
Следующее поле, которое нужно создать, имеет такие настройки:
- Field Name - date_from
- Element Type - Text type
- Text input - 2026-07-01
- Required Field - включено
Оно предназначено для ввода даты начала периода, за который вы хотите выгрузить данные.
Следующее поле - точно такое же, только для даты окончания отчетного периода:
- Field Name - date_to
- Element Type - Text type
- Text input - 2026-07-15
- Required Field - включено

Дата начала и дата завершения (date_from и date_to)
Для полей date_from и date_to я специально добавил подсказки, так как даты нужны в формате YYYY-MM-DD (например, 2026-07-01). Он выглядит «перевернутым» относительно привычного ДД.ММ.ГГГГ. Но так требует API Яндекс Метрики. Период в запросе передается как date1 / date2 именно в ISO-формате YYYY-MM-DD. Если указать дату иначе, запрос к API, скорее всего, завершится ошибкой.
Последнее поле, которое мы добавив для заполнения - это:
- Field Name - attribution
- Element Type - Dropdown
- Option - по очереди: last, lastsign, cross_device_first, cross_device_last_significant, automatic;
- Default value - lastsign;
- Required Field - включено

Пример последнего поля (attribution)
Для API отчетов доступна параметризация - механизм задания параметров для некоторых группировок и метрик. И там мы можем добавить модель атрибуции. Это поле как раз и будет отвечать за это в нашем отчете.
Чтобы открыть текущую форму для заполнения, в разделе Options в самом низу нажмите на кнопку Add option и выберите Message Button Label:

Add option - Message Button Label
В поле Message Button Label введите текст кнопки. Например: Создать отчет:

Message Button Label
Еще раз нажмите Add option и выберите Response Form Title. Эта настройка отвечает за заголовок на странице формы. Введите произвольный title. Например: Параметры отчета Яндекс Метрики:

Response Form Title
Следующую настройку, которую можно добавить - это Response Form Description. Она позволяет добавить подсказку прямо под заголовком формы. Давайте сделаем это и добавим туда следующий текст:
- counter_id - ID счетчика
- preset - готовый шаблон API отчетов
- date_from/date_to - в формате YYYY-MM-DD
- attribution - модель атрибуции

Response Form Description
Еще одна настройка, которую я предлагаю добавить в этом узле - Response Form Button Label. После нажатия на текст этой кнопки заполненные данные уходят в n8n, и workflow продолжается. Давайте назовем ее Сформировать отчет:

Response Form Button Label
Чтобы наш бот не ждал от нас бесконечного ответа, добавим настройку Limit Wait Time. Задайте для нее следующие данные:
- Limit Type - After Time Interval
- Amount - 30
- Unit - Minutes

Limit Wait Time
Таким образом, наш бот ждет заполнения формы до 30 минут. После 30 минут ожидание обрывается. Если пользователь (вы) так и не нажал кнопку формирования отчета, то данные формы в n8n не приходят, а сам workflow дальше по цепочке не идет. Обычно такой запуск (execution) завершается с ошибкой/таймаутом ожидания.
В завершение не забудьте отключить опцию Append n8n Attribution, чтобы не отображалось системное сообщение от n8n.
Закройте настройки узла и запустите его на тест. В Telegram придет ваше сообщение с кнопкой, после нажатия на которую вам откроется форма, в которой вы заполните свои данные:

Заполнение формы с конфигурацией отчета
Нажав Сформировать отчет, вернитесь в n8n к этому узлу (или в Executions). В результате выполнения данные формы придут одним item - с конфигурацией отчета для запроса к API Яндекс Метрики.

Результат выполнения узла после отправки формы
Пока все просто! Но вот теперь начинается самая главная и сложная часть - подготовить данные к запросу API таким образом, чтобы Яндекс понял, что мы от него хотим. Поэтому следующим звеном по цепочке будет идти узел Code. Добавьте его в конец ветки report.

Узел Code
Вставьте в редактор JavaScript нижеприведенный код:
<table><tbody><tr><td data-settings="show"><div><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p><p>14</p><p>15</p><p>16</p><p>17</p><p>18</p><p>19</p><p>20</p><p>21</p><p>22</p><p>23</p><p>24</p><p>25</p><p>26</p><p>27</p><p>28</p><p>29</p><p>30</p><p>31</p><p>32</p><p>33</p><p>34</p><p>35</p><p>36</p><p>37</p><p>38</p><p>39</p><p>40</p><p>41</p><p>42</p><p>43</p><p>44</p><p>45</p><p>46</p><p>47</p><p>48</p><p>49</p><p>50</p></div></td><td><div><p><span>// Берем данные формы: иногда они в .data, иногда сразу в корне json</span></p><p><span>const</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>$</span><span>input</span><span>.</span><span>first</span><span>(</span><span>)</span><span>.</span><span>json</span><span>.</span><span>data</span><span> </span><span>||</span><span> </span><span>$</span><span>input</span><span>.</span><span>first</span><span>(</span><span>)</span><span>.</span><span>json</span><span>;</span></p><p><span>// Достаем поля формы и приводим к строкам без лишних пробелов</span></p><p><span>const</span><span> </span><span>counterid</span><span> </span><span>=</span><span> </span><span>String</span><span>(</span><span>data</span><span>.</span><span>counterid</span><span> </span><span>||</span><span> </span><span>''</span><span>)</span><span>.</span><span>trim</span><span>(</span><span>)</span><span>;</span></p><p><span>const</span><span> </span><span>preset</span><span> </span><span>=</span><span> </span><span>String</span><span>(</span><span>data</span><span>.</span><span>preset</span><span> </span><span>||</span><span> </span><span>'sourcessummary'</span><span>)</span><span>.</span><span>trim</span><span>(</span><span>)</span><span>;</span><span> </span><span>// если пусто — шаблон по умолчанию</span></p><p><span>const</span><span> </span><span>datefrom</span><span> </span><span>=</span><span> </span><span>String</span><span>(</span><span>data</span><span>.</span><span>datefrom</span><span> </span><span>||</span><span> </span><span>''</span><span>)</span><span>.</span><span>trim</span><span>(</span><span>)</span><span>;</span></p><p><span>const</span><span> </span><span>dateto</span><span> </span><span>=</span><span> </span><span>String</span><span>(</span><span>data</span><span>.</span><span>dateto</span><span> </span><span>||</span><span> </span><span>''</span><span>)</span><span>.</span><span>trim</span><span>(</span><span>)</span><span>;</span></p><p><span>const</span><span> </span><span>attribution</span><span> </span><span>=</span><span> </span><span>String</span><span>(</span><span>data</span><span>.</span><span>attribution</span><span> </span><span>||</span><span> </span><span>'last'</span><span>)</span><span>.</span><span>trim</span><span>(</span><span>)</span><span>;</span><span> </span><span>// модель атрибуции по умолчанию</span></p><p><span>// Проверки до запроса к API Яндекс Метрики</span></p><p><span>if</span><span> </span><span>(</span><span>!</span><span>counterid</span><span>)</span><span> </span><span>throw</span><span> </span><span>new</span><span> </span><span>Error</span><span>(</span><span>'Укажи counterid'</span><span>)</span><span>;</span></p><p><span>if</span><span> </span><span>(</span><span>!</span><span>/</span><span>^</span><span>\</span><span>d</span><span>{</span><span>4</span><span>}</span><span>-</span><span>\</span><span>d</span><span>{</span><span>2</span><span>}</span><span>-</span><span>\</span><span>d</span><span>{</span><span>2</span><span>}</span><span>$</span><span>/</span><span>.</span><span>test</span><span>(</span><span>datefrom</span><span>)</span><span> </span><span>||</span><span> </span><span>!</span><span>/</span><span>^</span><span>\</span><span>d</span><span>{</span><span>4</span><span>}</span><span>-</span><span>\</span><span>d</span><span>{</span><span>2</span><span>}</span><span>-</span><span>\</span><span>d</span><span>{</span><span>2</span><span>}</span><span>$</span><span>/</span><span>.</span><span>test</span><span>(</span><span>dateto</span><span>)</span><span>)</span><span> </span><span>{</span></p><p><span> </span><span>throw</span><span> </span><span>new</span><span> </span><span>Error</span><span>(</span><span>'Даты должны быть в формате YYYY-MM-DD'</span><span>)</span><span>;</span></p><p><span>}</span></p><p><span>// Человекочитаемые названия preset для HTML/подписей</span></p><p><span>const</span><span> </span><span>presetTitles</span><span> </span><span>=</span><span> </span><span>{</span></p><p><span> </span><span>sourcessummary</span><span>:</span><span> </span><span>'Источники, сводка'</span><span>,</span></p><p><span> </span><span>searchengines</span><span>:</span><span> </span><span>'Поисковые системы'</span><span>,</span></p><p><span> </span><span>sourcessites</span><span>:</span><span> </span><span>'Сайты'</span><span>,</span></p><p><span> </span><span>techbrowsers</span><span>:</span><span> </span><span>'Браузеры'</span><span>,</span></p><p><span> </span><span>techdevices</span><span>:</span><span> </span><span>'Устройства'</span><span>,</span></p><p><span> </span><span>traffic</span><span>:</span><span> </span><span>'Трафик'</span><span>,</span></p><p><span> </span><span>geocountry</span><span>:</span><span> </span><span>'География: страны'</span><span>,</span></p><p><span> </span><span>contententrance</span><span>:</span><span> </span><span>'Страницы входа'</span></p><p><span>}</span><span>;</span></p><p><span>// Человекочитаемые названия моделей атрибуции</span></p><p><span>const</span><span> </span><span>attributionTitles</span><span> </span><span>=</span><span> </span><span>{</span></p><p><span> </span><span>crossdevicefirst</span><span>:</span><span> </span><span>'Первый переход'</span><span>,</span></p><p><span> </span><span>last</span><span>:</span><span> </span><span>'Последний переход'</span><span>,</span></p><p><span> </span><span>crossdevicelastsignificant</span><span>:</span><span> </span><span>'Последний значимый переход'</span><span>,</span></p><p><span> </span><span>automatic</span><span>:</span><span> </span><span>'Автоматическая атрибуция'</span></p><p><span>}</span><span>;</span></p><p><span>// Один item для следующих узлов: параметры API + chatid для ответа в Telegram</span></p><p><span>return</span><span> </span><span>[</span><span>{</span></p><p><span> </span><span>json</span><span>:</span><span> </span><span>{</span></p><p><span> </span><span>// ID чата, где нажали кнопку (из исходного callback Telegram Trigger)</span></p><p><span> </span><span>chatid</span><span>:</span><span> </span><span>$</span><span>(</span><span>'Telegram Trigger'</span><span>)</span><span>.</span><span>first</span><span>(</span><span>)</span><span>.</span><span>json</span><span>.</span><span>callbackquery</span><span>.</span><span>message</span><span>.</span><span>chat</span><span>.</span><span>id</span><span>,</span></p><p><span> </span><span>counterid</span><span>,</span></p><p><span> </span><span>preset</span><span>,</span></p><p><span> </span><span>presettitle</span><span>:</span><span> </span><span>presetTitles</span><span>[</span><span>preset</span><span>]</span><span> </span><span>||</span><span> </span><span>preset</span><span>,</span><span> </span><span>// если кода нет в словаре — оставим как есть</span></p><p><span> </span><span>datefrom</span><span>,</span></p><p><span> </span><span>dateto</span><span>,</span></p><p><span> </span><span>attribution</span><span>,</span></p><p><span> </span><span>attribution_title</span><span>:</span><span> </span><span>attributionTitles</span><span>[</span><span>attribution</span><span>]</span><span> </span><span>||</span><span> </span><span>attribution</span></p><p><span> </span><span>}</span></p><p><span>}</span><span>]</span><span>;</span></p></div></td></tr></tbody></table>
В настройках узла это будет выглядеть так:

Код на JavaScript в узле Code
Этот узел Code - подготовка данных после формы, до запроса к API отчетов Яндекс Метрики.
Выполните тестовый запуск, заполните данные по своему отчету и сформируйте его. Как только workflow дойдет до последнего узла, откройте вкладку Executions:

Вкладка "Executions"
И посмотрите, какие данные пришли на выходе (Output):

Исходные данные о вашем отчете
Если кратко, то он:
- достает поля формы (counter_id, preset, даты, attribution);
- проверяет, что счетчик заполнен и даты в формате YYYY-MM-DD;
- добавляет понятные названия (preset_title, attribution_title);
- подставляет chat_id из триггера Telegram (чат, где нажали кнопку);
- отдает дальше один item.
Эти данные нам понадобятся на следующем узле HTTP Request, в котором мы будем заполнять все нужные данные по запросу к API отчетов Яндекс Метрики. chat_id и _title для самого API не нужны, но они пригодятся позже для HTML и отправки в Telegram.

Узел HTTP Request
Чтобы его правильно заполнить, вы должны уметь работать с API отчетов Яндекс Метрики и понимать, как собирается HTTP-запрос с query-параметрами, заголовками, токеном доступа и набором группировок и метрик (явно через dimensions/metrics или через preset).
Поскольку мы используем шаблоны (preset - предопределенный набор параметров и показателей в отчете с ), то тело запроса использовать не нужно. Раскройте настройки узла HTTP Request и укажите:
- Method - GET
- URL - https://api-metrika.yandex.net/stat/v1/data
- Send Query Parameters - включено
- Authentication - None

Настройки HTTP Request
Затем нужно добавить несколько параметров, задав им имена (Name) ровно такие же, как этого требует сам Яндекс для запроса к API. А вот значения (Value) вам необходимо перетащить из входных данных предыдущего узла. Имена параметров такие:
- ids - идентификатор счетчика Яндекс Метрики
- date1 - дата начала периода выборки в формате YYYY-MM-DD
- date2 - дата окончания периода выборки в формате YYYY-MM-DD
- preset - шаблон отчета
- accuracy - full (размер выборки, используемой для отчета)
- attribution - модель атрибуции
- lang - ru (язык ответа)
В интерфейсе n8n узла HTTP Request это будет выглядеть так:

Пример заполнения параметров запроса (Query Parameters)
После заполнения параметров запроса активируйте опцию Send Headers и добавьте заголовок Authorization со значением:
<table><tbody><tr><td data-settings="show"><div><p>1</p></div></td><td><div><p><span>OAuth </span><span>token</span></p></div></td></tr></tbody></table>
, где token - ваш токен доступа Яндекс Метрики, который вы получили на предыдущем шаге.

Authorization: OAuth <access_token>
На этом настройка узла HTTP Request завершена. Запустите рабочий процесс, сформируйте отчет в форме, и в ответе Яндекса вы увидите данные по вашему счетчику Метрики согласно выбранному шаблону:

Данные вашего счетчика Яндекс Метрики
Однако, в таком формате мы не можем отправить данные в Telegram. Нам нужно их окончательно преобразовать. Для этого используется еще один узел Code - JavaScript.

Узел Code
Добавьте его на предпоследнем шаге и вставьте нижеприведенный скрипт:
<table><tbody><tr><td data-settings="show"><div><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p><p>14</p><p>15</p><p>16</p><p>17</p><p>18</p><p>19</p><p>20</p><p>21</p><p>22</p><p>23</p><p>24</p><p>25</p><p>26</p><p>27</p><p>28</p><p>29</p><p>30</p><p>31</p><p>32</p><p>33</p><p>34</p><p>35</p><p>36</p><p>37</p><p>38</p><p>39</p><p>40</p><p>41</p><p>42</p><p>43</p><p>44</p><p>45</p><p>46</p><p>47</p><p>48</p><p>49</p><p>50</p><p>51</p><p>52</p><p>53</p><p>54</p><p>55</p><p>56</p><p>57</p><p>58</p><p>59</p><p>60</p><p>61</p><p>62</p><p>63</p><p>64</p><p>65</p><p>66</p><p>67</p><p>68</p><p>69</p><p>70</p><p>71</p><p>72</p><p>73</p><p>74</p><p>75</p><p>76</p><p>77</p><p>78</p><p>79</p><p>80</p><p>81</p><p>82</p><p>83</p><p>84</p><p>85</p><p>86</p><p>87</p><p>88</p><p>89</p><p>90</p><p>91</p><p>92</p><p>93</p><p>94</p><p>95</p><p>96</p><p>97</p><p>98</p><p>99</p><p>100</p><p>101</p><p>102</p><p>103</p><p>104</p><p>105</p><p>106</p><p>107</p><p>108</p><p>109</p><p>110</p><p>111</p><p>112</p><p>113</p><p>114</p><p>115</p><p>116</p><p>117</p><p>118</p><p>119</p><p>120</p><p>121</p><p>122</p><p>123</p><p>124</p><p>125</p><p>126</p><p>127</p><p>128</p><p>129</p><p>130</p><p>131</p><p>132</p><p>133</p><p>134</p><p>135</p><p>136</p></div></td><td><div><p><span>// Параметры отчета из предыдущего узла</span></p><p><span>const</span><span> </span><span>p</span><span> </span><span>=</span><span> </span><span>$</span><span>input</span><span>.</span><span>first</span><span>(</span><span>)</span><span>.</span><span>json</span><span>;</span></p><p><span>// Ответ HTTP-запроса к API Яндекс Метрики</span></p><p><span>const</span><span> </span><span>resp</span><span> </span><span>=</span><span> </span><span>$</span><span>input</span><span>.</span><span>first</span><span>(</span><span>)</span><span>.</span><span>json</span><span>;</span></p><p><span>// Если Метрика вернула ошибку — останавливаем workflow с понятным текстом</span></p><p><span>if</span><span> </span><span>(</span><span>resp</span><span>.</span><span>errors</span><span> </span><span>||</span><span> </span><span>resp</span><span>.</span><span>message</span><span> </span><span>||</span><span> </span><span>resp</span><span>.</span><span>code</span><span>)</span><span> </span><span>{</span></p><p><span> </span><span>throw</span><span> </span><span>new</span><span> </span><span>Error</span><span>(</span><span>'Ошибка Метрики: '</span><span> </span><span>+</span><span> </span><span>JSON</span><span>.</span><span>stringify</span><span>(</span><span>resp</span><span>)</span><span>.</span><span>slice</span><span>(</span><span>0</span><span>,</span><span> </span><span>400</span><span>)</span><span>)</span><span>;</span></p><p><span>}</span></p><p><span>// Из ответа достаём названия колонок и строки данных</span></p><p><span>const</span><span> </span><span>query</span><span> </span><span>=</span><span> </span><span>resp</span><span>.</span><span>query</span><span> </span><span>||</span><span> </span><span>{</span><span>}</span><span>;</span></p><p><span>const</span><span> </span><span>dimNames</span><span> </span><span>=</span><span> </span><span>query</span><span>.</span><span>dimensions</span><span> </span><span>||</span><span> </span><span>[</span><span>]</span><span>;</span><span> </span><span>// группировки</span></p><p><span>const</span><span> </span><span>metricNames</span><span> </span><span>=</span><span> </span><span>query</span><span>.</span><span>metrics</span><span> </span><span>||</span><span> </span><span>[</span><span>]</span><span>;</span><span> </span><span>// метрики</span></p><p><span>const</span><span> </span><span>rows</span><span> </span><span>=</span><span> </span><span>Array</span><span>.</span><span>isArray</span><span>(</span><span>resp</span><span>.</span><span>data</span><span>)</span><span> </span><span>?</span><span> </span><span>resp</span><span>.</span><span>data</span><span> </span><span>:</span><span> </span><span>[</span><span>]</span><span>;</span></p><p><span>// Экранирование HTML, чтобы спецсимволы в данных не ломали разметку</span></p><p><span>const</span><span> </span><span>esc</span><span> </span><span>=</span><span> </span><span>(</span><span>v</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>String</span><span>(</span><span>v</span><span> </span><span>?</span><span>?</span><span> </span><span>''</span><span>)</span></p><p><span> </span><span>.</span><span>replace</span><span>(</span><span>/</span><span>&</span><span>/</span><span>g</span><span>,</span><span> </span><span>'&amp;'</span><span>)</span></p><p><span> </span><span>.</span><span>replace</span><span>(</span><span>/</span><span><</span><span>/</span><span>g</span><span>,</span><span> </span><span>'&lt;'</span><span>)</span></p><p><span> </span><span>.</span><span>replace</span><span>(</span><span>/</span><span>></span><span>/</span><span>g</span><span>,</span><span> </span><span>'&gt;'</span><span>)</span><span>;</span></p><p><span>// Функция для получения читаемого значения из измерения</span></p><p><span>const</span><span> </span><span>getDimensionValue</span><span> </span><span>=</span><span> </span><span>(</span><span>d</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>{</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span> </span><span>==</span><span> </span><span>null</span><span>)</span><span> </span><span>return</span><span> </span><span>''</span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>typeof</span><span> </span><span>d</span><span> </span><span>!==</span><span> </span><span>'object'</span><span>)</span><span> </span><span>return</span><span> </span><span>String</span><span>(</span><span>d</span><span>)</span><span>;</span></p><p><span> </span><span>// Приоритет: name > id > favicon > url</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span>.</span><span>name</span><span>)</span><span> </span><span>return</span><span> </span><span>d</span><span>.</span><span>name</span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span>.</span><span>id</span><span>)</span><span> </span><span>return</span><span> </span><span>d</span><span>.</span><span>id</span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span>.</span><span>favicon</span><span>)</span><span> </span><span>return</span><span> </span><span>d</span><span>.</span><span>favicon</span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span>.</span><span>url</span><span>)</span><span> </span><span>return</span><span> </span><span>d</span><span>.</span><span>url</span><span>;</span></p><p><span> </span><span>// Если все поля null или пустые, возвращаем пустую строку</span></p><p><span> </span><span>return</span><span> </span><span>''</span><span>;</span></p><p><span>}</span><span>;</span></p><p><span>// Функция для получения заголовка измерения</span></p><p><span>const</span><span> </span><span>getDimensionHeader</span><span> </span><span>=</span><span> </span><span>(</span><span>d</span><span>,</span><span> </span><span>index</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>{</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>!</span><span>d</span><span>)</span><span> </span><span>return</span><span> </span><span></span><span>dimension_</span><span>$</span><span>{</span><span>index</span><span> </span><span>+</span><span> </span><span>1</span><span>}</span><span></span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>typeof</span><span> </span><span>d</span><span> </span><span>===</span><span> </span><span>'string'</span><span>)</span><span> </span><span>return</span><span> </span><span>d</span><span>;</span></p><p><span> </span><span>// Используем осмысленное название для заголовка</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span> </span><span>===</span><span> </span><span>'ym:s:lastsignTrafficSource'</span><span>)</span><span> </span><span>return</span><span> </span><span>'Источник трафика'</span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span> </span><span>===</span><span> </span><span>'ym:s:lastsignSourceEngine'</span><span>)</span><span> </span><span>return</span><span> </span><span>'Источник/движок'</span><span>;</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>d</span><span> </span><span>===</span><span> </span><span>'ym:s:lastsignDirectPlatformType'</span><span>)</span><span> </span><span>return</span><span> </span><span>'Тип платформы'</span><span>;</span></p><p><span> </span><span>return</span><span> </span><span>d</span><span>;</span></p><p><span>}</span><span>;</span></p><p><span>// Заголовки таблицы: сначала измерения, потом метрики</span></p><p><span>const</span><span> </span><span>headers</span><span> </span><span>=</span><span> </span><span>[</span></p><p><span> </span><span>.</span><span>.</span><span>.</span><span>dimNames</span><span>.</span><span>map</span><span>(</span><span>(</span><span>d</span><span>,</span><span> </span><span>i</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>getDimensionHeader</span><span>(</span><span>d</span><span>,</span><span> </span><span>i</span><span>)</span><span>)</span><span>,</span></p><p><span> </span><span>.</span><span>.</span><span>.</span><span>metricNames</span><span>.</span><span>map</span><span>(</span><span>(</span><span>m</span><span>,</span><span> </span><span>i</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>m</span><span> </span><span>||</span><span> </span><span></span><span>metric_</span><span>$</span><span>{</span><span>i</span><span> </span><span>+</span><span> </span><span>1</span><span>}</span><span></span><span>)</span></p><p><span>]</span><span>;</span></p><p><span>const</span><span> </span><span>head</span><span> </span><span>=</span><span> </span><span>headers</span><span>.</span><span>map</span><span>(</span><span>(</span><span>h</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span></span><span><</span><span>th</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>h</span><span>)</span><span>}</span><span><</span><span>/</span><span>th</span><span>></span><span></span><span>)</span><span>.</span><span>join</span><span>(</span><span>''</span><span>)</span><span>;</span></p><p><span>// Тело таблицы: каждая строка API → <tr>...</tr></span></p><p><span>const</span><span> </span><span>body</span><span> </span><span>=</span><span> </span><span>rows</span><span>.</span><span>length</span></p><p><span> </span><span>?</span><span> </span><span>rows</span><span>.</span><span>map</span><span>(</span><span>(</span><span>row</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>{</span></p><p><span> </span><span>// Обработка измерений с улучшенной логикой</span></p><p><span> </span><span>const</span><span> </span><span>dims</span><span> </span><span>=</span><span> </span><span>(</span><span>row</span><span>.</span><span>dimensions</span><span> </span><span>||</span><span> </span><span>[</span><span>]</span><span>)</span><span>.</span><span>map</span><span>(</span><span>(</span><span>d</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>getDimensionValue</span><span>(</span><span>d</span><span>)</span><span>)</span><span>;</span></p><p><span> </span><span>// Обработка метрик с округлением для читаемости</span></p><p><span> </span><span>const</span><span> </span><span>metrics</span><span> </span><span>=</span><span> </span><span>(</span><span>row</span><span>.</span><span>metrics</span><span> </span><span>||</span><span> </span><span>[</span><span>]</span><span>)</span><span>.</span><span>map</span><span>(</span><span>(</span><span>m</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span>{</span></p><p><span> </span><span>if</span><span> </span><span>(</span><span>typeof</span><span> </span><span>m</span><span> </span><span>===</span><span> </span><span>'number'</span><span>)</span><span> </span><span>{</span></p><p><span> </span><span>// Округляем числа до 2 знаков, если это не целое</span></p><p><span> </span><span>return</span><span> </span><span>Number</span><span>.</span><span>isInteger</span><span>(</span><span>m</span><span>)</span><span> </span><span>?</span><span> </span><span>m</span><span> </span><span>:</span><span> </span><span>Math</span><span>.</span><span>round</span><span>(</span><span>m *</span><span> </span><span>100</span><span>)</span><span> </span><span>/</span><span> </span><span>100</span><span>;</span></p><p><span> </span><span>}</span></p><p><span> </span><span>return</span><span> </span><span>m</span><span>;</span></p><p><span> </span><span>}</span><span>)</span><span>;</span></p><p><span> </span><span>const</span><span> </span><span>cells</span><span> </span><span>=</span><span> </span><span>[</span><span>.</span><span>.</span><span>.</span><span>dims</span><span>,</span><span> </span><span>.</span><span>.</span><span>.</span><span>metrics</span><span>]</span><span>.</span><span>map</span><span>(</span><span>(</span><span>c</span><span>)</span><span> </span><span>=</span><span>></span><span> </span><span></span><span><</span><span>td</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>c</span><span>)</span><span>}</span><span><</span><span>/</span><span>td</span><span>></span><span></span><span>)</span><span>.</span><span>join</span><span>(</span><span>''</span><span>)</span><span>;</span></p><p><span> </span><span>return</span><span> </span><span></span><span><</span><span>tr</span><span>></span><span>$</span><span>{</span><span>cells</span><span>}</span><span><</span><span>/</span><span>tr</span><span>></span><span></span><span>;</span></p><p><span> </span><span>}</span><span>)</span><span>.</span><span>join</span><span>(</span><span>''</span><span>)</span></p><p><span> </span><span>:</span><span> </span><span></span><span><</span><span>tr</span><span>></span><span><</span><span>td </span><span>colspan</span><span>=</span><span>"${Math.max(headers.length, 1)}"</span><span>></span>Нет<span> </span>данных<span> </span>за<span> </span>период<span><</span><span>/</span><span>td</span><span>></span><span><</span><span>/</span><span>tr</span><span>></span><span></span><span>;</span></p><p><span>// ВАЖНО: Укажите здесь ваш реальный chatid</span></p><p><span>// Получить можно у бота @userinfobot или через @BotFather</span></p><p><span>const</span><span> </span><span>CHATID</span><span> </span><span>=</span><span> </span><span>'chatid'</span><span>;</span><span> </span><span>// Замените на ваш реальный chatid</span></p><p><span>// Собираем готовый HTML-файл отчёта</span></p><p><span>const</span><span> </span><span>html</span><span> </span><span>=</span><span> </span><span></span><span><</span><span>!</span><span>doctype </span><span>html</span><span>></span></p><p><span><</span><span>html </span><span>lang</span><span>=</span><span>"ru"</span><span>></span><span><</span><span>head</span><span>></span><span><</span><span>meta </span><span>charset</span><span>=</span><span>"utf-8"</span><span> </span><span>/</span><span>></span></p><p><span><</span><span>title</span><span>></span>Отчёт<span> </span>Метрика<span><</span><span>/</span><span>title</span><span>></span></p><p><span><style></span></p><p><span>body</span><span>{</span><span>font-family</span><span>:</span><span>Arial,sans-serif</span><span>;</span><span>margin</span><span>:</span><span>24px</span><span>;</span><span>background</span><span>:</span><span>#f7f7f7</span><span>;</span><span>color</span><span>:</span><span>#222</span><span>}</span></p><p><span>.card</span><span>{</span><span>background</span><span>:</span><span>#fff</span><span>;</span><span>border</span><span>:</span><span>1px</span><span> </span><span>solid</span><span> </span><span>#ddd</span><span>;</span><span>border-radius</span><span>:</span><span>10px</span><span>;</span><span>padding</span><span>:</span><span>16px</span><span>}</span></p><p><span>h1</span><span>{</span><span>margin</span><span>:</span><span>0</span><span> </span><span>0</span><span> </span><span>8px</span><span>;</span><span>font-size</span><span>:</span><span>20px</span><span>}</span></p><p><span>.meta</span><span>{</span><span>color</span><span>:</span><span>#666</span><span>;</span><span>margin</span><span>:</span><span>0</span><span> </span><span>0</span><span> </span><span>12px</span><span>;</span><span>line-height</span><span>:</span><span>1.5</span><span>}</span></p><p><span>table</span><span>{</span><span>border-collapse</span><span>:</span><span>collapse</span><span>;</span><span>width</span><span>:</span><span>100%</span><span>;</span><span>font-size</span><span>:</span><span>13px</span><span>}</span></p><p><span>th,td</span><span>{</span><span>border</span><span>:</span><span>1px</span><span> </span><span>solid</span><span> </span><span>#ddd</span><span>;</span><span>padding</span><span>:</span><span>8px</span><span>;</span><span>text-align</span><span>:</span><span>left</span><span>}</span></p><p><span>th</span><span>{</span><span>background</span><span>:</span><span>#111</span><span>;</span><span>color</span><span>:</span><span>#fff</span><span>}</span></p><p><span>tr:nth-child(even) td</span><span>{</span><span>background</span><span>:</span><span>#fafafa</span><span>}</span></p><p><span>td:not(:first-child):not(:nth-child(2)):not(:nth-child(3)) </span><span>{</span></p><p><span> </span><span>text-align</span><span>:</span><span> </span><span>right</span><span>;</span></p><p><span>}</span></p><p><span></style></span><span><</span><span>/</span><span>head</span><span>></span><span><</span><span>body</span><span>></span><span><</span><span>div </span><span>class</span><span>=</span><span>"card"</span><span>></span></p><p><span><</span><span>h1</span><span>></span>Отчёт<span> </span>Яндекс<span> </span>Метрика<span><</span><span>/</span><span>h1</span><span>></span></p><p><span><</span><span>p</span><span> </span><span>class</span><span>=</span><span>"meta"</span><span>></span></p><p>Счётчик<span>:</span><span> </span><span><</span><span>b</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>p</span><span>.</span><span>counter_id</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>ids</span><span>?</span><span>.</span><span>[</span><span>0</span><span>]</span><span> </span><span>||</span><span> </span><span>'не указан'</span><span>)</span><span>}</span><span><</span><span>/</span><span>b</span><span>></span><span><</span><span>br</span><span>/</span><span>></span></p><p>Шаблон<span>:</span><span> </span><span><</span><span>b</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>p</span><span>.</span><span>preset_title</span><span> </span><span>||</span><span> </span><span>p</span><span>.</span><span>preset</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>preset</span><span> </span><span>||</span><span> </span><span>'не указан'</span><span>)</span><span>}</span><span><</span><span>/</span><span>b</span><span>></span><span><</span><span>br</span><span>/</span><span>></span></p><p>Период<span>:</span><span> </span><span><</span><span>b</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>p</span><span>.</span><span>date_from</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>date1</span><span> </span><span>||</span><span> </span><span>'не указан'</span><span>)</span><span>}</span><span><</span><span>/</span><span>b</span><span>></span><span> </span>→<span> </span><span><</span><span>b</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>p</span><span>.</span><span>date_to</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>date2</span><span> </span><span>||</span><span> </span><span>'не указан'</span><span>)</span><span>}</span><span><</span><span>/</span><span>b</span><span>></span><span><</span><span>br</span><span>/</span><span>></span></p><p>Атрибуция<span>:</span><span> </span><span><</span><span>b</span><span>></span><span>$</span><span>{</span><span>esc</span><span>(</span><span>p</span><span>.</span><span>attribution_title</span><span> </span><span>||</span><span> </span><span>p</span><span>.</span><span>attribution</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>attribution</span><span> </span><span>||</span><span> </span><span>'не указан'</span><span>)</span><span>}</span><span><</span><span>/</span><span>b</span><span>></span><span><</span><span>br</span><span>/</span><span>></span></p><p>Строк<span>:</span><span> </span><span><</span><span>b</span><span>></span><span>$</span><span>{</span><span>rows</span><span>.</span><span>length</span><span>}</span><span><</span><span>/</span><span>b</span><span>></span></p><p><span><</span><span>/</span><span>p</span><span>></span></p><p><span><</span><span>table</span><span>></span><span><</span><span>thead</span><span>></span><span><</span><span>tr</span><span>></span><span>$</span><span>{</span><span>head</span><span>}</span><span><</span><span>/</span><span>tr</span><span>></span><span><</span><span>/</span><span>thead</span><span>></span><span><</span><span>tbody</span><span>></span><span>$</span><span>{</span><span>body</span><span>}</span><span><</span><span>/</span><span>tbody</span><span>></span><span><</span><span>/</span><span>table</span><span>></span></p><p><span><</span><span>/</span><span>div</span><span>></span><span><</span><span>/</span><span>body</span><span>></span><span><</span><span>/</span><span>html</span><span>></span><span></span><span>;</span></p><p><span>// Имя файла для отправки в Telegram</span></p><p><span>const</span><span> </span><span>presetName</span><span> </span><span>=</span><span> </span><span>p</span><span>.</span><span>preset</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>preset</span><span> </span><span>||</span><span> </span><span>'report'</span><span>;</span></p><p><span>const</span><span> </span><span>dateFrom</span><span> </span><span>=</span><span> </span><span>p</span><span>.</span><span>datefrom</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>date1</span><span> </span><span>||</span><span> </span><span>'date1'</span><span>;</span></p><p><span>const</span><span> </span><span>dateTo</span><span> </span><span>=</span><span> </span><span>p</span><span>.</span><span>dateto</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>date2</span><span> </span><span>||</span><span> </span><span>'date2'</span><span>;</span></p><p><span>const</span><span> </span><span>fileName</span><span> </span><span>=</span><span> </span><span></span><span>metrika</span><span>-</span><span>$</span><span>{</span><span>presetName</span><span>}</span><span>-</span><span>$</span><span>{</span><span>dateFrom</span><span>}</span><span>_</span><span>$</span><span>{</span><span>dateTo</span><span>}</span><span>.</span><span>html</span><span></span><span>;</span></p><p><span>// HTML → binary для узла Telegram (sendDocument)</span></p><p><span>const</span><span> </span><span>binary</span><span> </span><span>=</span><span> </span><span>await </span><span>this</span><span>.</span><span>helpers</span><span>.</span><span>prepareBinaryData</span><span>(</span></p><p><span> </span><span>Buffer</span><span>.</span><span>from</span><span>(</span><span>html</span><span>,</span><span> </span><span>'utf8'</span><span>)</span><span>,</span></p><p><span> </span><span>fileName</span><span>,</span></p><p><span> </span><span>'text/html'</span></p><p><span>)</span><span>;</span></p><p><span>// На выход: метаданные в json + файл в binary.data</span></p><p><span>return</span><span> </span><span>[</span><span>{</span></p><p><span> </span><span>json</span><span>:</span><span> </span><span>{</span></p><p><span> </span><span>chatid</span><span>:</span><span> </span><span>CHATID</span><span>,</span><span> </span><span>// Используем статический chatid</span></p><p><span> </span><span>fileName</span><span>,</span></p><p><span> </span><span>rowscount</span><span>:</span><span> </span><span>rows</span><span>.</span><span>length</span><span>,</span></p><p><span> </span><span>preset</span><span>:</span><span> </span><span>presetName</span><span>,</span></p><p><span> </span><span>datefrom</span><span>:</span><span> </span><span>dateFrom</span><span>,</span></p><p><span> </span><span>dateto</span><span>:</span><span> </span><span>dateTo</span><span>,</span></p><p><span> </span><span>attribution</span><span>:</span><span> </span><span>p</span><span>.</span><span>attribution</span><span> </span><span>||</span><span> </span><span>query</span><span>.</span><span>attribution</span><span> </span><span>||</span><span> </span><span>'не указан'</span></p><p><span> </span><span>}</span><span>,</span></p><p><span> </span><span>binary</span><span>:</span><span> </span><span>{</span><span> </span><span>data</span><span>:</span><span> </span><span>binary</span><span> </span><span>}</span></p><p><span>}</span><span>]</span><span>;</span></p></div></td></tr></tbody></table>
Найдите строку:
<table><tbody><tr><td data-settings="show"><div><p>1</p></div></td><td><div><p><span>const</span><span> </span><span>CHATID</span><span> </span><span>=</span><span> </span><span>'chatid'</span><span>;</span></p></div></td></tr></tbody></table>
И замените chat_id на ваш собственный идентификатор чата Telegram. Все остальное оставьте без изменений.
Этот код готовит данные после формы к запросу в Яндекс Метрику. Он достает из ответа формы counter_id, preset, даты и attribution, проверяет счетчик и формат дат, добавляет понятные названия (preset_title, attribution_title) и chat_id чата из Telegram. На выходе получается один аккуратный item.
Протестируйте этот шаг, нажав на кнопку Execute step. В выходных данных вы должны увидеть сформировать файл:

Тестирование шага
Это HTML-страница со статистикой вашего счетчика Яндекс Метрики. Вы можете скачать этот файл, нажав на кнопку Download, сохранить его на компьютере, а затем открыть как обычную вкладку браузера:

Пример полученной статистики Яндекс Метрики (в формате HTML)
Таким образом, мы получили готовый файл HTML, который теперь необходимо отправить в нашего Telegram-бота. Для этого нажмите на иконку + у последнего узла Code и в строке поиска введите Telegram. Выберите Action - Send a document:

Telegram - Send a document
Настройки, которые вам нужно задать для финального узла-действия, следующие:
- Credential - ваши учетные данные Telegram-бота;
- Resource - Message;
- Operation - Send Document;
- Chat ID - ваш идентификатор чата (можете ввести вручную);
- Binary File - включено.

Настройки узла-действия Send a document
Чтобы передавать вместе с документом текстовую подпись (например, тип шаблона, диапазоны дат или какой-то комментарий), мы можем добавить дополнительную опцию Caption:

Additional Fields - Add Field - Caption
Например, такой текст:
<table><tbody><tr><td data-settings="show"><div><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p></div></td><td><div><p>Отчет<span> </span>по<span> </span>Яндекс<span> </span>Метрике<span> </span>готов<span> </span>✅</p><p>Дата<span> </span>начала<span>:</span></p><p>Дата<span> </span>окончания<span>:</span></p><p>Шаблон<span>:</span></p><p>Модель<span> </span>атрибуции<span>:</span></p><p>Количество<span> </span>строк<span>:</span></p></div></td></tr></tbody></table>
Напротив каждого пункта подставьте свое поле из входных данных. При отправке значения подставятся динамически:

Подпись к документу в Telegram
Он отобразится прямо под документом в чате Telegram.
Вы также можете добавить поле File Name и подставить для него поле fileName, в котором сохраняется название файла:

Поле File Name для названия документа
На этом настройка рабочего процесса в n8n для получения статистики из Яндекс Метрики завершена!
Запустите свой workflow и убедитесь, что HTML-документ с данными и подписью приходит в вашего бота Telegram:

Статистика Яндекс Метрики в Telegram-боте
В завершение активируйте (опубликуйте) workflow, чтобы он работал постоянно. Для этого в правом верхнем углу нажмите на кнопку Publish:

Workflow - Publish
Теперь ваш Telegram-бот сможет в любой момент принимать команды и присылать статистику ваших счетчиков Яндекс Метрики:

Опубликованный рабочий процесс
Источник публикации: Осипенков.ру



Что думаете?
Загружаем комментарии…