Разработка модуля A/B тестирования 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Разработка модуля A/B тестирования 1С-Битрикс
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1173
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    745
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    976

Разработка модуля A/B тестирования 1С-Битрикс

A/B тест — это не просто «показать половине пользователей красную кнопку». Это корректное разделение аудитории, устойчивое назначение варианта (один пользователь всегда видит один вариант), отслеживание целевых событий, статистическая значимость результатов. Без модуля разработчики обычно делают это через if (rand(0,1)) — и получают мерцающие варианты, бесполезную статистику и невозможность масштабировать эксперименты. Правильный модуль решает все эти проблемы.

Модель данных

Модуль vendor.abtest:

  • b_vendor_ab_experiment — эксперименты: id, name, code, status (draft/running/paused/finished), traffic_percent (10-100), started_at, finished_at, goal_event, description
  • b_vendor_ab_variant — варианты: id, experiment_id, name, weight (для неравномерного разделения), is_control
  • b_vendor_ab_assignment — назначения: id, experiment_id, variant_id, user_id (или null), session_id, created_at
  • b_vendor_ab_event — целевые события: id, experiment_id, variant_id, assignment_id, event_type, created_at
  • b_vendor_ab_stat — агрегированная статистика (суточные срезы): experiment_id, variant_id, date, participants, conversions, revenue

Устойчивое назначение варианта

Пользователь должен всегда видеть один и тот же вариант. Назначение выполняется один раз и сохраняется:

class AssignmentService
{
    public function getVariant(string $experimentCode): ?Variant
    {
        $experiment = ExperimentTable::getByCode($experimentCode);
        if (!$experiment || $experiment['STATUS'] !== 'running') return null;

        $sessionId = $this->getSessionId();
        $userId    = $GLOBALS['USER']->GetID() ?: null;

        // Ищем существующее назначение
        $existing = AssignmentTable::getList([
            'filter' => [
                'EXPERIMENT_ID' => $experiment['ID'],
                'LOGIC'         => 'OR',
                'USER_ID'       => $userId,
                'SESSION_ID'    => $sessionId,
            ],
        ])->fetch();

        if ($existing) {
            return VariantTable::getById($existing['VARIANT_ID'])->fetch();
        }

        // Проверяем попадание в процент трафика (детерминированно по session_id)
        $hash = crc32($sessionId . $experimentCode) % 100;
        if ($hash >= $experiment['TRAFFIC_PERCENT']) return null; // пользователь вне теста

        // Выбираем вариант по весам
        $variant = $this->selectVariant($experiment['ID']);

        AssignmentTable::add([
            'EXPERIMENT_ID' => $experiment['ID'],
            'VARIANT_ID'    => $variant['ID'],
            'USER_ID'       => $userId,
            'SESSION_ID'    => $sessionId,
        ]);

        return $variant;
    }
}

Детерминированный хеш по session_id + experiment_code гарантирует стабильное попадание в процент трафика без сохранения лишних данных.

Применение в шаблонах

В шаблоне компонента или лейауте:

$abTest  = \Vendor\AbTest\AbTestService::getInstance();
$variant = $abTest->getVariant('checkout_button_color');

$buttonClass = match ($variant?->getName()) {
    'green'  => 'btn-success',
    'orange' => 'btn-warning',
    default  => 'btn-primary', // контрольный вариант или вне теста
};

В JavaScript:

// Данные варианта передаются через data-атрибут или JS-переменную
const variant = window.ABTEST_VARIANTS?.checkout_button_color;
if (variant === 'new_form') {
    document.querySelector('.checkout-form').classList.add('new-form');
}

Трекинг целевых событий

Отслеживаем конверсию — покупку, регистрацию, клик на CTA:

// При оплате заказа
AddEventHandler('sale', 'OnSaleOrderPaid', function(\Bitrix\Main\Event $event) {
    $orderId = $event->getParameter('id');
    $order   = \Bitrix\Sale\Order::load($orderId);

    \Vendor\AbTest\EventTracker::track('purchase', [
        'user_id'  => $order->getUserId(),
        'revenue'  => $order->getPrice(),
        'order_id' => $orderId,
    ]);
});

EventTracker::track() ищет активные назначения для данного пользователя и записывает событие в b_vendor_ab_event.

Статистическая значимость

В административном интерфейсе для каждого эксперимента рассчитывается:

  • Конверсия по вариантам (conversion rate = events / participants)
  • p-value по критерию хи-квадрат (χ²) — порог значимости 95%
  • Uplift — относительное улучшение относительно контрольного варианта
  • Sample ratio mismatch — проверка, не нарушилось ли соотношение вариантов
// χ² тест для двух вариантов
function chiSquaredTest(int $a_visitors, int $a_conversions, int $b_visitors, int $b_conversions): float
{
    $a_rate = $a_conversions / $a_visitors;
    $b_rate = $b_conversions / $b_visitors;
    $pooled = ($a_conversions + $b_conversions) / ($a_visitors + $b_visitors);

    $expected_a = $pooled * $a_visitors;
    $expected_b = $pooled * $b_visitors;

    return (($a_conversions - $expected_a) ** 2 / $expected_a) +
           (($b_conversions - $expected_b) ** 2 / $expected_b);
}

p-value < 0.05 → результат статистически значим.

Сроки разработки

Этап Срок
ORM-таблицы, детерминированное назначение 2 дня
Трекинг событий, интеграция с продажами 2 дня
Статистика, χ² тест 2 дня
JavaScript SDK для фронтенда 1 день
Административный интерфейс 2 дня
Тестирование 1 день

Итого: 10 рабочих дней. Мультивариантное тестирование (3+ варианта) и серверный feature-flag сервис — дополнительная оценка.