# 🛍 Персонализация листинга товаров (PLP) в Gravity Field

Модуль PLP (Product Listing Personalization) позволяет персонализировать выдачу товаров на странице категории в реальном времени — на основе поведения пользователя, рекомендательных алгоритмов и мерчандайзинговых правил.


# Что умеет модуль PLP?

# 🤖 Персонализированная сортировка товаров

Используются алгоритмы, учитывающие историю поведения и интересы пользователя:

Алгоритм Описание
Popularity Учитывает просмотры, добавления в корзину, покупки. Оценивает и сортирует товары по активности.
User affinity Строит профиль интересов пользователя и подбирает товары по релевантным атрибутам (категория, бренд и др.).
Deep learning (скоро) Рекомендует следующее вероятное действие на основе поведения похожих пользователей.

# 🔀 Комбинирование алгоритмов (Per Slot)

Можно использовать разные алгоритмы для разных мест в выдаче:

  • 🔁 Недавно просмотренные — вернуть интерес к товарам
  • 🎯 Affinity — показать товары, максимально соответствующие интересам

# 🧠 Управление выдачей (мерчандайзинг)

  • Include / Exclude — исключить или включить товары по заданным правилам.
  • Pin — закрепить конкретные товары на определённых позициях.
  • Boosting (скоро) — мягко поднять товары с нужными атрибутами (например, с высокой маржой).

# ⚙️ Как работает PLP

PLP использует API-кампании и требует серверной интеграции. Подробнее:


# 🪜 Этапы настройки персонализации листинга

# 1️⃣ Отправка SSAPI Page

При переходе пользователя на страницу категории:

  • Отправьте Page-запрос, чтобы зафиксировать просмотр.
  • Это можно сделать через отдельный SSAPI Page или в составе запроса SSAPI Choose.

📘 Подробнее: Контекст страницы (Page Context)


# 2️⃣ Создание PLP-стратегии

  1. Перейдите в настройки стратегий.
  2. Выберите PLP стратегию.
  3. Настройте:
    • Рекомендательный алгоритм (например, Affinity).
    • Правила фильтрации, пина и бустинга.


# 3️⃣ Создание API-кампании

  1. Создайте новую API-кампанию с типом Recommendations.
  2. Внутри кампании:
    • Добавьте вариацию.
    • В переменной выберите созданную PLP стратегию.
    • Можно создать несколько experience для разных сегментов (например, Popularity для новых пользователей, Affinity — для лояльных).


# 4️⃣ Вызов SSAPI Choose на категории

На странице категории отправьте запрос Choose. Он вернёт отсортированные товары, которые нужно отобразить на странице.

📘 Подробнее: Choose API

# 🔧 Важно передавать:

Поле Назначение
context.page.page Номер страницы
selector.args.recs_campaign.realtimeRules Пользовательские фильтры (например, выбранный бренд, цвет)

# 📤 Пример запроса

