Diil Docs
  1. Документация
  2. Виджет

Заявки: формы сайта прямо в CRM

Обновлено:

Форма обратной связи, которая шлёт письмо сотруднику в отпуске, — кладбище заявок. В Diil каждая форма вашего сайта превращается в карточку в CRM: с телефоном или почтой, состоянием и ответственным, который перезвонит. Хватит одного атрибута на <form>, а если нужно больше контроля — есть JavaScript и отправка с сервера.

Отправить заявку можно тремя способами — выбирайте подходящий:

  • Форма с data-crm-lead — ноль JavaScript. Виджет сам перехватывает отправку и делает остальное.
  • window.crmLead() — для React, Vue и любых форм, состоянием которых вы управляете сами.
  • POST /marketing/lead с вашего сервера — заказы по телефону, формы на бэкенде, интеграции с другими системами.

Как заявка попадает из формы в CRM

Заявка в Diil — это особый вид события. У каждого события есть имя, например contact_form, и это имя сначала нужно завести в CRM. Отметьте у него «Это заявка» — и каждая отправка с таким именем станет карточкой в CRM → Заявки.

  1. Посетитель заполняет форму и жмёт «Отправить».
  2. Виджет собирает поля, разбирается, где имя, телефон, почта и сообщение, и отправляет.
  3. Сервер проверяет, что имя события заведено, в заявке есть телефон или почта и она не похожа на бота.
  4. В CRM появляется карточка заявки, а если настроено — ещё и уведомление в Telegram.

Два правила, которые стоит запомнить сразу:

  • Незаведённое имя отклоняется. CRM принимает только то, о чём знает, — опечатки не превращаются в мусор.
  • Заведено, но без отметки «Это заявка»? Тогда отправка сохранится как обычное событие, а карточки заявки не будет.

Заведите тип заявки в CRM

Пара минут кликов, один раз на каждый вид формы:

  1. Откройте Маркетинг → События

    Здесь описываются все события, которые может присылать ваш сайт.
  2. Создайте событие

    Дайте ему имя, которое будет в коде: латиница, цифры и подчёркивания, первой — буква: contact_form, callback_request, quote_request.
  3. Отметьте «Это заявка»

    Теперь отправки становятся карточками. Как подсказывает сама CRM, форма должна прислать способ связи — телефон или почту.
  4. По желанию: отметьте «Событие приносит деньги»

    Только тогда у заявки сохранятся сумма и валюта. Без этой отметки они тихо игнорируются.

Способ A: форма с одним атрибутом

Добавьте data-crm-lead="имя_события" любой форме на странице, где подключён скрипт виджета. Это вся интеграция. Формы, которые появляются позже — в модальном окне, после перехода в одностраничном приложении, — подхватываются автоматически.

Полный пример

Форма «Запросить расчёт»: имя, телефон, почта и сообщение, сумма для отчёта по выручке, «спасибо» после отправки и своя проверка. Сначала чистый HTML; версии для React и Vue вызывают crmLead() из собственного обработчика отправки.

<form id="quote" data-crm-lead="quote_request" data-crm-value="149900" data-crm-currency="EUR">
  <label>Ваше имя <input name="name" autocomplete="name" required></label>
  <label>Телефон <input name="phone" type="tel" autocomplete="tel"></label>
  <label>Почта <input name="email" type="email" autocomplete="email"></label>
  <label>Что нужно сделать? <textarea name="message" rows="4"></textarea></label>

  <!-- Не из списка известных полей: попадёт в карточку заявки как есть -->
  <label>Размер команды
    <select name="team_size">
      <option>1–5</option>
      <option>6–20</option>
      <option>20+</option>
    </select>
  </label>

  <button type="submit">Отправить</button>
  <p class="form-status" role="status" hidden></p>
</form>

