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

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

![](/images/plp/PLP_-_Sorting.gif)

---

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

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

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

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

---

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

![](/images/plp/Component_139.png)

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

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

---

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

![](/images/plp/Component_141.png)

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

---

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

PLP использует **API-кампании** и требует **серверной интеграции**. Подробнее:
- [Интеграция через API](/Integration/api_integration/api_integration.md)
- [API-кампании](./api_campaigns.md)

![](./assets/plp.png)

---

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

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

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

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

📘 Подробнее: [Контекст страницы (Page Context)](/Integration/api_integration/page_context.md)

---

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

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

![](/images/plp/Screenshot_2024-05-29_at_14.50.36.png)

---

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

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

![](/images/plp/Screenshot_2024-05-29_at_14.44.09.png)

---

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

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

📘 Подробнее: [Choose API](/Integration/api_integration/personalization/choose.md)

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

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

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

```json
{
	"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
    }
}
```

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

```json
{
    "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` используется для применения пользовательских фильтров (например, по бренду).  
> Поля для фильтрации должны быть доступны в [фиде товаров](/Integration/products_catalogues/general_reqs.md).

---

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

Для отслеживания эффективности и сбора аналитики — отправляйте события взаимодействия:
📘 [Engagement API](/Integration/api_integration/personalization/engagement.md)  
📘 [JS SDK](/Integration/web_integration/client_side_api/other_helpful.md#трекинг-взаимодействия-с-апи-кампанией)

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

---

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

### 🔸 Нужно ли подключать API-интеграцию?
Да. Модуль PLP работает только через [серверную API-интеграцию](/Integration/api_integration/api_integration.md).  
Также потребуется настроить [API-кампании](./api_campaigns.md) и реализовать вызовы `choose`, `engagement`, `page`.

---

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

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

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

---

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

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

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

```js
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)

```js
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-кампанией](https://docs.gravityfield.ai/Integration/web_integration/client_side_api/other_helpful.md#трекинг-взаимодействия-с-апи-кампанией)

---

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

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

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

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

---

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

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

```json
"context": {
  "page": {
    "page": 2
  }
}
```

---

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

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

Пример:
- `Popularity` → новые пользователи
- `Affinity` → авторизованные или постоянные

---

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

- [API-интеграция](/Integration/api_integration/api_integration.md)
- [Выбор контента (Choose)](/Integration/api_integration/personalization/choose.md)
- [Engagement события](/Integration/api_integration/personalization/engagement.md)
- [Фид товаров и фильтры](/Integration/products_catalogues/general_reqs.md)
- [API-кампании](./api_campaigns.md)
