Форма работает, заявки сохраняются в базу. Но мы пока не знаем, что происходит на сайте: сколько людей зашло, сколько кликнуло на кнопку, какой процент оставил заявку. Добавим события конверсии и научим сайт принимать события извне.
Представьте: вы запустили лендинг, за неделю пришло 5 заявок. Это хорошо или плохо? Без данных — непонятно. Может, на сайт зашло 10 человек и 5 оставили заявку — отличный результат. А может зашло 10 000, и конверсия — 0.05%.
События конверсии — это записи о ключевых действиях посетителей. Они показывают, где люди «отваливаются» и что можно улучшить.
Воронка — это путь посетителя от первого визита до целевого действия. На каждом шаге часть людей уходит, и это нормально. Наша воронка:
Например: 1000 посещений -> 100 кликов -> 10 заявок. Конверсия из посещения в заявку — 1%. Теперь вы знаете, на каком шаге теряете больше всего людей, и можете это исправить.
Все эти события мы будем записывать в таблицу EventLog, которую создали на предыдущем шаге.
Добавь отслеживание событий конверсии на лендинг.
Три типа событий, все пишутся в таблицу EventLog:
1. landing_view — при загрузке страницы.
Source: internal, payload: URL, referrer
2. cta_click — при клике на кнопку CTA
или при скролле до формы.
Source: internal, payload: тип действия
3. lead_created — при успешном создании лида
(уже есть API, нужно просто добавить запись
в EventLog при создании Lead).
Source: internal, payload: id лида
Каждое событие должно содержать visitor_id
(если есть) и created_at.
Webhook — это когда внешний сервис сам отправляет данные на ваш сайт. Не вы ходите к нему за информацией, а он присылает её вам, когда что-то произошло.
Примеры из жизни:
Для нашего лендинга мы создадим webhook inbox — адрес внутри нашего приложения, который принимает любые входящие события и записывает их в тот же EventLog.
Webhook-адрес доступен из интернета, а значит, кто угодно может отправить на него данные. Чтобы этого не допустить, используют секрет — пароль, который знают только ваш сервер и отправитель.
Отправитель передаёт секрет в заголовке запроса. Сервер проверяет — если секрет не совпадает, возвращает ошибку 401 (не авторизован).
На предыдущем шаге мы добавили в EventLog поле idempotency_key — уникальный ключ события. Вот зачем он нужен: иногда внешний сервис отправляет одно и то же событие несколько раз — например, если не получил подтверждения. Без защиты каждая повторная отправка создаст дубль в базе.
Идемпотентность решает эту проблему. Каждое событие приходит с уникальным ключом. Если запись с таким ключом уже есть — сервер просто игнорирует повтор и возвращает успех. Для внутренних событий (с сайта) ключ тоже должен быть заполнен — мы упоминали это в предыдущей главе.
Создай webhook inbox — адрес POST /api/webhook
в нашем приложении, который:
1. Проверяет секрет в заголовке
X-Webhook-Secret. Если не совпадает —
вернуть ошибку 401.
2. Принимает данные с полями:
тип события, полезные данные и уникальный
ключ для защиты от дублей.
3. Если событие с таким ключом уже есть —
вернуть успех, но ничего не записывать.
4. Сохраняет событие в EventLog как внешнее
(source: external).
Секрет хранить в переменной окружения
WEBHOOK_SECRET. Добавь его в .env и .env.example.
Перезапускаем контейнеры:
user@computer:~/landing$ docker compose up --buildОткройте лендинг в браузере, прокрутите до формы, отправьте заявку. Потом попросите агента показать записи в EventLog — там должны быть landing_view, cta_click и lead_created.
Откройте консоль браузера (F12 -> Console) и выполните:
fetch('/api/webhook', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Secret': 'ваш-секрет'
},
body: JSON.stringify({
type: 'test_event',
payload: { message: 'hello' },
idempotency_key: 'test-123'
})
})
Отправьте тот же запрос ещё раз — второй раз запись не должна создаться. Это и есть идемпотентность в действии.
user@computer:~/landing$ ./scripts/deploy.sh <ваш-IP> ~/.ssh/my-project deployНе забудьте добавить переменную WEBHOOK_SECRET в .env на сервере. Попросите агента помочь, если не знаете как.
Перед коммитом попросите агента обновить README:
Обнови README.md — добавь раздел про аналитику:
какие события отслеживаются, как работает
webhook inbox, где хранится WEBHOOK_SECRET.
После этого сделай коммит.
Мы записываем события и принимаем данные извне. Но узнавать о новых заявках можно только заглядывая в базу. В следующей главе подключим Telegram — и уведомления будут приходить прямо в чат.