<script>
  const form = document.getElementById('quote');
  const status = form.querySelector('.form-status');
  const button = form.querySelector('button');

  function say(text) {
    status.textContent = text;
    status.hidden = false;
  }

  // 1. Перед отправкой: своя проверка. preventDefault() = ничего не уйдёт
  form.addEventListener('crm:lead-before', (event) => {
    const phone = form.elements.phone.value.trim();
    const email = form.elements.email.value.trim();
    if (!phone && !email) {
      event.preventDefault();
      say('Оставьте телефон или почту, чтобы мы могли ответить.');
      return;
    }
    button.disabled = true;
  });

  // 2. После отправки: виджет ничего не показывает, «спасибо» — за вами
  form.addEventListener('crm:lead', (event) => {
    button.disabled = false;
    say(event.detail.ok
      ? 'Спасибо! Ответим в течение рабочего дня.'
      : 'Что-то пошло не так. Попробуйте ещё раз или позвоните нам.');
  });
</script>

<script src="https://widget.sitecog.com/widget.js" defer></script>

Что происходит при отправке формы

  1. Виджет всегда отменяет обычную отправку — страница не перезагружается, action формы не используется.
  2. Генерирует на форме событие crm:lead-before. Если какой-нибудь обработчик вызовет event.preventDefault(), на этом всё — ничего не отправится.
  3. Собирает поля через FormData — кроме исключённых: паролей, полей с data-crm-ignore и полей с «чувствительными» именами. Учитываются только текстовые значения: поля с файлами пропускаются. Несколько полей с одним именем (группа чекбоксов) склеиваются через ", ".
  4. Отправляет заявку под защитой одноразового пропуска формы (подробнее — в разделе о защите от спама).
  5. Генерирует crm:lead с { ok: true } или { ok: false } в event.detail.
  6. Если ok равно true, вызывает form.reset(). При неудаче форма остаётся как есть — посетитель не потеряет набранное.

Своего интерфейса у виджета нет: ни всплывашки, ни спиннера, ни «спасибо». Сайт ваш, дизайн ваш, слова тоже ваши — слушайте crm:lead и показывайте что угодно.

Атрибуты формы

АтрибутПримерЧто делает
data-crm-lead"quote_request"Превращает форму в форму заявки. Значение — имя события, заведённого в CRM. Пустой атрибут означает имя lead_submit — его тоже нужно завести.
data-crm-value"149900"Сумма в минимальных единицах, целым числом: 149900 — это 1499,00. Сохраняется, только если у события отмечено «Событие приносит деньги».
data-crm-currency"EUR"Валюта суммы: EUR, USD, UAH…
data-crm-ignoreбез значенияСтавится не на форму, а на поле или любую обёртку (fieldset, div…): само поле или всё, что внутри обёртки, в заявку не попадёт. См. поля, которые никогда не отправляются.

События формы

Оба события всплывают, поэтому слушать их можно на самой форме или один раз на document — сразу для всех форм страницы.

СобытиеКогдаevent.detailМожно отменить
crm:lead-beforeСразу после отправки формы, до любых запросов{ name } — имя событияДа: preventDefault() отменяет отправку
crm:leadПосле ответа сервера{ ok } — true, если заявка принятаНет
Один обработчик для всех форм заявок на страницеjs
document.addEventListener('crm:lead', (event) => {
  if (event.detail.ok) {
    event.target.closest('.modal')?.classList.add('is-thanks');
  }
});

Какие имена полей понимает CRM

В карточке заявки четыре главных места: имя, телефон, почта и сообщение. Виджет раскладывает данные по именам полей: обрезает пробелы, переводит в нижний регистр и сверяет с этим списком точно (так что Phone сработает, а your-phone — нет):

