# Событие onPersonalization
Три продукта в админке — один JS API
В разделе Сайт персонализации, A/B-тесты и действия по правилам — отдельные сущности (чем они отличаются).
В веб-бандле и JS API все они проходят через один метод onPersonalization: один и тот же personalizationId, те же варианты (personalizationOptionId), тот же handler.
- Персонализация — AI выбирает вариант под пользователя.
- A/B-тест — сравнение вариантов по статистике.
- Действие по правилам — показ по жёстким условиям без ML.
Первый аргумент handler — объект любой из этих сущностей (в коде часто называется personalization или abTest в примерах админки); второй — применённый вариант.
Когда на сайте применяется вариант (из персонализации, A/B-теста или rule-based действия), часто нужна своя JavaScript-логика: аналитика, доработка DOM, цепочка редиректов. Для этого подписываются на onPersonalization.
# Общая идея
Подписка — вызов ninja('onPersonalization', { ... }). Можно указать:
- только
personalizationId— сработает при любом варианте этой сущности; personalizationId+personalizationOptionId— только для конкретного варианта;- ни одного ID — на каждое применение любой сущности стека «Сайт» на странице.
personalizationId берётся из карточки сущности в админке (персонализация, A/B-тест или действие по правилам — поле ID одно и то же по смыслу для API).
Самая простая подписка (пример для персонализации; для A/B или rule-based подставьте свой ID):
// Пример: персонализация «Показывать лучший отзыв у товара»
ninja('onPersonalization', {
personalizationId: '6fbf1dd7-3771-45ce-a7a0-bd08187549ee',
handler: (entity, variant, dataContext) => {
switch (variant.id) {
case '10337247-6fa7-4ac3-92ed-bb2506d79ffa':
// вариант «Да»
break;
case 'fb8211d7-5aa3-40df-a3ed-54a67d72f850':
// вариант «Нет»
break;
}
},
})
Тот же вызов для A/B-теста или действия по правилам — только другой personalizationId из соответствующего раздела админки.
# Типы подписки
Существует три основных типа подписки:
# Указан один personalizationId
Подписка сработает, если сущность применима по условиям показа, с любым вариантом.
ninja('onPersonalization', {
personalizationId: '6fbf1dd7-3771-45ce-a7a0-bd08187549ee',
handler: (entity, variant) => {
switch (variant.id) {
// любой вариант этой сущности
}
},
})
# Указаны personalizationId и personalizationOptionId
Подписка сработает только для конкретного варианта.
ninja('onPersonalization', {
personalizationId: '6fbf1dd7-3771-45ce-a7a0-bd08187549ee',
personalizationOptionId: '10337247-6fa7-4ac3-92ed-bb2506d79ffa',
handler: (entity, variant) => {
// только выбранный вариант
},
})
# Не указан ни personalizationId, ни personalizationOptionId
Подписка на каждое применение на странице — персонализация, A/B или rule-based. Удобно для единой самописной аналитики.
ninja('onPersonalization', {
handler: (entity, variant) => {
// каждое применение варианта стека «Сайт»
},
})
# Таймаут
Если применение варианта критично по времени (например, промежуточная страница перед лендингом A/B), задайте timeout и onTimeoutExceeded — они работают для всех типов сущностей так же, как для персонализаций.
ninja('onPersonalization', {
personalizationId: '6fbf1dd7-3771-45ce-a7a0-bd08187549ee',
handler: (entity, variant) => { /* ... */ },
timeout: 2000,
onTimeoutExceeded: (entity, variant) => { /* ... */ },
})
# Несколько подписок с таймаутом
Если несколько подписок на варианты одной сущности и у каждой указан таймаут, при успехе любой из них onTimeoutExceeded у остальных не вызывается.
# Таймаут по умолчанию
Если есть onTimeoutExceeded, но нет timeout, используется 5 секунд.
# Метод подписки возвращает Promise
onPersonalization возвращает Promise (opens new window). Перед вызовом дождитесь window.SalesNinja.ready === true.
await ninja('onPersonalization', {
personalizationId: '6fbf1dd7-3771-45ce-a7a0-bd08187549ee',
handler: (entity, variant) => { /* ... */ },
})
# Параметры dataContext
Третий аргумент handler — dataContext (гео, Schema.org, погода). Доступен для любой сущности стека «Сайт».
ninja('onPersonalization', {
personalizationId: '6fbf1dd7-3771-45ce-a7a0-bd08187549ee',
personalizationOptionId: '10337247-6fa7-4ac3-92ed-bb2506d79ffa',
handler: (entity, variant, dataContext) => {
if (dataContext) {
const cityName = dataContext.geo.city.nativeName;
// ...
}
},
})
# Список полей dataContext
geo.city.nativeName,geo.city.englishName,geo.city.russianNamegeo.city.isRegionCapital,geo.city.isCountryCapital,geo.city.populationgeo.region.*,geo.country.*— аналогичноpage.schemaOrg.brandName,page.schemaOrg.offer.price,page.schemaOrg.offer.availabilitypage.schemaOrg.aggregateRating.ratingValue,page.schemaOrg.aggregateRating.reviewCountweather.temp,weather.tempFeelsLike,weather.humidity
# Устаревший способ
Для обратной совместимости: window.SalesNinja.onPersonalization({ ... }) — тот же контракт, что у ninja('onPersonalization', ...).
# См. также
- Ручной запуск вариантов —
applyPersonalization - REST: персонализации (runtime) и A/B (runtime) — тот же стек без веб-бандла
- JS-действия в варианте