Заявка с Тильды пришла на почту, но вы увидели её через три часа — клиент уже ушёл к конкуренту. Telegram-уведомления решают эту проблему: сообщение приходит за секунду. Разберём три способа настройки — от простого вебхука до серверлесс-функции.
Способ 1: прямой вебхук на Telegram Bot API
Самый быстрый вариант. Тильда отправляет данные формы на ваш endpoint, а тот пересылает их в Telegram. Но есть нюанс — Тильда не умеет отправлять напрямую в Bot API. Нужна прослойка.
Шаг 1: создаём бота
Откройте @BotFather в Telegram, отправьте /newbot, задайте имя и username. Сохраните токен — он выглядит так: 7123456789:AAH...
Шаг 2: узнаём chat_id
Отправьте боту любое сообщение, затем откройте в браузере:
curl "https://api.telegram.org/bot<TOKEN>/getUpdates"
В ответе найдите "chat":{"id":123456789} — это ваш chat_id. Для группового чата id будет отрицательным.
Шаг 3: серверная прослойка на Python
Минимальный скрипт, который принимает POST от Тильды и пересылает в Telegram:
from fastapi import FastAPI, Request
import httpx
app = FastAPI()
BOT_TOKEN = "7123456789:AAH..."
CHAT_ID = "123456789"
@app.post("/webhook/tilda")
async def tilda_webhook(request: Request):
data = await request.form()
lines = ["<b>Новая заявка с сайта</b>\n"]
field_names = {
"Name": "Имя",
"Phone": "Телефон",
"Email": "Email",
"Message": "Сообщение",
}
for key, value in data.items():
if key.startswith("tilda") or not value:
continue
label = field_names.get(key, key)
lines.append(f"<b>{label}:</b> {value}")
text = "\n".join(lines)
async with httpx.AsyncClient() as client:
resp = await client.post(
f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage",
json={
"chat_id": CHAT_ID,
"text": text,
"parse_mode": "HTML",
},
)
if resp.status_code != 200:
return {"ok": False, "error": resp.text}
return {"ok": True}
В настройках формы на Тильде: «Ещё» → «Webhook» → вставьте URL вашего сервера (https://yourdomain.com/webhook/tilda).
Способ 2: через n8n (no-code)
Если не хотите писать код — используйте n8n. Это open-source платформа автоматизации, можно развернуть бесплатно на своём сервере или использовать n8n.cloud.
Схема workflow
- Webhook — принимает POST от Тильды
- Set — форматирует текст сообщения
- Telegram — отправляет сообщение через Bot API
Настройка ноды Webhook
Создайте workflow, добавьте ноду «Webhook»:
— HTTP Method: POST
— Path: tilda-lead
— Response Mode: Last Node
Скопируйте Production URL — его вставите в настройки формы Тильды.
Настройка ноды Set (форматирование)
Добавьте ноду «Set» и настройте expression для текста:
// Expression в поле "text"
{{ "📋 *Новая заявка*\n\n" +
"*Имя:* " + ($json.body.Name || "—") + "\n" +
"*Телефон:* " + ($json.body.Phone || "—") + "\n" +
"*Email:* " + ($json.body.Email || "—") + "\n" +
"*Сообщение:* " + ($json.body.Message || "—")
}}
Настройка ноды Telegram
Добавьте ноду «Telegram»:
— Operation: Send Message
— Chat ID: ваш chat_id
— Text: подключите output ноды Set
— Parse Mode: Markdown
— Credentials: добавьте Bot Token
Активируйте workflow — готово.
Способ 3: серверлесс-функция (Vercel / Cloudflare Workers)
Бесплатный и надёжный вариант без собственного сервера. Покажу на Vercel.
Структура проекта
tilda-telegram/
├── api/
│ └── webhook.js
├── package.json
└── vercel.json
api/webhook.js
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const BOT_TOKEN = process.env.BOT_TOKEN;
const CHAT_ID = process.env.CHAT_ID;
if (!BOT_TOKEN || !CHAT_ID) {
return res.status(500).json({ error: 'Missing config' });
}
const data = req.body;
const fieldMap = {
Name: 'Имя',
Phone: 'Телефон',
Email: 'Email',
Message: 'Сообщение',
};
let text = '<b>Новая заявка с сайта</b>\n\n';
for (const [key, value] of Object.entries(data)) {
if (key.startsWith('tilda') || !value) continue;
const label = fieldMap[key] || key;
text += `<b>${label}:</b> ${value}\n`;
}
// Добавляем UTM-метки, если есть
const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign'];
const utms = utmKeys
.filter(k => data[k])
.map(k => `${k}=${data[k]}`)
.join(', ');
if (utms) {
text += `\n<i>UTM: ${utms}</i>`;
}
try {
const response = await fetch(
`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: CHAT_ID,
text: text,
parse_mode: 'HTML',
}),
}
);
const result = await response.json();
if (!result.ok) {
console.error('Telegram API error:', result);
return res.status(500).json({ error: 'Telegram send failed' });
}
return res.status(200).json({ ok: true });
} catch (error) {
console.error('Webhook error:', error);
return res.status(500).json({ error: 'Internal error' });
}
}
vercel.json
{
"version": 2,
"builds": [
{ "src": "api/webhook.js", "use": "@vercel/node" }
]
}
Деплой
npm i -g vercel
vercel login
vercel --prod
# Добавляем переменные окружения
vercel env add BOT_TOKEN
vercel env add CHAT_ID
Webhook URL: https://your-project.vercel.app/api/webhook
Форматирование сообщений
Telegram поддерживает HTML и Markdown. Рекомендую HTML — он предсказуемее:
<b>Жирный текст</b>
<i>Курсив</i>
<code>Моноширинный</code>
<a href="https://example.com">Ссылка</a>
<pre>Блок кода</pre>
<s>Зачёркнутый</s>
Не используйте вложенные теги — Telegram их не поддерживает. <b><i>текст</i></b> не сработает.
Обработка ошибок и дублей
Тильда может отправить вебхук повторно, если не получила 200 в ответ. Добавьте защиту от дублей:
const processedIds = new Set();
export default async function handler(req, res) {
const formId = req.body.tranid || req.body.formid;
if (formId && processedIds.has(formId)) {
return res.status(200).json({ ok: true, duplicate: true });
}
if (formId) {
processedIds.add(formId);
// Очищаем старые записи через 10 минут
setTimeout(() => processedIds.delete(formId), 600000);
}
// ... основная логика
}
Для продакшена вместо Set используйте Redis или KV-хранилище Vercel/Cloudflare.
Уведомления в несколько чатов
Разные формы — разным менеджерам:
const chatRouting = {
'order': '-100123456789', // чат отдела продаж
'support': '-100987654321', // чат поддержки
'default': '123456789', // личный чат владельца
};
function getChatId(formData) {
const formName = (formData.formname || '').toLowerCase();
if (formName.includes('заказ')) return chatRouting.order;
if (formName.includes('поддержк')) return chatRouting.support;
return chatRouting.default;
}
Сравнение способов
| Критерий | Прямой вебхук | n8n | Serverless |
|---|---|---|---|
| Сложность | Средняя | Низкая | Средняя |
| Стоимость | VPS от 300 ₽/мес | Бесплатно (self-hosted) | Бесплатно (Vercel free tier) |
| Надёжность | Зависит от сервера | Зависит от сервера | Высокая (CDN) |
| Кастомизация | Полная | Через ноды | Полная |
| Обслуживание | Сервер, SSL, uptime | Обновления n8n | Минимальное |
Для большинства случаев рекомендую серверлесс-функцию на Vercel — бесплатно, быстро, не нужно следить за сервером. Если уже используете n8n для других автоматизаций — добавьте Telegram как ещё один workflow.
Есть идея? Реализуем
Разрабатываем проекты, которые решают задачи бизнеса — от лендинга до сложного сервиса. Расскажите о своей задаче, подберём решение.