МестоИмена полейМаксимум символов
Имяname, fio, username, user_name, fullname, full_name, firstname, first_name, contact_name, client_name, имя, фио, ім'я200
Телефонphone, tel, telephone, mobile, phone_number, contact_phone, телефон, тел40
Почтаemail, e_mail, e-mail, mail, contact_email, почта, пошта, емейл320
Сообщениеmessage, comment, comments, text, question, note, description, task, сообщение, комментарий, вопрос, повідомлення, коментар4000
  • Побеждает первое совпадение. Если в форме есть и phone, и mobile, место займёт то поле, что идёт в форме раньше.
  • Остальное тоже не теряется. Незнакомые поля и повторные совпадения попадают в «дополнительные» и показываются в карточке в порядке формы. До 30 таких полей; имя — до 60 символов, значение — до 1000.
  • Телефон засчитывается, только если в нём от 7 до 20 цифр. Пробелы, скобки и дефисы не мешают; плюс в начале сохраняется.
  • Телефон или почта обязательны. Заявка без того и другого отклоняется с no_contact — ответить-то некуда.

Поля, которые никогда не отправляются

Форма регистрации с паролем или оплата с номером карты тоже могут оказаться формой заявки. Чтобы такие данные случайно не осели в CRM, кое-что виджет просто не отправляет:

  • Пароли — любые <input type="password">.
  • Всё, что помечено data-crm-ignore. Атрибут можно поставить на само поле или на любую обёртку — fieldset, div, что угодно: тогда пропускается всё внутри.
  • Поля с «чувствительными» именами. Имя разбивается на слова (по _, -, ., camelCase и так далее), и поле отбрасывается, если отдельным словом в нём стоит card, cc, csc, cvv, cvc, iban, ssn, secret или pass — либо если где угодно в имени встречается password, passwd, pwd, token, csrf, xsrf, creditcard, cardnumber или ccnum.
Имя поляУйдёт в заявку?Почему
card_numberнетcard — отдельное слово
cvvнетв списке слов
csrf_tokenнетсодержит csrf и token
user_passwordнетсодержит password
discard_reasonдаcard здесь часть слова discard, а не отдельное слово

Ещё пара деталей:

  • Исключение действует на имя целиком. Если хотя бы одно поле с каким-то именем отброшено, отбрасываются все поля с этим именем.
  • Скрытые поля отправляются. <input type="hidden"> — удобный способ передать товар, тариф или страницу. Если, конечно, его имя не из списка выше.
  • Сервер страхует. Тот же фильтр применяется и на нашей стороне — в том числе к заявкам с сервера. Так что чувствительное поле в CRM не попадёт никаким путём.
Что уйдёт, а что нетhtml
<form data-crm-lead="signup_request">
  <input name="email" type="email">            <!-- уйдёт: это почта заявки -->
  <input name="password" type="password">      <!-- не уйдёт: пароль -->

  <fieldset data-crm-ignore>                   <!-- всё внутри пропускается -->
    <input name="company_inn">
    <input name="billing_address">
  </fieldset>

  <input type="hidden" name="plan" value="pro"> <!-- уйдёт: скрытое поле с обычным именем -->
  <input name="card_number">                   <!-- не уйдёт: card — отдельное слово -->

  <button type="submit">Отправить</button>
</form>

Способ B: отправка из JavaScript

Если состоянием формы управляете вы — React, Vue, многошаговый мастер, чат-бот, — вызывайте виджет напрямую. Обе функции появляются в window, как только загрузится widget.js.

crmLead(name, fields, options)

const { ok } = await window.crmLead(
  'callback_request',
  { name: 'Анна', phone: '+49 30 1234567', message: 'Перезвоните после 17:00, пожалуйста' },
  { value: 149900, currency: 'EUR' },
);
namestringобязательно
Имя события, заведённого в CRM с отметкой «Это заявка». Латиница, цифры и подчёркивания, первой — буква (^[A-Za-z][A-Za-z0-9_]*$). С неподходящим именем в консоли появится предупреждение, а вернётся { ok: false }.
fieldsobjectобязательно
Данные формы — простые пары «ключ — значение». Ключи разбираются по тем же правилам имён, что и в формах: знакомые заполняют имя, телефон, почту и сообщение, остальные уходят в «дополнительные». Ключи с чувствительными именами (password, card_number…) отбрасываются так же, как поля формы.
options.valueintegerнеобязательно
Сумма в минимальных единицах: 149900 = 1499,00. Сохраняется только у событий с отметкой «Событие приносит деньги».
options.currencystringнеобязательно
Валюта суммы, например EUR.

