# Получение персонализаций (runtime)

Метод применяется без веб-бандла: мобильное приложение, серверный рендер, бэкенд.

Три продукта в админке — общий runtime-контур

В админке персонализации, A/B-тесты и действия по правилам — разные разделы (обзор).

На backend и в ответе personalizations/apply они обрабатываются единым контуром применения вариантов (те же поля personalizationId / optionId, модификации, subscription params). Отдельный эндпоинт ab-tests/apply — для выборки только A/B без смешивания с персонализациями в одном ответе.

На сайте с бандлом всё это также идёт через onPersonalization.

Sales Ninja по контексту пользователя возвращает, какие варианты (персонализаций, а при общем apply — и других сущностей стека «Сайт») следует применить.

# Описание метода

POST https://api.sales-ninja.me/public/{source}/v1.0/personalizations/apply
Headers:
  X-SN-TOKEN: <ваш токен проекта>
  Content-Type: application/json

{source} — идентификатор источника вызова (mobile, server, и т.п.). Уточняется в поддержке.

# Тело запроса

{
  "context": {
    "pageTitle": "<название текущей страницы/экрана>",
    "userScreenWidth": 1280,
    "userScreenHeight": 720,
    "customUserScopeParams": {},
    "customPageScopeParams": {},
    "clientDevice": "<Desktop|Tablet|Smartphone|Other>",
    "deviceModel": "<модель устройства, опционально>",
    "deviceBrand": "<производитель устройства, опционально>",
    "os": "<Android|Windows|Linux|MacOs|IOs|Other>",
    "osVersion": "<версия ОС, опционально>",
    "userIp": "<IP клиента, опционально>",
    "utmMedium": "<utm_medium, опционально>",
    "utmSource": "<utm_source, опционально>",
    "utmCampaign": "<utm_campaign, опционально>",
    "utmTerm": "<utm_term, опционально>",
    "utmContent": "<utm_content, опционально>",
    "sessionNumber": 4,
    "sessionId": "<id сессии>",
    "pagesOpenedSinceFirstEntry": 2,
    "pagesOpenedInThisSession": 1,
    "firstEntryOnUtc": "2026-04-10T19:27:47Z",
    "sessionStartOnUtc": "2026-04-15T18:15:50Z",
    "lastReachedGoals": []
  },
  "customerId": "<id клиента в Sales Ninja>",
  "appliedPersonalizationItems": []
}

projectId в теле передавать не нужно — он выводится из токена; любое значение в этом поле игнорируется.

# Пример

{
  "context": {
    "pageTitle": "Интернет-магазин — Главная",
    "userScreenWidth": 1280,
    "userScreenHeight": 720,
    "customUserScopeParams": {
      "revenue": "12350",
      "netProfit": "900"
    },
    "customPageScopeParams": {},
    "clientDevice": "Desktop",
    "deviceModel": "MacBook Air M1",
    "deviceBrand": "Apple",
    "os": "MacOs",
    "osVersion": "14.0",
    "userIp": "192.168.0.1",
    "utmMedium": "display",
    "utmSource": "billboard",
    "utmCampaign": "yellow_dress",
    "sessionNumber": 4,
    "sessionId": "8bf06a1d-0321-4be2-89b7-314181511c3d",
    "pagesOpenedSinceFirstEntry": 2,
    "pagesOpenedInThisSession": 1,
    "firstEntryOnUtc": "2026-04-10T19:27:47Z",
    "sessionStartOnUtc": "2026-04-15T18:15:50Z",
    "lastReachedGoals": []
  },
  "customerId": "ab859455-b459-419b-bba0-d73e911a9dc2",
  "appliedPersonalizationItems": [
    {
      "personalizationId": "50e62336-9b35-4ab6-b77a-a26b99c69883",
      "personalizationOptionId": "47b6fd00-29be-4d8c-adc0-0d9fa525745f",
      "isControl": false,
      "option": { "id": "09c5fd24-adce-46af-8338-c84fbb2af59c", "title": "Как сейчас" },
      "title": "Размер шрифтов",
      "version": 18,
      "validUntilUtc": "2026-04-30T19:27:48Z"
    }
  ]
}

# Поля контекста

# pageTitle

Название страницы/экрана, для которой запрашиваются персонализации.

