Максим Игошев.

Форма заявки, которая действительно доходит: разбираю свою

Большинство форм показывают «спасибо» независимо от того, дошла заявка или нет. Разбираю по шагам форму этого сайта: работа без JavaScript, отсев ботов без капчи и честное поведение при сбое доставки.

Форма на сайте выглядит простой задачей, пока не задашь один вопрос: что происходит, когда отправка не удалась.

Большинство форм отвечают «спасибо, скоро свяжемся» в любом случае. Человек уходит довольным, заявка не дошла никуда, и узнаёте вы об этом через месяц, когда кто-то напишет «я вам писал, вы не ответили». Это не редкая авария, это обычное поведение по умолчанию.

Разберу форму этого сайта целиком: она открыта в репозитории, так что всё ниже можно проверить.

Вертикальная схема. Форма на странице отправляет обычный POST в функцию /api/lead. Функция сначала проверяет скрытую ловушку и время заполнения: похожая на бота отправка получает ответ как при успехе и дальше не идёт. Настоящая заявка уходит в телеграм, это обязательный канал, и параллельно копией в таблицу, сбой которой на доставку не влияет. Если телеграм принял, человек видит страницу «спасибо», если нет, страницу с адресом почты. Форма на странице обычный POST, без JavaScript Функция /api/lead ловушка и время заполнения Похоже на бота ответ как при успехе Телеграм обязательный канал Таблица копия, может молчать доставлено не доставлено Страница «спасибо» Страница с почтой
Путь заявки от формы до сообщения

Она работает без JavaScript

Форма — обычный <form method="post" action="/api/lead">. Никакого перехвата отправки ради красоты.

Это не про принципиальность, а про доставку. JavaScript не выполняется чаще, чем кажется: экономия трафика в мобильном браузере, блокировщик, который зацепил лишнее, медленная сеть, где человек успел нажать кнопку до загрузки скриптов, режим чтения. Если отправка держится на скрипте, все эти заявки просто исчезают, причём бесшумно: в аналитике их не будет, потому что аналитика тоже на скрипте.

Браузер умеет отправлять формы сам, тридцать лет как. Сервер принимает FormData и отвечает редиректом на страницу «спасибо». Скрипт на странице нужен только для мелочей: подставить UTM-метки и отправить фоном, чтобы страница не перезагружалась. Выключите его — всё продолжит работать, только с перезагрузкой.

Боты отсеиваются без капчи

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

Вместо неё два незаметных фильтра.

Первый — скрытое поле website, спрятанное от глаз и помеченное aria-hidden, чтобы его не увидел и скринридер. Человек его не заполнит, потому что не видит. Боты заполняют формы по именам полей и в поле с именем «website» охотно пишут адрес.

Второй — время. Страница проставляет скрытую метку момента загрузки, и отправка быстрее трёх секунд считается машинной. Живой человек физически не успевает прочитать три поля и написать осмысленную задачу за это время.

Важная деталь в том, что происходит дальше. Пойманная отправка получает ровно такой же ответ, как успешная: тот же редирект на «спасибо», тот же {"ok": true}. Бот не узнаёт, что его отсекли, и не начинает подбирать обход. Отличить снаружи нельзя, в логе остаётся строчка.

Длинный текст обрезается, а не отклоняется

У каждого поля есть предел: сто символов на имя, двести на контакт, три тысячи на описание задачи. Но превышение не отклоняет заявку, а подрезает значение.

Разница существенная. Человек, который написал подробное описание на четыре тысячи знаков, — это хороший человек, он уже вложился. Ответить ему «слишком длинно, перепишите» означает потерять его на ровном месте. Пусть лучше придёт укороченным, остальное спросите в переписке.

Два получателя с разной важностью

Заявка уходит в два места, и они неравноправны.

Телеграм — обязательный канал. Не дошло туда — значит, не дошло вообще.

Таблица — копия. Если вебхук таблицы отвалился или отвечает ошибкой, в лог падает строка, а доставка продолжается как ни в чём не бывало. Копия для истории не должна иметь права уронить основной канал. Это общее правило для любой такой связки: решите заранее, что именно обязательно, и не позволяйте необязательному блокировать обязательное.

У обоих вызовов стоит таймаут в восемь секунд. Без него зависший провайдер держал бы человека на белом экране до таймаута самой функции.

Самое главное: что видно при сбое

Если телеграм не принял сообщение, человек не увидит «спасибо». Он увидит страницу, где написано, что отправить не получилось, и стоит кнопка написать на почту напрямую.

Это неприятно показывать и правильно показывать. Заявка не теряется: человек в этот момент максимально мотивирован, он уже всё написал, и один клик уводит его в почту. Ложное «спасибо» в той же ситуации теряет его целиком, и тихо.

То же решение я заложил в голосового администратора: когда агент дважды не смог записать email, он не делает вид, что всё в порядке, а помечает запись и отдаёт человеку. Принцип один — сбой нужно показывать тому, кто может на него среагировать.

Что забрать себе

Четыре правила, не зависящие от стека.

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

Код формы и серверной функции открыт в репозитории сайта. Нужна такая же связка под ваш сайт и вашу CRM — опишите задачу.

  • Автоматизация
  • Формы
  • Телеграм
  • Приём заявок