Возвращает Promise, который разрешается в:

okboolean
true — заявка принята. false — отклонена или не дошла; причину мы намеренно не сообщаем (почему).

crmLeadForm(form, name)

Делает ровно то же, что атрибут data-crm-lead, только из кода. Пригодится, когда форму рисует сторонняя библиотека и атрибут ей не добавить или когда имя события выясняется на лету. Ничего не возвращает; результат приходит тем же событием crm:lead.

const form = document.querySelector('#newsletter-popup form');
window.crmLeadForm(form, 'newsletter_signup');

form.addEventListener('crm:lead', (e) => {
  if (e.detail.ok) form.innerHTML = '<p>Готово! Загляните в почту.</p>';
});
formHTMLFormElementобязательно
Элемент формы, который нужно подключить.
namestringобязательно
Имя события, заведённого в CRM, — по тем же правилам, что и в crmLead.

Типы для TypeScript

Виджет — обычный скрипт, и TypeScript о нём ничего не знает. Добавьте это в любой файл .d.ts:

crm-widget.d.tsts
export {};

declare global {
  interface Window {
    crmLead?: (
      name: string,
      fields: Record<string, string>,
      options?: { value?: number; currency?: string },
    ) => Promise<{ ok: boolean }>;
    crmLeadForm?: (form: HTMLFormElement, name: string) => void;
  }
}

Как устроена защита от спама

Открытая форма притягивает ботов как магнит. Капча, чтобы их отвадить, не нужна: виджет и сервер справляются вдвоём, а живые посетители ничего не замечают.

Одноразовый пропуск формы

Перед отправкой виджет получает у сервера подписанный «пропуск формы». Чтобы не терять время, он запрашивает его, как только посетитель впервые ставит курсор в форму. Пропуск:

  • одноразовый — один пропуск, одна заявка;
  • привязан к вашему сайту — с другого сайта он бесполезен;
  • действует 24 часа.

Боты, которые вслепую шлют POST на адрес приёма, пропуска не имеют и получают отказ. А двойной клик или повторная отправка с тем же пропуском вернут { ok: true }, но заявка сохранится один раз — никаких дублей от нетерпеливых пальцев.

Ловушка для ботов

То самое скрытое поле company_site. Человек его не видит, и оно остаётся пустым. Бот, который заполняет всё, что находит, выдаёт себя — и заявка отклоняется.

«Подозрительные» заявки

Некоторые заявки выглядят странно, но могут оказаться настоящими. Такие принимаются и получают в CRM пометку «подозрительная» — менеджер посмотрит на неё, прежде чем звонить:

  • форму заполнили меньше чем за 3 секунды — быстрее, чем способен человек;
  • форма провисела открытой больше 30 минут;
  • с одного IP-адреса за час пришло больше 5 заявок.

«Спам» — это состояние, которое человек ставит в CRM вручную. Автоматически в спам ничего не попадает, так что настоящий клиент молча не потеряется.

IP-адрес в карточке заявки показывается усечённым: у IPv4 последний октет обнуляется (203.0.113.57 → 203.0.113.0), IPv6 обрезается до /48. Полный адрес мы не храним — подробнее в разделе Что мы храним и сколько.

Почему браузер получает только ok: true или false

Сообщить боту «отклонено: заполнена ловушка» — значит бесплатно научить его проходить защиту. Поэтому для браузера любой отказ выглядит одинаково: { ok: false }, без причины. Отлаживаете свою форму? Список типичных проблем покрывает все случаи, а серверный способ честно называет ошибку — он ведь защищён секретным ключом.

Под капотом: запрос из браузера

Для любопытных — собирать это вручную не придётся. Виджет получает пропуск в POST https://back.sitecog.com/marketing/fk (ответ: {"pass":"…"}), а затем отправляет заявку:

Что отправляет виджетhttp
POST https://back.sitecog.com/marketing/f
Content-Type: application/json