{
	"user": {
		"slid": "63a01b64f0f50b4424075002"
	},
	"session": {
		"sl": "D5C4EF3F-E2F6-4D1D-8ADF-B6FBA2FE8B40"
	},
	"context": {
        "page": {
            "type": "CATEGORY",
            "data": [
                "Диваны"
            ],
            "location": "test.com",
            "page": 1 // Номер страницы
        },
        "device": {
            "userAgent": "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; EML-AL00 Build/HUAWEIEML-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 baidu.sogo.uc.UCBrowser/11.9.4.974 UWS/2.13.1.48 Mobile Safari/537.36 AliApp(DingTalk/4.5.11) com.alibaba.android.rimet/10487439 Channel/227200 language/zh-CN"
        }
    },
    "selector": {
        "names": [ // Название селектора кампании
            "plp_campaign"
        ],
        "args": {
            "maxProducts": 10, // Количество товаров на странице
            "recs campaign": {
                "realtimeRules": [ // Дополнительные фильтры чтобы ограничить выдачу товаров пользовательскими фильтрами, например если пользователь отфильтровал страницу по определенному бренду
                    {
                        "id": 1, // ID фильтра
                        "type": "include", // Include or Exclude
                        "slots": [], // Слоты к которым применить фильтры
                        "query": {
                            "conditions": [ // Условия фильтрации
                                {
                                    "field": "categories", // Поле по которому будет работать фильтр
                                    "arguments": [
                                        {
                                            "action": "equal", // Условие фильтрации,not_equal, more, more_or_equal, less, less_or_equal, contains
                                            "value": [
                                                "Диваны"
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                ]
            }
        }
    },
    "options": {
        "returnAnalyticsMetadata": false
    }
}

# 📥 Пример ответа

{
    "choices": [
        {
            "id": 1,
            "name": "plp_campaign",
            "type": "RECS_DECISION",
            "variations": [
                {
                    "id": 1,
                    "name": "Variation_Name",
                    "payload": {
                        "type": "RECS",
                        "data": {
                            "custom": {
                               // Custom Code, описанный в вариации
                            },
                            "slots": [
                                {
                                    "sku": "12345",
                                    "productData": {},
                                    "slotId": "63gf:63bd:63bc4d2:63bdba:63bc91:63a17:0:104445:0:3:0"
                                }
														],
														"count_pages": 61 // Общее количество страниц с запрашиваемым размером

                        }
                    }
                }
            ],
            "groups": [],
            "decisionId": "63bca:63bd:63bc48d2:63bdba"
        }
    ],
		"session": {
        "sl": "C7-EA-48-83-5706"
    },
		"user": {
        "slid": "63c7fgn6"
    }
}

💡 realtimeRules используется для применения пользовательских фильтров (например, по бренду).
Поля для фильтрации должны быть доступны в фиде товаров.


# 5️⃣ Отправка Engagement событий

Для отслеживания эффективности и сбора аналитики — отправляйте события взаимодействия: 📘 Engagement API
📘 JS SDK

Событие Когда отправляется
SLOT_CLICK Пользователь кликнул по товару
WRIMP Виджет попал во viewport на 50% и более, не менее чем на 1 сек

# Часто задаваемые вопросы (FAQ)

# 🔸 Нужно ли подключать API-интеграцию?

Да. Модуль PLP работает только через серверную API-интеграцию.
Также потребуется настроить API-кампании и реализовать вызовы choose, engagement, page.


# 🔸 Как передать количество товаров на странице?

В параметрах запроса choose укажите:

"selector": {
  "args": {
    "maxProducts": 12
  }
}

# 🔸 Как отправить engagement с фронта?

Используйте JS SDK Gravity Field:

# 📌 1. Трекинг клика по товару (SLOT_CLICK)

productElement.addEventListener('click', (event) => {
  const slotId = event.currentTarget.dataset.slotId;
  if (window.SL && window.SL.ServerUtils) {
    window.SL.ServerUtils.reportEngagement(slotId, 'SLOT_CLICK');
  }
});

🏷️ Обязательно: у элемента должен быть data-slot-id с slotId из ответа API


# 📌 2. Трекинг попадания в экран (WRIMP)

const targetElements = document.querySelectorAll('.product-item');
const decisionId = '...'; // decisionId из ответа choose

// опционально: подписка на событие
document.addEventListener('productInViewport', e => {
  console.log('product in viewport:', e.detail.elements);
});

if (window.SL && window.SL.Utils) {
  SL.Utils.detectElementsRealImpresssion(targetElements, 'productInViewport')
    .then(elements => {
      window.SL.ServerUtils.reportEngagement(decisionId, 'WRIMP');
    });
}

⚠️ Все элементы должны иметь одинаковые размеры для корректного расчёта попадания в viewport.

📘 Документация: JS SDK — трекинг взаимодействия с API-кампанией


# 🔸 Как применить пользовательские фильтры?

Передайте параметр realtimeRules в аргументах selector.args:

"selector": {
  "args": {
    "recs campaign": {
      "realtimeRules": [
        {
          "type": "include",
          "query": {
            "conditions": [
              {
                "field": "brand",
                "arguments": [
                  {
                    "action": "equal",
                    "value": ["Nike"]
                  }
                ]
              }
            ]
          }
        }
      ]
    }
  }
}

⚠️ Убедитесь, что нужные поля доступны в товарном фиде.


# 🔸 Как реализовать пагинацию?

Укажите номер страницы в context.page.page, а в ответе вы получите поле count_pages:

"context": {
  "page": {
    "page": 2
  }
}

# 🔸 Как показать разные стратегии для разных аудиторий?

Внутри кампании создайте несколько сценариев (experience) и настройте для каждого таргетинг и свою PLP-стратегию.

Пример:

  • Popularity → новые пользователи
  • Affinity → авторизованные или постоянные

# 📚 Полезные ссылки