# Событие 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

Третий аргумент handlerdataContext (гео, 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.russianName
  • geo.city.isRegionCapital, geo.city.isCountryCapital, geo.city.population
  • geo.region.*, geo.country.* — аналогично
  • page.schemaOrg.brandName, page.schemaOrg.offer.price, page.schemaOrg.offer.availability
  • page.schemaOrg.aggregateRating.ratingValue, page.schemaOrg.aggregateRating.reviewCount
  • weather.temp, weather.tempFeelsLike, weather.humidity

# Устаревший способ

Для обратной совместимости: window.SalesNinja.onPersonalization({ ... }) — тот же контракт, что у ninja('onPersonalization', ...).

# См. также