{
  "n": "contact_form",
  "pass": "…",
  "fields": {
    "name": "Анна",
    "email": "anna@example.com",
    "message": "Здравствуйте!",
    "company_site": ""
  },
  "val": 149900,
  "cur": "EUR",
  "u": "https://shop.example/contacts",
  "vid": "…",
  "sid": "…"
}

В ответ приходит { "ok": true } или { "ok": false }. vid и sid — идентификаторы посетителя и сессии: благодаря им заявка связывается с рекламным каналом, из которого пришёл человек. Подробнее — в разделе События и аналитика.

Отправка заявок с сервера

Не каждая заявка начинается в браузере. Серверный способ нужен, когда:

  • менеджер принимает заказ по телефону и вносит его в вашу учётную систему;
  • форма обрабатывается на бэкенде (обработчик на PHP, server action в Next.js), и зависеть от виджета не хочется;
  • заявки приходят из другой системы: маркетплейса, сервиса бронирования, бота.
POST https://back.sitecog.com/marketing/lead
x-event-key: sk_…
Content-Type: application/json

Секретные ключи

Серверный способ работает по секретному ключу. Создайте его в CRM → Маркетинг → События → Секретные ключи → Выпустить ключ. Ключ выглядит как sk_ и 48 шестнадцатеричных символов; у сайта может быть до 5 активных ключей, любой можно отозвать. Называйте ключи по месту использования («платёжный сервер», «заказы по телефону») — когда придёт время отзывать, вы себе спасибо скажете.

Пример запроса

curl https://back.sitecog.com/marketing/lead \
  -H "x-event-key: sk_3f9a1c7e5b2d4f6a8c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "phone_order",
    "event_id": "order-1024",
    "fields": {
      "name": "Анна Шмидт",
      "phone": "+49 30 1234567",
      "message": "Две пары Air 3, графит. Доставка в офис."
    },
    "value": 149900,
    "currency": "EUR",
    "url": "https://shop.example/contacts"
  }'

Тело запроса

x-event-keyheaderstringобязательно
Секретный ключ sk_… из CRM. Нет ключа или он отозван → 401 invalid_key.
namestringобязательно
Имя события, заведённого в CRM с отметкой «Это заявка». Короткий вариант: n.
fieldsobjectобязательно
Сама заявка: имя, телефон, почта, сообщение и всё остальное — по тем же правилам имён. Телефон или почта обязательны. Контакты всегда кладите сюда: ключи из корня тела запроса подмешиваются в заявку. Поля с чувствительными именами сервер отбрасывает и здесь, даже при запросе с секретным ключом.
event_idstringнеобязательно
Ваш идентификатор заявки, до 128 символов: номер заказа, номер обращения. Делает запрос идемпотентным. Короткий вариант: id.
visitor_idstringнеобязательно
Идентификатор посетителя из браузера (crm_vid). Короткий вариант: vid. См. атрибуцию.
session_idstringнеобязательно
Идентификатор сессии из браузера (crm_sid). С ним заявка наследует рекламный канал и UTM-метки этой сессии. Короткий вариант: sid.
valueintegerнеобязательно
Сумма в минимальных единицах: 149900 = 1499,00. Сохраняется только у событий с отметкой «Событие приносит деньги». Короткий вариант: val.
currencystringнеобязательно
Валюта суммы, например EUR. Короткий вариант: cur.
urlstringнеобязательно
Страница, к которой относится заявка или с которой она пришла. Короткий вариант: u.

Ответ

200 OKjson
{ "ok": true, "duplicate": false }
okboolean
При ответе 200 всегда true. Проблемы приходят кодами 4xx с полем message — см. ошибки.
duplicateboolean
true, если заявка с таким event_id уже есть. Ничего нового не сохранилось — и это нормально.

В отличие от браузера, на сервере нет ни пропусков формы, ни проверок по времени: секретного ключа достаточно. А вот ловушка действует: непустое company_site в fields получит 400 rejected.

Идемпотентность: повторяйте без страха

