# A/B-тесты
Модуль `experiments` распределяет посетителей между вариантами, применяет
вариант к публичной странице и считает показы и конверсии. Назначение стабильно:
посетитель получает один вариант эксперимента на всём сроке cookie.
## Цели эксперимента
| Цель | Ключ цели | Поведение |
| --- | --- | --- |
| API или тег | Не требуется | Вариант получает собственный компонент или тег `[mod_experiment:code]`. |
| Обычный блок | ID блока | Модуль автоматически оборачивает результат блока. |
| Системный блок | ID системного блока | Модуль автоматически оборачивает результат системного блока. |
| CSS-селектор | Например, `#buy-button` | Вариант применяется к найденным DOM-элементам. |
| Цена | CSS-селектор цены | Меняется только отображаемый текст цены. |
Режим **Цена** не меняет цену товара, корзины, заказа или платежа. Для теста
расчётной цены нужен отдельный проектный обработчик
`experiments.assignment.resolved` и серверная проверка на всех этапах заказа.
## Варианты
Эксперимент содержит минимум два варианта. Вес задаёт относительную долю, а
охват - процент посетителей, участвующих в тесте. Payload варианта поддерживает:
- `control` - оставить исходное содержимое;
- `replace` - заменить содержимое цели;
- `before` и `after` - вставить HTML рядом с целью;
- замену текста, добавление CSS-класса и ссылки;
- отображаемое значение цены.
Эксперимент можно оставить черновиком, запустить, приостановить или завершить.
Период начала и окончания необязателен.
## Вставка в шаблон
```text
[mod_experiment:promo_button]
```
На месте тега создаётся стабильный слот. Вариант загружается после получения
страницы, поэтому общий full-page cache не смешивает варианты разных
посетителей.
Для автоматической фиксации конверсии добавьте атрибут кнопке или ссылке:
```html
```
Произвольное событие задаётся вторым атрибутом:
```html
Оформить
```
Из JavaScript событие можно отправить вручную:
```javascript
window.AVEExperiments.convert('promo_button', 'form_sent');
```
## Публичный API
```text
GET /api/v1/experiments/{code}
GET /api/v1/experiments/assignments?codes=promo_button,hero_title
POST /api/v1/experiments/event
```
Последний endpoint принимает `code` и `event`. ID варианта от клиента не
принимается: сервер повторно вычисляет назначение и записывает событие только в
этот вариант. Для одного посетителя уникальность события считается раз в день,
при этом общее число событий также сохраняется.
## Hooks
### `experiments.assignment.resolved`
Вызывается после серверного выбора варианта. В контексте доступны:
- `experiment` - полная запись эксперимента;
- `variant` - выбранный вариант;
- `visitor_hash` - обезличенный хеш посетителя.
Результатом события является массив назначения. Обработчик может вернуть
изменённый массив, например для проектной интеграции с сервисным слоем.
### `experiments.event.recorded`
Вызывается после записи события. Контекст содержит `experiment`, `variant`,
`event_code` и флаг `unique`.
## Кеш и приватность
В HTML кешируется только одинаковый для всех слот и конфигурация активных
целей. Назначение запрашивается клиентом через API. Случайный seed хранится год
в cookie `ave_experiment_seed` с `HttpOnly`, `SameSite=Lax` и `Secure` на HTTPS.
IP и исходный seed в статистике не сохраняются.
## Права и удаление
- `view_experiments` - просмотр экспериментов и результатов;
- `manage_experiments` - создание, запуск, сброс статистики и удаление.
Деинсталляция удаляет эксперименты, варианты, статистику, дедупликацию
посетителей и настройки модуля.