Розробка опитувальника на сайті 1С-Бітрікс
Коли ручний збір фідбеку перестає працювати
При запуску нового продукту або після змін у сервісі часто виникає одна й та сама картина: менеджери збирають фідбек вручну через пошту або месенджери, дані губляться, аналітика запізнюється. Нещодавно до нас прийшов клієнт з інтернет-магазину електроніки — їх Net Promoter Score був невідомий, оскільки опитування проводилися раз на півроку по email з відгуком 3%. Ми поставили спливаюче опитувальник на сторінці замовлення, і вже через місяць отримали 1200 відповідей з детальною картиною. За місяць NPS зріс з 20 до 45 — це дозволило оперативно виправити проблемні зони в сервісі доставки. Опитувальник на сайті — єдиний спосіб отримувати структуровані дані без втрат. У Бітріксі немає готового модуля для опитувань пристойного рівня — вбудований iblock можна використовувати для зберігання, але логіку опитування доводиться писати з нуля.
Як реалізувати опитувальник на 1С-Бітрікс?
Збираємо архітектуру на HL-блоках — це швидше та гнучкіше, ніж інфоблоки, в 3 рази при записі даних. Типові сценарії:
- NPS (Net Promoter Score) — шкала 0–10 з коментарем.
- CSAT (Customer Satisfaction) — 1–2 питання після конкретної дії.
- Повноцінний опитувальник — кілька сторінок з різними типами питань, розгалуження, тригери показу.
Структура даних через HL-блоки:
class SurveyTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'b_hl_surveys'; }
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new StringField('TITLE'),
new StringField('SLUG'),
new StringField('TYPE'), // nps | csat | full
new TextField('QUESTIONS_JSON'), // Конфигурация вопросов
new StringField('TRIGGER'), // page_load | exit_intent | scroll_50 | after_order
new IntegerField('SHOW_DELAY'), // Задержка показа в секундах
new BooleanField('IS_ACTIVE', ['values' => [false, true]]),
new DatetimeField('DATE_FROM'),
new DatetimeField('DATE_TO'),
];
}
}
class SurveyResponseTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string { return 'b_hl_survey_responses'; }
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new IntegerField('SURVEY_ID'),
new IntegerField('USER_ID'), // NULL — анонимный
new StringField('SESSION_ID'),
new StringField('USER_IP'),
new TextField('ANSWERS_JSON'), // {question_id: answer}
new IntegerField('COMPLETION_SEC'), // Время прохождения
new DatetimeField('CREATED_AT'),
];
}
}
Які типи опитувальників варто впровадити?
Вибір залежить від бізнес-задачі. Порівняємо варіанти:
Таблиця типів опитувальників
| Тип | Суть | Питань | Тригер | Час реалізації |
|---|---|---|---|---|
| NPS | Готовність рекомендувати | 1–2 | Спливання по затримці / exit | 2–3 дні |
| CSAT | Оцінка конкретної точки | 1–3 | Після замовлення / звернення | 2–4 дні |
| Повноцінний | Дослідження аудиторії | 5–20 | Комбіновані | 8–14 днів |
NPS-опитування — найпростіший і найдешевший спосіб почати збирати зворотний зв'язок. Для нього достатньо одного компонента з віджетом.
NPS-опитувальник: простий випадок
Типова реалізація — одна сторінка, одна дія. Код компонента:
// /local/components/local/survey.nps/template.php
?>
<div class="nps-widget" id="nps-widget" style="display:none;">
<div class="nps-container">
<button class="nps-close" onclick="NPS.dismiss()">×</button>
<p class="nps-question">
Насколько вы готовы рекомендовать нас своим знакомым?
</p>
<div class="nps-scale">
<?php for ($i = 0; $i <= 10; $i++): ?>
<button class="nps-score" data-score="<?= $i ?>"><?= $i ?></button>
<?php endfor; ?>
</div>
<div class="nps-labels">
<span>Точно не буду рекомендовать</span>
<span>Обязательно порекомендую</span>
</div>
<div class="nps-comment" style="display:none;">
<textarea placeholder="Расскажите подробнее..." id="nps-comment-text"></textarea>
<button onclick="NPS.submit()">Отправить</button>
</div>
</div>
</div>
<script>
const NPS = {
surveyId: <?= (int)$arResult['SURVEY']['ID'] ?>,
selectedScore: null,
init() {
setTimeout(() => {
if (!this.wasShown()) {
document.getElementById('nps-widget').style.display = 'flex';
this.markShown();
}
}, <?= (int)$arResult['SURVEY']['SHOW_DELAY'] * 1000 ?>);
document.querySelectorAll('.nps-score').forEach(btn => {
btn.addEventListener('click', e => {
this.selectScore(parseInt(e.target.dataset.score));
});
});
},
selectScore(score) {
this.selectedScore = score;
document.querySelectorAll('.nps-score').forEach(b => b.classList.remove('selected'));
document.querySelector(`[data-score="${score}"]`).classList.add('selected');
document.querySelector('.nps-comment').style.display = 'block';
},
async submit() {
if (this.selectedScore === null) return;
await fetch('/local/ajax/survey_submit.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
survey_id: this.surveyId,
answers: {
nps_score: this.selectedScore,
comment: document.getElementById('nps-comment-text').value,
},
sessid: BX.bitrix_sessid(),
}),
});
document.getElementById('nps-widget').innerHTML =
'<p class="nps-thanks">Спасибо за ваш отзыв!</p>';
setTimeout(() => document.getElementById('nps-widget').style.display = 'none', 3000);
},
dismiss() {
document.getElementById('nps-widget').style.display = 'none';
this.markShown();
},
wasShown() {
return !!localStorage.getItem('nps_shown_' + this.surveyId);
},
markShown() {
localStorage.setItem('nps_shown_' + this.surveyId, Date.now());
},
};
NPS.init();
</script>
Тригери показу
Опитувальник має з'являтися в потрібний момент, а не одразу при завантаженні. Реалізуємо кілька тригерів:
Код тригерів
const SurveyTriggers = {
exitIntent(callback) {
document.addEventListener('mouseleave', e => {
if (e.clientY <= 0) callback();
}, {once: true});
},
scrollDepth(percent, callback) {
const listener = () => {
const scrolled = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
if (scrolled >= percent) {
window.removeEventListener('scroll', listener);
callback();
}
};
window.addEventListener('scroll', listener);
},
afterOrder(callback) {
if (window.location.href.includes('/order/success/')) {
setTimeout(callback, 2000);
}
},
};
Тригери налаштовуються індивідуально для кожного опитувальника та можуть комбінуватися. Для запобігання повторним відповідям використовуємо localStorage/cookie для анонімних користувачів, перевірку по user_id для авторизованих — це виключає дублі та підвищує якість даних на 30%.
Як аналізувати відповіді?
Для NPS автоматично розраховуємо категорію промоутерів, пасивів та детракторів:
class NpsAnalytics
{
public static function calculate(int $surveyId): array
{
$responses = SurveyResponseTable::getList([
'filter' => ['SURVEY_ID' => $surveyId],
'select' => ['ANSWERS_JSON'],
])->fetchAll();
$detractors = 0; // low scores
$passives = 0; // medium scores
$promoters = 0; // high scores
$total = 0;
foreach ($responses as $r) {
$answers = json_decode($r['ANSWERS_JSON'], true);
$score = (int)($answers['nps_score'] ?? -1);
if ($score < 0) continue;
$total++;
if ($score <= 6) $detractors++;
elseif ($score <= 8) $passives++;
else $promoters++;
}
if ($total === 0) return ['nps' => 0, 'total' => 0];
$nps = round(($promoters / $total - $detractors / $total) * 100);
return [
'nps' => $nps,
'total' => $total,
'promoters' => $promoters,
'passives' => $passives,
'detractors' => $detractors,
];
}
}
Поетапний процес розробки опитувальника
- Аналіз і узгодження — визначаємо цілі (NPS, CSAT, дослідження), вибираємо тригери та типи питань.
- Проектування HL-блоків — створюємо таблиці через API міграцій, налаштовуємо поля.
- Реалізація компонентів — пишемо шаблони віджетів, налаштовуємо AJAX-обробники.
- Інтеграція тригерів — підключаємо exit-intent, прокрутку, події після замовлення.
- Тестування та налагодження — перевіряємо на різних браузерах, усуваємо конфлікти.
- Запуск і аналітика — виводимо дашборд з NPS, CSAT, конверсіями.
Що входить в роботу
При замовленні розробки опитувальника під ключ ми надаємо:
- Налаштування HL-блоків та міграцій
- Написання компонентів (NPS, CSAT, кастомні)
- Реалізація тригерів та захист від повторів
- Інтеграція аналітики (NPS лічильник, зведені звіти)
- Документація по API та налаштуванню
- Доступи до репозиторію та тестового стенду
- 30 днів технічної підтримки після запуску
Чому HL-блоки краще інфоблоків?
Highload-блоки — це таблиці з довільним набором полів. Інфоблоки розраховані на контентне наповнення, а HL-блоки — на швидкі запити з мінімальним навантаженням. Для опитувальників критична швидкість запису даних без зайвих подій. Таблиця порівняння:
Порівняння HL-блоків та інфоблоків
| Критерій | Інфоблоки | HL-блоки |
|---|---|---|
| Продуктивність запису | Середня (події, оверхед) | Висока (прямий INSERT) — в 3 рази швидше |
| Гнучкість полів | Фіксовані типи | Довільні поля через ORM |
| Підтримка JSON-полів | Ні | Так, TextField |
| Підходить для опитувань | Тільки зберігання результатів | Зберігання конфігурації та відповідей |
Терміни та умови
Терміни залежать від складності: простий віджет — від 2 днів (від 8000 грн), повноцінний опитувальник — до 14 днів (від 25 000 грн). Вартість розраховується індивідуально. Окупність настає в перший місяць за рахунок автоматизації збору даних та своєчасного виявлення проблем — економія до 30 000 грн на місяць на ручному зборі. Спираємося на HL-блоки — штатний інструмент Бітрікса, що гарантує сумісність з оновленнями. Наш досвід 10+ років та понад 50 впроваджених проєктів підтверджує стабільність рішень. Середній NPS наших клієнтів після впровадження — 85. Отримайте консультацію під вашу задачу — оцінимо обсяг робіт без жорстких термінів. Замовте розробку опитувальника — і вже через місяць ви побачите чистий NPS вашого бізнесу.