Сеть падает в самый неподходящий момент. Дошёл запрос или нет? С event_id это неважно: просто отправьте ещё раз. Повтор вернёт {"ok":true,"duplicate":true}, и заявка не сохранится дважды.

Тот же event_id, второй разjson
{ "ok": true, "duplicate": true }

Атрибуция: какая реклама привела заявку

Заявки из виджета связываются с посетителем автоматически. Серверная заявка о браузере ничего не знает — пока вы ей не расскажете. Виджет хранит идентификатор посетителя в localStorage под ключом crm_vid, а идентификатор сессии — под crm_sid. Передайте их на бэкенд вместе с формой или заказом, а оттуда — дальше:

В браузере, при оформлении заказаjs
const crm = {
  vid: localStorage.getItem('crm_vid'),
  sid: localStorage.getItem('crm_sid'),
};

await fetch('/api/orders', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ ...order, crm }),
});
// …а на сервере: visitor_id: body.crm.vid, session_id: body.crm.sid

С session_id заявка наследует рекламный канал и UTM-метки первого просмотра этой сессии и попадает в отчёты рядом с кампанией, которая её принесла. Подробнее — в разделе События и аналитика.

Ошибки

В браузере crmLead() и событие crm:lead сообщают только ok: false. Серверный способ отвечает кодом и полем message:

КодТелоЧто случилось
400{"message":"unknown_event","name":"phone_order"}В CRM нет события с таким именем. Заведите его в Маркетинг → События (проверьте написание и регистр).
400{"message":"invalid_event_name"}В имени есть что-то кроме латиницы, цифр и подчёркиваний, или оно начинается не с буквы.
400{"message":"no_contact"}В fields нет ни телефона (7–20 цифр), ни почты.
400{"message":"invalid_body"}Тело запроса — не JSON-объект нужной формы.
400{"message":"rejected"}Заполнено поле-ловушка company_site.
401{"message":"invalid_key"}x-event-key не передан, записан неверно или отозван.
413—Тело запроса больше 8 КБ.
429{"message":"rate_limit_exceeded"}Слишком много запросов за эту минуту. Дождитесь следующей.

Запросы из браузера могут получить ещё 400 unknown_origin или 400 unknown_domain, если домен страницы не заведён в CRM как сайт. Их видно во вкладке Network, а код при этом получает ok: false.

Ограничения

ЧтоПредел
Запросы с одного IP (все маркетинговые адреса вместе)120 в минуту
Запросы на сайт6000 в минуту
Пропуски формы с одного IP20 в минуту
Тело запроса8 КБ
Имя / телефон / почта / сообщение200 / 40 / 320 / 4000 символов
Дополнительные полядо 30; имя — до 60, значение — до 1000 символов
Телефон7–20 цифр, чтобы считаться контактом
event_idдо 128 символов
Секретные ключидо 5 активных на сайт

Окна — фиксированные минуты: после 429 дождитесь начала следующей. Живой посетитель к этим пределам даже не приблизится, а скрипт, долбящий вашу форму, — вполне.

Если что-то не так

Заявка не пришла

Пройдитесь по списку — почти всегда дело в одном из пунктов:

  • Имя не заведено. В Маркетинг → События должно быть событие ровно с таким именем, с учётом регистра. Пустой data-crm-lead означает lead_submit — заведите его.
  • Не отмечено «Это заявка». Тогда отправка сохранилась как обычное событие: ищите её в статистике событий, а не в Заявках.
  • Нет ни телефона, ни почты. Или они есть, но под незнакомыми CRM именами (your-phone, contact[email]) и уехали в «дополнительные». Переименуйте поля — см. таблицу имён. Телефон короче 7 цифр тоже не засчитывается.
  • Данные были в поле с файлом. Файлы пропускаются — виджет отправляет только текст.
  • Настоящее поле называется company_site. Это имя ловушки, и заявку принимают за бота.
  • Ваш же обработчик crm:lead-before вызвал preventDefault() — возможно, не тогда, когда вы ждали.
  • На этой странице нет виджета. Без widget.js атрибут ничего не делает, и форма отправляется по старинке (или никуда).
  • Мешает Content Security Policy. Если у сайта есть CSP, в ней нужны script-src https://widget.sitecog.com и connect-src https://back.sitecog.com. Консоль браузера скажет об этом красным.
  • Домен не заведён в CRM. Сайт определяется по адресу страницы (www. отбрасывается). На localhost или тестовом домене, которого нет в CRM, во вкладке Network будет unknown_domain.
  • Вы очень активно тестировали. 20 пропусков в минуту с одного IP людям хватает с запасом, а вот лихорадочным кликам — нет. Подождите минуту.

