Квиз для сайта: что это, когда поднимает конверсию и код формы
Квиз для сайта: что такое квиз-форма, когда она помогает лендингу, цены Marquiz и Тильды и готовый код квиза с отправкой ответов в api.php и Keitaro…

Квиз для сайта это форма заявки, разбитая на шаги. Сначала посетитель отвечает на несколько вопросов с готовыми вариантами, а на последнем шаге оставляет имя и телефон. В справке Тильды это сформулировано так: маркетинговый квиз «это пошаговая форма, которая поможет вовлечь клиента в выбор услуги или товара, уточнить его желания и собрать эти данные, чтобы упростить процесс продаж».
Ниже разбор: чем квиз отличается от обычной формы, когда он помогает лендингу, а когда мешает, где его собрать без программиста и готовый код квиза на 2026 год. Код работает с клавиатуры и на телефоне, без JavaScript превращается в обычную форму и отправляет ответы вместе с лидом в api.php и в Keitaro. Всё проверено в Chromium.
- Что такое квиз-форма и чем она отличается от обычной
- Когда квиз поднимает конверсию лендинга, а когда мешает
- Где сделать квиз: сервисы и свой код
- Квиз-форма: готовый код
- HTML: вставьте вместо старой формы
- CSS: файл quiz.css
- JavaScript: файл quiz.js
- Как отправить ответы в api.php и Keitaro
- Файл quiz-keitaro.php
- Что дописать в api.php
- Установка по шагам
- Что исправлено по сравнению с версией 2024 года
- Частые вопросы
- Что такое квиз на сайте простыми словами?
- Сколько вопросов делать в квизе?
- Телефон спрашивать в начале или в конце?
- Можно ли сделать квиз бесплатно?
- Как сделать квиз на Тильде?
- Работает ли квиз без JavaScript?
Что такое квиз-форма и чем она отличается от обычной
| Параметр | Обычная форма | Квиз-форма |
|---|---|---|
| Экран | все поля сразу | один вопрос на экран |
| Ответы | текстовые поля | варианты на выбор, текст только в контактах |
| Прогресс | не нужен | счётчик «Шаг 2 из 4» и полоса |
| Что получает оператор | имя и телефон | имя, телефон и ответы на вопросы |
В интерфейсах такой приём называют мастером (wizard). Nielsen Norman Group определяет мастер как пошаговый ввод данных в заданном порядке, где следующие шаги могут зависеть от предыдущих ответов. Для арбитражника у квиза есть ещё одна польза: ответы уходят оператору колл-центра и в трекер, и по ним видно, какие посетители дают апрув.

