A/B-сплит лендингов через JS-редирект
Назначение
Скрипт делит трафик с одного лендинга между несколькими вариантами (A/B/C…). Все GET-параметры (UTM и прочие) и #hash сохраняются. Выпавший вариант закрепляется за посетителем.
Куда ставить
- Только на исходную страницу (вариант A).
- В
<head>страницы (настройки страницы → код в head). Если вставить скрипт в HTML-блок, перед редиректом будет виден контент. - На страницы других вариантов (B, C…) скрипт не ставится.
Настройки
| Переменная | Назначение |
|---|---|
SOURCE_PATH |
Путь страницы, на которой запускается сплит (без домена). На других страницах скрипт не срабатывает, это защищает от цикла. |
STORAGE_KEY |
Имя ключа в localStorage, где хранится выпавший вариант. Уникален для каждого теста. Смена ключа перераспределяет всех заново. |
VARIANTS |
Список вариантов: name, url, weight. Вес задаёт долю трафика (2,1,1 = 50/25/25). |
Как работает
- Если путь ≠
SOURCE_PATH, скрипт останавливается. - Страница скрывается, чтобы не было мелькания. Через 3 сек срабатывает страховочный показ.
- Из
localStorageберётся сохранённый вариант. Если его нет, вариант выбирается случайно с учётом весов и сохраняется. - Если выпал вариант A (текущая страница), страница показывается без редиректа.
- Иначе происходит редирект (
location.replace) на URL варианта со всеми параметрами и hash.
Где хранится вариант
- В
localStorageбраузера посетителя, на сервере ничего нет. - Выбор привязан к браузеру, устройству и домену. С другого устройства, в инкогнито или после очистки данных посетитель распределяется заново.
- Хранится бессрочно.
- Проверить или сбросить: DevTools → Application → Local Storage → домен → ключ
STORAGE_KEY. Для своих тестов удобнее режим инкогнито.
Ограничения
- Целевые URL должны иметь путь, отличный от
SOURCE_PATH, иначе будет цикл. - Метка группы в URL не передаётся. Вариант определяется по адресу лендинга.
Скрипт (пример: intensiv)
<script>
(function () {
// ===== НАСТРОЙКИ =====
var SOURCE_PATH = '/intensiv-a';
var STORAGE_KEY = 'ab_intensiv_2026_10';
var VARIANTS = [
{ name: 'a', url: 'https://edu.baniilatreaba.ro/intensiv-a', weight: 1 },
{ name: 'b', url: 'https://edu.baniilatreaba.ro/intensiv-b', weight: 1 },
{ name: 'c', url: 'https://edu.baniilatreaba.ro/intensiv-c', weight: 1 }
];
// =====================
var current = new URL(window.location.href);
if (current.pathname !== SOURCE_PATH) return;
// Сразу скрываем страницу
var html = document.documentElement;
html.style.visibility = 'hidden';
function show() { html.style.visibility = ''; }
// Страховка: показать через 3 сек
var failsafe = setTimeout(show, 3000);
var saved = null;
try { saved = localStorage.getItem(STORAGE_KEY); } catch (e) {}
var variant = VARIANTS.filter(function (v) { return v.name === saved; })[0];
if (!variant) {
var total = VARIANTS.reduce(function (s, v) { return s + (v.weight || 1); }, 0);
var r = Math.random() * total;
for (var i = 0; i < VARIANTS.length; i++) {
r -= (VARIANTS[i].weight || 1);
if (r < 0) { variant = VARIANTS[i]; break; }
}
variant = variant || VARIANTS[0];
try { localStorage.setItem(STORAGE_KEY, variant.name); } catch (e) {}
}
var target = new URL(variant.url, current.origin);
// Вариант = текущая страница → показываем и остаёмся
if (target.origin === current.origin && target.pathname === current.pathname) {
clearTimeout(failsafe);
show();
return;
}
// Переносим все параметры и hash
current.searchParams.forEach(function (value, key) {
target.searchParams.append(key, value);
});
target.hash = current.hash;
window.location.replace(target.toString());
})();
</script>
No comments to display
No comments to display