Не дошло одно поле

Заявка в CRM есть, а какого-то поля в ней нет? Скорее всего, виджет (или сервер) отбросил его намеренно:

  • У поля «чувствительное» имя. promo_pass отбрасывается, потому что pass в нём — отдельное слово. Переименуйте во что-нибудь нейтральное, например promo_code. Полный список — в разделе Поля, которые никогда не отправляются.
  • Поле или его обёртка помечены data-crm-ignore. Проверьте всех родителей поля, а не только его самого: атрибут на fieldset или div выше по дереву тоже считается.
  • Это type="password" — пароли не отправляются никогда.
  • Где-то в форме есть второе поле с тем же именем, и оно попало под исключение — тогда отбрасываются все поля с этим именем.
  • Это поле с файлом. Файлы пропускаются в любом случае — виджет отправляет только текст.

Не видно суммы

Отметьте у типа события «Событие приносит деньги». И проверьте, что сумма — целое число в минимальных единицах: 1499.00 отправляется как 149900.

Уведомления в Telegram

Заявка, которую никто не увидел, — потерянная заявка. В настройках раздела CRM → Заявки можно подключить Telegram-бота: указать токен бота, включить оповещения, решить, присылать ли подозрительные заявки, и задать тихие часы — чтобы ночная смена ботов не будила отдел продаж.

Уведомления оформлены HTML-разметкой, а всё, что ввёл посетитель, перед отправкой экранируется. «Имя» вида <a href="…">Нажмите сюда</a> придёт обычным текстом: подсунуть ссылку в чат вашей команды или сломать оформление посетитель не сможет. Длинные поля обрезаются, чтобы роман в поле «Сообщение» не превратился в простыню, — заявка целиком всегда есть в CRM.

Удаление данных человека по запросу

«Удалите всё, что у вас обо мне есть» — обычная просьба, и ответ на неё не должен превращаться в неделю раскопок по таблицам. В CRM для этого два инструмента, код с вашей стороны не нужен.

Из заявки или чата

В карточке заявки и в карточке чата есть «Удалить данные посетителя». Перед удалением CRM показывает, что именно уйдёт:

  • профиль посетителя и аналитика — просмотры страниц и события;
  • чаты и вложения — сколько чатов, сообщений и файлов;
  • заявки — только если отметить «Также удалить заявки этого посетителя». По умолчанию выключено: заявка часто — сделка в работе, и решать вам.

Заявка, отправленная с сервера без visitor_id, к посетителю не привязана — у неё удаляется только сама заявка.

По почте или телефону

Обычно просьба приходит письмом: «Я anna@example.com, забудьте меня». Откройте CRM → Настройки → «Запросы на удаление данных», введите почту или телефон, которые указал человек, — и CRM найдёт его заявки, чаты и аккаунт на вашем сайте. Одна кнопка удаляет всё найденное; вместе с ним можно удалить и аналитику посещений связанных посетителей.

  • Права. Для удаления нужны те же права, что и на редактирование этих разделов. Менеджер, который может только смотреть чаты, увидит найденное, но удалить не сможет.
  • Журнал действий. Каждое удаление записывается в журнал — без почты и телефона человека, иначе журнал хранил бы ровно то, что просили забыть.
  • Без отмены. Удалено — значит удалено. Проверьте цифры, прежде чем подтверждать.