Когда квиз поднимает конверсию лендинга, а когда мешает
Универсальной цифры «квиз даёт плюс N%» нет: всё решает тест на вашем трафике. Зато понятно, от чего зависит результат. NN/g перечисляет плюсы мастеров: на каждом экране меньше полей, человек не пугается длинной формы, меньше ошибается и проходит только нужный ему путь. Минусы тоже названы: больше кликов, неудобно тем, кто знает, чего хочет, и тем, кто проходит процесс много раз.
Квиз скорее поможет, если:
- трафик холодный и человек ещё не решил, нужен ли ему товар: вопросы вовлекают его в выбор;
- у оффера есть варианты (размер, для кого, какая проблема), и оператору проще продать, зная ответы заранее;
- вы хотите понять, какие ответы дают апрув, и резать трафик по ним.
Квиз скорее помешает, если:
- посетитель пришёл готовым купить: каждый лишний шаг отделяет его от кнопки заказа;
- вопросы ничего не дают оператору и задаются ради «вовлечения»;
- на последнем шаге стоит таймер, который перезапускается. W3C в руководстве по многошаговым формам советует по возможности не ставить ограничение по времени на заполнение формы.
Наш опыт 2024 года: мы ставили квиз на нутра-лендинги вместо колёс фортуны и «дверей». Конверсия в заявку была чуть ниже, чем у обычной формы, а апрув выше: на последнем шаге квиз подчёркивал, что акционная цена действует только на одну упаковку. Это наблюдение по нашим офферам, а не правило. Проверяйте на своих: сделайте две копии лендинга и разделите трафик сплит-тестом лендингов в Keitaro. Сравнивайте CR, апрув и EPC: как их считать, разобрано в статье про метрики арбитража.
Где сделать квиз: сервисы и свой код
| Вариант | Цена | Плюсы | Минусы |
|---|---|---|---|
| Marquiz | «Бесплатный» 0 ₽ на 10 заявок в месяц, «Старт» 790 ₽ на 30 заявок, «Плюс» от 1 790 ₽ | конструктор, шаблоны, интеграции | тариф считается по заявкам, квиз работает на стороне сервиса |
| Тильда, блок QZ101 | сайт на Тильде, тариф Personal 500 ₽ в месяц при оплате за год или 750 ₽ помесячно | ветвление вопросов, виртуальный консультант, отправка в сервисы приёма данных | только для сайтов на Тильде |
| Свой код (ниже) | бесплатно | лежит в архиве лендинга, работает в Keitaro, ответы уходят в сеть и в sub_id | вопросы правите в HTML сами |
Цены сняты со страниц тарифов 1 октября 2026 года. Для арбитражного лендинга у конструктора два минуса: форма грузится со стороннего домена, а связку с subid клика и API партнёрской сети придётся собирать через интеграции сервиса. Свой код лежит в архиве лендинга и отправляет заявку тем же api.php, что и обычная форма.
Квиз-форма: готовый код
Каждый вопрос это <fieldset> с заголовком <legend>, а варианты это обычные радиокнопки и галочки внутри <label>. Поэтому клавиатура и скринридер работают без дополнительных настроек: стрелки выбирают вариант, пробел ставит галочку, скринридер читает вопрос вместе с вариантом. Если JavaScript не загрузился, форма показывает все вопросы сразу и отправляется как обычная.
Что умеет квиз:
- показывает по одному вопросу со счётчиком «Шаг 2 из 4», счётчик зачитывается скринридером;
- Enter переводит на следующий шаг, а не отправляет форму; кнопка «Назад» сохраняет ответы;
- клик мышью или пальцем по варианту сразу открывает следующий вопрос, стрелки на клавиатуре так не делают;
- не пускает дальше без ответа, в группе галочек требует хотя бы одну, в телефоне ждёт от 7 до 15 цифр;
- на телефоне варианты высотой 48 px, крупные кнопки и поля со шрифтом 16 px;
- собирает ответы в текст для оператора и блокирует кнопку отправки после первого клика, чтобы не плодить дубли лидов.
HTML: вставьте вместо старой формы
<form class="kq" action="api.php" method="post">
<h2 class="kq__title">Подберём уход за ногами за 3 вопроса</h2>
<div class="kq__top" hidden>
<p class="kq__count" aria-live="polite">Шаг 1 из 4</p>
<div class="kq__bar" aria-hidden="true"><span></span></div>
</div>
<fieldset class="kq__step">
<legend>Для кого подбираем?</legend>
<label class="kq__opt"><input type="radio" name="q1" value="self" required> Для себя</label>
<label class="kq__opt"><input type="radio" name="q1" value="parents"> Для родителей</label>
<label class="kq__opt"><input type="radio" name="q1" value="gift"> В подарок</label>
</fieldset>
<fieldset class="kq__step" data-min="1">
<legend>Что беспокоит к вечеру? <span class="kq__hint">Можно выбрать несколько</span></legend>
<label class="kq__opt"><input type="checkbox" name="q2[]" value="tired"> Усталость ног</label>
<label class="kq__opt"><input type="checkbox" name="q2[]" value="heavy"> Тяжесть в ногах</label>
<label class="kq__opt"><input type="checkbox" name="q2[]" value="dry"> Сухая кожа стоп</label>
<label class="kq__opt"><input type="checkbox" name="q2[]" value="care"> Ничего, нужен уход</label>
</fieldset>
<fieldset class="kq__step">
<legend>Когда удобнее принять звонок?</legend>
<label class="kq__opt"><input type="radio" name="q3" value="morning" required> Утром, до 12:00</label>
<label class="kq__opt"><input type="radio" name="q3" value="day"> Днём, 12:00-17:00</label>
<label class="kq__opt"><input type="radio" name="q3" value="evening"> Вечером, после 17:00</label>
</fieldset>
<fieldset class="kq__step">
<legend>Куда позвонить? <span class="kq__hint">Оператор расскажет о составе и условиях доставки</span></legend>
<label class="kq__field">Имя
<input type="text" name="name" autocomplete="name" required minlength="2" maxlength="60">
</label>
<label class="kq__field">Телефон
<input type="tel" name="phone" autocomplete="tel" inputmode="tel" required maxlength="20">
</label>
</fieldset>
<input type="hidden" name="subid" value="{subid}">
<input type="hidden" name="answers" value="">
<div class="kq__nav">
<button type="button" class="kq__back" hidden>Назад</button>
<button type="button" class="kq__next" hidden>Далее</button>
<button type="submit" class="kq__send">Жду звонка</button>
</div>
</form>В value вариантов пишите короткие латинские коды: они уйдут в Keitaro. Подписи могут быть на любом языке. Порядок шагов любой: если хотите, как в нашей версии 2024 года, спрашивать имя и телефон первыми, просто переставьте последний <fieldset> наверх.
CSS: файл quiz.css
.kq{max-width:560px;margin:0 auto;padding:20px 16px;background:#fff;color:#1f2328;border-radius:14px;box-shadow:0 2px 12px rgba(0,0,0,.08);font:17px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;box-sizing:border-box}
.kq *,.kq *::before,.kq *::after{box-sizing:border-box}
.kq [hidden]{display:none!important}
.kq__title{margin:0 0 12px;font-size:24px;line-height:1.25}
.kq__count{margin:0 0 6px;font-size:14px;color:#4b5563}
.kq__bar{height:8px;margin-bottom:16px;border-radius:4px;background:#e5e7eb;overflow:hidden}
.kq__bar span{display:block;width:0;height:100%;background:#166534;transition:width .3s}
.kq__step{min-width:0;margin:0 0 16px;padding:0;border:0}
.kq__step legend{margin-bottom:12px;padding:0;font-size:20px;font-weight:700}
.kq__hint{display:block;font-size:14px;font-weight:400;color:#4b5563}
.kq__opt{display:flex;align-items:center;gap:10px;min-height:48px;margin-bottom:8px;padding:10px 14px;border:1px solid #d1d5db;border-radius:10px;cursor:pointer;-webkit-tap-highlight-color:transparent}
.kq__opt:has(input:checked){border-color:#166534;background:#f0fdf4}
.kq__opt:has(input:focus-visible){outline:3px solid #1d4ed8;outline-offset:2px}
.kq__opt input{flex:none;width:20px;height:20px;margin:0;accent-color:#166534}
.kq__field{display:block;margin-bottom:12px;font-weight:600}
.kq__field input{display:block;width:100%;margin-top:6px;padding:12px;border:1px solid #9ca3af;border-radius:10px;font:inherit;font-size:16px;font-weight:400}
.kq__nav{display:flex;gap:10px}
.kq__nav button{min-height:48px;padding:12px 18px;border-radius:10px;font:inherit;font-weight:700;cursor:pointer}
.kq__back{border:1px solid #9ca3af;background:#fff;color:#1f2328}
.kq__next,.kq__send{flex:1;border:0;background:#166534;color:#fff}
.kq__send:disabled{opacity:.6;cursor:wait}
.kq button:focus-visible,.kq__field input:focus-visible{outline:3px solid #1d4ed8;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.kq__bar span{transition:none}}JavaScript: файл quiz.js
/* quiz.js: пошаговая квиз-форма. Без JavaScript форма показывает все вопросы сразу и отправляется как обычная */
(() => {
document.querySelectorAll('form.kq').forEach((form) => {
const steps = [...form.querySelectorAll('.kq__step')];
const count = form.querySelector('.kq__count');
const bar = form.querySelector('.kq__bar span');
const back = form.querySelector('.kq__back');
const next = form.querySelector('.kq__next');
const send = form.querySelector('.kq__send');
const answers = form.querySelector('input[name="answers"]');
const d = form.dataset;
let cur = 0;
let lastPointer = 0;
const fields = (step) => [...step.querySelectorAll('input, select, textarea')];
// Свои проверки поверх стандартных: минимум ответов в группе галочек и цифры в телефоне
function setChecks(step) {
const min = Number(step.dataset.min || 0);
if (min) {
const boxes = step.querySelectorAll('input[type="checkbox"]');
const checked = step.querySelectorAll('input[type="checkbox"]:checked').length;
boxes[0].setCustomValidity(checked >= min ? '' : (d.errorChoice || 'Выберите хотя бы один вариант'));
}
const phone = step.querySelector('input[type="tel"]');
if (phone) {
const digits = phone.value.replace(/\D/g, '').length;
const ok = phone.value === '' || (digits >= 7 && digits <= 15);
phone.setCustomValidity(ok ? '' : (d.errorPhone || 'Проверьте номер телефона'));
}
}
const stepOk = (step) => { setChecks(step); return fields(step).every((f) => f.checkValidity()); };
function report(step) {
setChecks(step);
const bad = fields(step).find((f) => !f.checkValidity());
if (bad) bad.reportValidity();
return !bad;
}
function show(i, focus) {
cur = i;
steps.forEach((s, k) => { s.hidden = k !== i; });
const last = i === steps.length - 1;
back.hidden = i === 0;
next.hidden = last;
send.hidden = !last;
count.textContent = (d.stepText || 'Шаг {n} из {total}').replace('{n}', i + 1).replace('{total}', steps.length);
bar.style.width = ((i + 1) / steps.length) * 100 + '%';
if (focus) {
const f = steps[i].querySelector('input:checked') || fields(steps[i])[0];
if (f) f.focus();
}
}
function summary() {
return steps.map((step) => {
const picked = [...step.querySelectorAll('input:checked')].map((i) => i.parentElement.textContent.trim());
if (!picked.length) return '';
const legend = step.querySelector('legend').cloneNode(true);
legend.querySelectorAll('.kq__hint').forEach((h) => h.remove());
return legend.textContent.trim() + ' ' + picked.join(', ');
}).filter(Boolean).join('; ').slice(0, 500);
}
form.noValidate = true; // проверяем сами по шагам, иначе браузер ругается на скрытые поля
form.querySelector('.kq__top').hidden = false;
show(0, false);
next.addEventListener('click', () => { if (report(steps[cur])) show(cur + 1, true); });
back.addEventListener('click', () => show(cur - 1, true));
// Enter на промежуточном шаге ведёт дальше, а не отправляет форму
form.addEventListener('keydown', (e) => {
if (e.key !== 'Enter' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA') return;
if (cur < steps.length - 1) { e.preventDefault(); next.click(); }
});
// Клик мышью или пальцем по варианту сразу открывает следующий шаг. Стрелки на клавиатуре так не делают
form.addEventListener('pointerdown', () => { lastPointer = Date.now(); });
form.addEventListener('change', (e) => {
setChecks(steps[cur]);
if (e.target.type === 'radio' && Date.now() - lastPointer < 1000 && cur < steps.length - 1) {
const at = cur;
setTimeout(() => { if (cur === at) next.click(); }, 250);
}
});
form.addEventListener('submit', (e) => {
const badStep = steps.findIndex((s) => !stepOk(s));
if (badStep !== -1) {
e.preventDefault();
show(badStep, false);
report(steps[badStep]);
return;
}
answers.value = summary();
send.disabled = true; // защита от двойного клика
});
// Кнопка «Назад» в браузере возвращает страницу из кеша: включаем кнопку отправки снова
window.addEventListener('pageshow', () => { send.disabled = false; });
});
})();Подключение: <link rel="stylesheet" href="quiz.css"> в <head> и <script src="quiz.js" defer></script> перед </body>. Для других языков задайте тексты атрибутами формы: data-step-text="Paso {n} de {total}", data-error-choice и data-error-phone. Остальной текст лендинга переводите вместе с вопросами квиза.
Как отправить ответы в api.php и Keitaro
Проверки в браузере помогают посетителю, но не защищают сервер от произвольного POST-запроса. В api.php отдельно проверяйте обязательные ответы, допустимые коды вариантов и формат контактов. Данные о здоровье из вопросов не передавайте рекламным системам как параметры событий.
Квиз отправляет в api.php поля name, phone, subid, коды ответов q1, q2[], q3 и текст answers. Сам api.php берите из статьи про вашу партнёрскую сеть, например про интеграцию Leadbit с Keitaro. К нему добавляются две вещи.
- Ответы оператору. Если API сети принимает комментарий (в наших разборах поле
commentесть у Leadbit, RocketProfit, Shakes.pro и AlterCPA), передайте в негоquiz_comment(). Оператор увидит: «Для кого подбираем? Для родителей; Что беспокоит к вечеру? Усталость ног, Тяжесть в ногах; Когда удобнее принять звонок? Днём, 12:00-17:00». - Ответы в трекер. Функция
quiz_to_keitaro()записывает коды ответов в параметры кликаsub_id_7,sub_id_8,sub_id_9. Для этого Keitaro принимает запрос?_update_tokens=1&sub_id=…: так описано в документации об обновлении параметров. Изменения видны только в отчётах, на ссылки они не влияют. После этого в отчёте Keitaro можно сгруппировать конверсии поsub_id_8и увидеть апрув по каждому ответу.
Файл quiz-keitaro.php
<?php
// quiz-keitaro.php: ответы квиза для api.php. Подключите в начале api.php:
// require __DIR__ . '/quiz-keitaro.php';
const KT_TRACKER = 'https://ВАШ_ТРЕКЕР'; // адрес Keitaro без слеша в конце
const QUIZ_TO_SUBID = ['q1' => 'sub_id_7', 'q2' => 'sub_id_8', 'q3' => 'sub_id_9']; // вопрос => параметр клика
// Ответы текстом для поля comment партнёрской сети, если её API принимает комментарий
function quiz_comment(): string
{
$text = trim(strip_tags((string)($_POST['answers'] ?? '')));
if ($text === '') { // форма ушла без JavaScript: собираем ответы из кодов
$parts = [];
foreach (array_keys(QUIZ_TO_SUBID) as $q) {
$v = $_POST[$q] ?? '';
$parts[] = $q . '=' . (is_array($v) ? implode(',', $v) : (string)$v);
}
$text = implode('; ', $parts);
}
return mb_substr($text, 0, 500);
}
// Записывает коды ответов в sub_id_7..9 клика: обновление параметров по документации Keitaro.
// Вызывайте в самом конце api.php, после header('Location: ...'), чтобы посетитель не ждал трекер.
function quiz_to_keitaro(): void
{
$subid = (string)($_POST['subid'] ?? '');
if (!preg_match('/^[A-Za-z0-9_-]{4,64}$/', $subid)) {
return; // subid пустой или макрос {subid} не подставился: обновлять нечего
}
$params = ['_update_tokens' => 1, 'sub_id' => $subid];
foreach (QUIZ_TO_SUBID as $q => $token) {
$v = $_POST[$q] ?? '';
$v = is_array($v) ? implode(',', $v) : (string)$v;
if (preg_match('/^[a-z0-9_,-]{1,100}$/i', $v)) {
$params[$token] = $v; // в трекер уходят только коды ответов, без текста
}
}
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request(); // отдаём редирект посетителю, запрос в трекер идёт уже без него
}
$ch = curl_init(KT_TRACKER . '/?' . http_build_query($params));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 2,
CURLOPT_TIMEOUT => 2,
]);
curl_exec($ch);
}Что дописать в api.php
// 1. В начале api.php
require __DIR__ . '/quiz-keitaro.php';
// 2. В массив заявки для сети, если её API принимает комментарий
'comment' => quiz_comment(),
// 3. В самом конце, после редиректа на страницу «Спасибо»
header('Location: ' . ($ok ? 'success.php' : 'error.php'));
quiz_to_keitaro();
exit;Почему запрос в трекер стоит в самом конце. У PHP в локальных лендингах Keitaro по требованиям есть 3 секунды, и почти всё это время может уйти на запрос в сеть. На серверах с PHP-FPM функция fastcgi_finish_request() сначала отдаёт посетителю редирект на страницу «Спасибо», а трекер обновляется уже без него. Номера sub_id выберите свободные: посмотрите, какие параметры уже заняты метками источника в настройках кампании.
Установка по шагам
Все файлы из статьи одним архивом: newform.zip (quiz.html, quiz.css, quiz.js и обработчик quiz-keitaro.php, версия от 1 октября 2026).
- Вставьте HTML квиза на место старой формы и замените вопросы и варианты под свой оффер.
- Подключите
quiz.cssиquiz.js. - Скрытое поле
subidоставьте со значением{subid}, если лендинг загружен в Keitaro: трекер подставит ID клика вindex.htmlилиindex.php. Если лендинг на своём хостинге, передавайте subid в адресе, как в статьях про интеграции с сетями. - Положите
quiz-keitaro.phpрядом сapi.php, впишите адрес трекера вKT_TRACKERи свободные параметры вQUIZ_TO_SUBID, допишите три строки вapi.php. - Пройдите квиз только с клавиатуры и с телефона, отправьте тестовую заявку. Проверьте комментарий в кабинете сети и значения
sub_id_7-sub_id_9у клика в логе кликов Keitaro.
Телефон на последнем шаге можно усилить маской с кодом страны: готовый вариант для Keitaro есть в статье про маску ввода телефона.
Что исправлено по сравнению с версией 2024 года
Мы прогнали старую форму из архива 2024 года в Chromium и нашли ошибки, которые теряли данные или ломали путь посетителя:
- Enter в поле имени сразу отправлял заявку целиком, минуя шаги. В поле телефона заранее стояло «+7», поэтому браузер считал его заполненным, и в сеть уходил лид с телефоном «+7».
- По той же причине на шаге телефона кнопка «Далее» была активна, пока номер не введён.
- Выбранные симптомы не попадали в заявку: это были кнопки без полей формы.
- При переходе на последний шаг скрипт падал с ошибкой «Cannot set properties of undefined».
- В HTML-файле стоял код
<?php echo $_GET['pxl']; ?>. В файле.htmlPHP не выполняется, и в заявку уходил сам этот текст. - Таймер «скидки» после нуля начинался заново с 5:00. Таймер и фразу об одобренной скидке 100% мы из примера убрали: условия акции у каждого оффера свои, пишите их на последнем шаге сами.
- Кнопки симптомов не сообщали скринридеру, выбраны ли они, а их значения были на испанском при русских подписях.
Если вы ищете другие способы помочь посетителю дойти до заявки без оператора, посмотрите наш ИИ-консультант для лендинга: он отвечает на вопросы по тексту страницы и ведёт к форме.
Частые вопросы
Что такое квиз на сайте простыми словами?
Это опрос из нескольких вопросов с вариантами ответов, в конце которого посетитель оставляет контакты. По сути та же форма заявки, только разбитая на шаги.
Сколько вопросов делать в квизе?
Столько, сколько реально пригодится оператору или для анализа трафика. Каждый шаг добавляет клик, поэтому вопросы «для вовлечения» лучше убрать. В нашем примере три вопроса и шаг с контактами.
Телефон спрашивать в начале или в конце?
В типовом квизе контакты идут последним шагом. В нашей версии 2024 года имя и телефон шли первыми. Код поддерживает любой порядок, а что лучше для вашего оффера, покажет сплит-тест.
Можно ли сделать квиз бесплатно?
Да. В Marquiz есть бесплатный тариф на 10 заявок в месяц, а код из этой статьи бесплатный без ограничений.
Как сделать квиз на Тильде?
В библиотеке блоков откройте раздел «Форма» и выберите блок QZ101 или одну из его вариаций QZ101A-QZ101F. Шаги, ветвление и отправка данных настраиваются в контенте блока.
Работает ли квиз без JavaScript?
Да. Без скрипта форма показывает все вопросы на одной странице и отправляется как обычная, а quiz_comment() собирает ответы из кодов вариантов.