# userScreenWidth / userScreenHeight

Размеры экрана пользователя в пикселях.

# customUserScopeParams / customPageScopeParams

Пользовательские параметры клиента и страницы в виде ключ-значение. Значения обязательно строками. Используются и для таргетинга персонализаций, и для обогащения статистики (revenue, netProfit и т.п.). Подробнее: user params, page params.

# clientDevice

Тип устройства. Допустимо: Desktop, Tablet, Smartphone, Other.

# deviceModel, deviceBrand

Модель и марка устройства, если их можно определить (для мобильных приложений — обычно да).

# os, osVersion

ОС и её версия. ОС: Android, Windows, Linux, MacOs, IOs, Other.

# userIp

IP клиента. Желательно передавать — нужен для антибота и географии.

# utmMedium, utmSource, utmCampaign, utmTerm, utmContent

Стандартные UTM-метки рекламной кампании, по которой пришёл пользователь.

# sessionNumber

Порядковый номер сессии этого пользователя.

# sessionId

Идентификатор текущей сессии.

# pagesOpenedSinceFirstEntry / pagesOpenedInThisSession

Сколько страниц/экранов пользователь открыл с момента первого визита / в этой сессии.

# firstEntryOnUtc / sessionStartOnUtc

Время первого входа пользователя и время начала текущей сессии в UTC.

# lastReachedGoals

Список последних достигнутых целей. Опционально — используется для обогащения сигналов таргетинга.

# customerId

Идентификатор клиента в Sales Ninja. Если у вас уже есть веб-бандл — берите его через await ninja('getCustomerIdAsync'). Если интеграция чисто серверная — сохраняйте customerId, который мы вернули в первом ответе, и используйте дальше.

# appliedPersonalizationItems

Список персонализаций, которые уже применены на этом экране в этой сессии. Передавайте сюда то, что вы получили в предыдущем вызове и реально показали пользователю — это даёт системе понимание непрерывности эксперимента и помогает не «перетыкать» решение в рамках одной сессии.

Поля одного элемента:

  • personalizationId — id персонализации.
  • personalizationOptionId — id применённого варианта.
  • isControl — был ли это контрольный вариант.
  • option.id, option.title — id и название варианта.
  • title — название самой персонализации.
  • version — версия персонализации, под которой решение было принято.
  • validUntilUtc — до какого UTC-времени применённое решение валидно.

# Ответ

{
  "personalizations": [
    {
      "personalizationId": "50e62336-9b35-4ab6-b77a-a26b99c69883",
      "title": "Размер шрифтов",
      "version": 19,
      "validUntilUtc": "2026-04-30T19:27:48Z",
      "isControl": false,
      "option": {
        "id": "47b6fd00-29be-4d8c-adc0-0d9fa525745f",
        "title": "Крупный шрифт"
      }
    }
  ],
  "customerId": "ab859455-b459-419b-bba0-d73e911a9dc2"
}

В personalizations — список того, что система рекомендует применить прямо сейчас на этом экране. Каждый элемент — это конкретный вариант (option) персонализации.

Если в запросе не был передан customerId, в ответе вернётся выданный системой свежий customerId — сохраните его и используйте в следующих запросах.

# Что делать с ответом

  • Применить указанные варианты на текущем экране (показать конкретный текст, поменять баннер, и т.п.).
  • На следующем экране передать эти же элементы в appliedPersonalizationItems, чтобы Sales Ninja понимал, что эксперимент идёт.
  • При достижении бизнес-цели вызвать POST /goals/reach с customerId из ответа — система привяжет конверсию к экспериментам, которые на пользователя действовали.

# Пример (Python)

import os, requests

SN_TOKEN = os.environ["SN_TOKEN"]
SOURCE = "mobile"

def fetch_personalizations(customer_id: str, screen: str, ctx: dict) -> dict:
    r = requests.post(
        f"https://api.sales-ninja.me/public/{SOURCE}/v1.0/personalizations/apply",
        headers={"X-SN-TOKEN": SN_TOKEN},
        json={
            "context": {
                "pageTitle": screen,
                **ctx,
            },
            "customerId": customer_id,
            "appliedPersonalizationItems": [],
        },
        timeout=15,
    )
    r.raise_for_status()
    return r.json()