# Трекинг событий Shopping Assistant

Для анализа качества Shopping Assistant передавайте в Gravity Field custom events по ключевым шагам диалога. Эти события помогают понять, открывают ли пользователи чат, отправляют ли сообщения, получают ли ответы и где возникают ошибки или разрывы воронки.

!!!
В этом разделе описаны только custom events ассистента.
!!!

---

## Базовая воронка

Минимальная воронка диалога:

```text
chat_dialog_open -> assistant_message_sent -> assistant_response_received
```

Если ответ содержит товарную подборку, дополнительно фиксируйте:

```text
assistant_response_received -> assistant_product_selection_received
```

Ошибки и закрытия анализируются отдельно:

```text
chat_error
chat_dialog_close
chat_dialog_end
```

---

## События ассистента

| Событие | Когда отправлять |
| :--- | :--- |
| `chat_dialog_open` | Пользователь открыл чат ассистента. |
| `assistant_message_sent` | Пользователь отправил сообщение ассистенту. |
| `assistant_response_received` | Frontend получил и отобразил ответ ассистента. |
| `assistant_product_selection_received` | Ответ ассистента содержит товарную подборку. |
| `chat_error` | Frontend зафиксировал ошибку в сценарии ассистента. |
| `chat_dialog_close` | Пользователь закрыл чат. |
| `chat_dialog_end` | Диалог завершен. |

### Как считать ответ полученным

Событие `assistant_response_received` отправляйте после того, как ответ успешно получен и добавлен в интерфейс чата. Если API ответил, но пользователь уже закрыл чат или frontend не смог отрендерить ответ, событие отправлять не нужно.

### Как считать товарную подборку

Событие `assistant_product_selection_received` отправляйте, если в ответе ассистента есть блок:

```json
{
  "type": "products",
  "value": []
}
```

Если блок `products` отсутствует или список товаров пустой, событие отправлять не нужно.

---

## Рекомендуемые поля

Передавайте технические идентификаторы, которые позволяют связать события одного диалога и одного запроса.
`resourceId` берите из `user.uid` Gravity Field. Его можно получить через [`POST /user`](/Integration/api_integration/v2/personalization/user.md).

| Поле | Назначение |
| :--- | :--- |
| `threadId` | ID диалога. Должен совпадать с `threadId` в `/shopping/generate`. |
| `resourceId` | `uid` пользователя Gravity Field. |
| `messageId` | ID пользовательского сообщения, если клиентская сторона его генерирует. |
| `requestId` | ID запроса к ассистенту, если клиентская сторона его генерирует. |
| `trafficType` | `real` или `test`, если это значение используется в интеграции. |
| `tenant_id` | ID секции Gravity Field. |
| `campaignId` | ID кампании, если ассистент запущен из кампании. |
| `experienceId` | ID experience, если ассистент запущен из кампании. |
| `variationId` | ID variation, если ассистент запущен из кампании. |
| `latencyMs` | Время ожидания ответа, где применимо. |
| `errorCode` | Код ошибки для `chat_error`, если он есть на стороне клиента. |

!!!
Не передавайте в event payload текст сообщений, персональные данные, чувствительные данные пользователя и другие данные, которые не нужны для аналитики воронки.
!!!

---

## Пример custom event

Ниже пример события для API V2. Дополнительные поля передаются в `customProps`.

```json
{
  "type": "assistant_message_sent",
  "name": "Assistant Message Sent",
  "customProps": {
    "threadId": "thread-8f2b1c",
    "resourceId": "665f0a000000000000000001",
    "messageId": "message-1001",
    "requestId": "request-7001",
    "trafficType": "test",
    "tenant_id": "670ccaae56afcafaf808c146",
    "campaignId": "696a3dcf26ec5935e70a7f05",
    "experienceId": "69f9fd5a4006ae8b33086404",
    "variationId": "69f9fd5a4006ae8b3308640e"
  }
}
```

Для передачи события используйте тот же канал, который уже применяется в вашей интеграции: Web, API или SDK.

---

## Диагностика разрывов

Разрыв воронки возникает, когда пользователь отправил сообщение, но frontend не зафиксировал получение ответа:

```text
assistant_message_sent -> нет assistant_response_received
```

Чтобы такие случаи можно было анализировать, важно:

- использовать стабильный `threadId` на протяжении всего диалога;
- передавать `messageId` или `requestId` для каждого пользовательского сообщения;
- отправлять `chat_error`, если frontend получил ошибку;
- отправлять `chat_dialog_close`, если пользователь закрыл чат;
- передавать `latencyMs` в `assistant_response_received` и `chat_error`, если время ожидания известно.
