# Настройка передачи событий

События нужны для отслеживания важных пользовательских действий, таких как добавление товара в корзину, добавление в список желаемого, аутентификации в личном кабинете и многие другие. Отслеживание таких событий необходимо для понимания поведения пользователя и таргетинга на его основе, а также корректной работы рекомендательных стратегий и измерения эффективности кампаний.

Для отправки данных в GF необходимо внедрить небольшой кусочек кода для каждого необходимого события. В событии вы можете передавать тот набор параметров, которые в дальнейшем планируете использовать для работы. Ряд событий, таких как покупка или вход в личный кабинет требуют внедрения по определенной схеме, вместе с тем, для других целевых действий вы можете создавать и собственные события. 

!!!
При внедрении в e-commerce события `Purchase` и `Add to Cart` являются обязательными, но мы также рекомендуем внедрить максимальное количество событий из списка преднастроенных, которые релевантны для вашего сайта. Это поможет реализовать больше use-кейсов и расширить профиль пользователя. Окончательный список требуемых событий согласовывается с вашим менеджером по персонализации в зависимости от планируемых use-кейсов.
!!!

## Преднастроенные события

### Добавление в корзину [!badge variant="warning" text="обязательно для e-commerce"]

+++ Javascript 
```jsx
GF.API("event", {
  name: "Add to Cart",
  properties: {
    eventType: "add-to-cart-v1",
    value: 118.26,
    currency: "any supported currency code",
    productId: "item-34454",
    quantity: 2,
    cart: [{
        productId: "sku-4324-bg",
        quantity: 2,
        itemPrice: 12.34
      },
      {
        productId: "item-34454",
        quantity: 2,
        itemPrice: 59.13
      }
    ]
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`add-to-cart-v1`" | string |
| **value** [!badge variant="danger" text="обязательно"] | Сумма добавляемого в корзину. Если добавляется больше одной единицы товара, то содержит количество умноженное на стоимость единицы. Например, для 99 рублей 99 копеек передается как `99.99` | float |
| **currency** | Код валюты ISO 421, например "`RUB`". Опционально, но необходимо для сайтов с поддержкой мультивалютности | string |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |
| **quantity** [!badge variant="danger" text="обязательно"] | Количество товаров, добавленных в корзину | integer, только положительные значения |
| **cart** | Текущее состояние корзины, включая последний добавленный товар. Товар должны идти в порядке добавления - от самых старых до самых новых | array  |
| **Объект товара:** |  |  |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |
| **quantity** [!badge variant="danger" text="обязательно"]| Количество единиц данного товара в корзине | integer, только положительные значения |
| **itemPrice**  [!badge variant="danger" text="обязательно"] | Стоимость одной единицы товара после применения скидок (при их наличии) | float  |

!!!warning Частые ошибки
В событии `Add to cart` часто некорректно передается параметр `quantity` .
Данный параметр должен отражать фактически добавленное число единиц товара, а не сумму всех единиц после действия. 
Пример: в корзине было 2 единицы товара и мы добавили еще 1. 
В событии мы ожидаем увидеть `quantity: 1`, а видим `quantity: 3` — это неправильно.
!!!

### Покупка [!badge variant="warning" text="обязательно для e-commerce"]

+++ Javascript 
```jsx
GF.API("event", {
  name: "Purchase",
  properties: {
    uniqueTransactionId: "123456",
    eventType: "purchase-v1",
    value: 90.55,
    currency: "any supported currency code",
    cart: [
      {
        productId: "item-34454",
        quantity: 1,
        itemPrice: 65.87,
      }, {
        productId: "sku-4324-bg",
        quantity: 2,
        itemPrice: 12.34,
      }
    ]
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`purchase-v1`" | string |
| **uniqueTransactionId** [!badge variant="danger" text="обязательно"]  | Уникальный ID транзакции. Гарантирует, что к одной транзакции относится только одна покупка. Максимум 64 символа | string |
| **value** [!badge variant="danger" text="обязательно"] | Сумма добавляемого в корзину. Если добавляется больше одной единицы товара, то содержит количество умноженное на стоимость единицы. Например, для 99 рублей 99 копеек передается как `99.99` | float |
| **currency** | Код валюты ISO 421, например "`RUB`". Опционально, но необходимо для сайтов с поддержкой мультивалютности | string |
| **cart** | Текущее состояние корзины, включая последний добавленный товар. Товар должны идти в порядке добавления - от самых старых до самых новых | array  |
| **Объект товара:** |  |  |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |
| **quantity** [!badge variant="danger" text="обязательно"]| Количество единиц данного товара в корзине | integer, только положительные значения |
| **itemPrice**  [!badge variant="danger" text="обязательно"] | Стоимость одной единицы товара после применения скидок (при их наличии) | float  |

### Удаление товара из корзины

+++ Javascript 
```jsx
GF.API("event", {
  name: "Remove from Cart",
  properties: {
    eventType: "remove-from-cart-v1",
    value: 34.45,
    currency: "any supported currency code",
    productId: "gswefd-34-454",
    quantity: 1,
    cart: [{
        productId: "sku-4324-bg",
        quantity: 2,
        itemPrice: 12.34
      },
      {
        productId: "item-34454",
        quantity: 1,
        itemPrice: 34.45
      }
    ]
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}    
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`remove-from-cart-v1`" | string |
| **value** [!badge variant="danger" text="обязательно"] | Сумма удаляемого из корзины. Если удаляется больше одной единицы товара, то содержит количество умноженное на стоимость единицы. Если удаляются множественные артикулы сразу, рекомендуется использовать “синхронизацию корзины” (см. ниже) | float |
| **currency** | Код валюты ISO 421, например "`RUB`". Опционально, но необходимо для сайтов с поддержкой мультивалютности | string |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |
| **quantity** [!badge variant="danger" text="обязательно"] | Количество единиц товара, удалённого из корзины | integer, только положительные значения |
| **cart** | Текущее состояние корзины, включая последний добавленный товар. Товар должны идти в порядке добавления - от самых старых до самых новых | array  |
| **Объект товара:** |  |  |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |
| **quantity** [!badge variant="danger" text="обязательно"]| Количество единиц данного товара в корзине | integer, только положительные значения |
| **itemPrice**  [!badge variant="danger" text="обязательно"] | Стоимость одной единицы товара после применения скидок (при их наличии) | float  |

### Синхронизация корзины

Данное событие обновляет текущее состояние корзины. 
Событие рекомендуется к использованию в случае пакетного изменения состава корзины или изменения сотава корзины без участия пользователя, например:
1. Обновление корзины сервером (например, автоудаление из корзины товаров, которые закончились в процессе сессии пользователя)
2. Обновление корзины при авторизации пользователя (объединение корзин до/после логина)
3. Обновление корзины при заходе пользователя на сайт, в том числе автологин (например, автоматическая подгрузка корзины, собранной на mobile при заходе в web)
4. Массовое единовременное удаление товаров из корзины - полная очистка корзины или удаление ряда позиций одним кликом

+++ Javascript 
```jsx
GF.API("event", {
  name: "Sync cart",
  properties: {
    eventType: "sync-cart-v1",
    currency: "any supported currency code", 
    cart: [ 
      {
        productId: "sku-4324-bg",
        quantity: 2,
        itemPrice: 12.34
      },
      {
        productId: "item-34454",
        quantity: 1,
        itemPrice: 34.45
      }
    ]
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}    
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`sync-cart-v1`" | string |
| **currency** | Код валюты ISO 421, например "`RUB`". Опционально, но необходимо для сайтов с поддержкой мультивалютности | string |
| **cart** | Текущее состояние корзины, включая последний добавленный товар. Товар должны идти в порядке добавления - от самых старых до самых новых | array  |
| **Объект товара:** |  |  |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |
| **quantity** [!badge variant="danger" text="обязательно"]| Количество единиц данного товара в корзине | integer, только положительные значения |
| **itemPrice**  [!badge variant="danger" text="обязательно"] | Стоимость одной единицы товара после применения скидок (при их наличии) | float  |

### Добавление в список желаемого

+++ Javascript
```jsx
GF.API("event", {
  name: "Add to Wishlist",
  properties: {
    eventType: "add-to-wishlist-v1",
    productId: "item-34454"
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}  
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`add-to-wishlist-v1`" | string |
| **productId** [!badge variant="danger" text="обязательно"] | SKU, указанный так же, как и в фиде | string |

### Смена атрибута

Используется при смене пользователем атрибута отображаемого продукта, например, размера или цвета.

+++ Javascript
```jsx
GF.API("event", {
  name: "Change Attribute",
  properties: {
    eventType: "change-attr-v1",
    attributeType: "Color",
    attributeValue: "Navy Blue"
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}  
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"]  | Должен быть "`change-attr-v1`" | string |
| **attributeType** [!badge variant="danger" text="обязательно"]  | Цвет, размер, бренд и др., должно совпадать с заголовком колонки в фиде | string |
| **attributeValue** [!badge variant="danger" text="обязательно"]  | Новое значение, должно совпадать со значениями в фиде | string |

!!! Важно
Тип и значение атрибута должны совпадать со значениями в фиде.
!!!

### Фильтрация товаров

Используется, когда пользователь фильтрует товары по какому-либо значению поля.

+++ Javascript
```jsx
GF.API("event", {
  name: "Filter Items",
  properties: {
    eventType: "filter-items-v1",
    filterType: "Color", // Name of filter (Color, Size, Brand, Fit, Author, Keyword, Category...)
    filterNumericValue: 4
  }
});
```
+++

Описание полей объекта **properties**:

{.compact} 
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`filter-items-v1`" | string |
| **filterType** [!badge variant="danger" text="обязательно"] | Название фильтра (цвет, размер, бренд и др). Должен совпадать со свойством товара, указанным в фиде | string |
| **filterNumericValue** [!badge variant="danger" text="обязательно"] | Необходимо указать значение для этого свойства или для filterStringValue, но не для обоих. Это влияет на то, как будут выполняться условия сегментации. | number |
| **filterStringValue** [!badge variant="danger" text="обязательно"] | Необходимо указать значение для этого свойства или для filterNumericValue, но не для обоих. Это влияет на то, как будут выполняться условия сегментации. | string |

### Поиск по ключевым словам в поисковой строке

+++ Javascript 
```jsx
GF.API("event", {
  name: "Keyword Search",
  properties: {
    eventType: "keyword-search-v1",
    keywords: "my search string"
  }
});
```

Описание полей объекта **properties**:

{.compact} 
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`keyword-search-v1`" | string |
| **keywords** [!badge variant="danger" text="обязательно"] | Поисковой запрос в формате, как он был введен пользователем | string |

### Агрегация запросов при живом поиске
В случаях, когда на сайте доступен живой поиск (подбор ответов, соответствующий части введенного запроса), при передаче событий необходимо реализовать агрегацию запросов.
При использовании данного метода игнорируется передача каждого введенного символа и в систему отправляется только последнее состояние ввода.
Например, при вводе пользователем запроса “игра”, создается 4 записи: “и”, “иг”, “игр”, и, наконец, “игра”. Однако в систему отправляется только последний ввод “игра”, игнорируя предыдущие.

!!! Важно
При передаче события необходимо обозначить отсрочку, после которой запрос будет отправлен в систему.
Например, если пользователь начал вводить “игр”, остановился, и прошло 2 секунды (заранее определенные как необходимая отсрочка), в систему должен быть отправлен данный запрос - “игр”. Далее, если пользователь решил продолжить ввод, дописал “игра” и остановился, по истечении 2 секунд должен быть отправлен второй результат ввода “игра”.
!!!

### Ввод промокода

+++ Javascript
```jsx
GF.API("event", {
  name: "Promo Code Entered",
  properties: {
    eventType: "enter-promo-code-v1",
    code: "..."
  }
});
```
+++

Описание полей объекта **properties**:

{.compact} 
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`enter-promo-code-v1`" | string |
| **code** [!badge variant="danger" text="обязательно"] | Промокод | string |

### Сортировка товаров

+++ Javascript
```jsx
GF.API("event", {
  name: "Sort Items",
  properties: {
    eventType: "sort-items-v1",
    sortBy: "price",
    sortOrder: "ASC"
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`sort-items-v1`" | string |
| **sortBy** [!badge variant="danger" text="обязательно"] | Любой из параметров: цена, срок, популярность, рейтинг и другие, параметр должен совпадать с названием колонки в фиде | string |
| **sortOrder** [!badge variant="danger" text="обязательно"] | По возрастанию или по убыванию (`ASC` или `DESC`) | string |

### Подписка на почтовую рассылку

+++ Javascript 
```jsx
GF.API("event", {
  name: "Subscription",
  properties: {
    eventType: "newsletter-subscription-v1",
    hashedEmail: "хешированный ранее адрес",   }
});
// и/или; данные методы могут быть использованы параллельно
GF.API("event", {
  name: "Subscription",
  properties: {
    eventType: "newsletter-subscription-v1",
    cuid: "...", 
    cuidType: "..." 
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`newsletter-subscription-v1`" | string |
| **hashedEmail** | Email, переведенный в lowercase и хешированный на стороне клиента | string |
| **cuid** | Если идентификация не с помощью email, передается любой другой customer ID (опционально) | string |
| **cuidType** | При передаче `cuid` передается его тип (обязательно при передаче поля `cuid`) | string |

`сuid` может означать один из заранее заданных типов идентификаторов (допустимые и предопределённые типы - справочник) или иметь значение не из справочника, если на стороне клиента есть свой внутренний идентификатор, например, CRM_ID, мобильный телефон и другие.

!!!danger
Не используйте без хеширования идентификаторы, являющиеся персональными данными.
!!!

### Регистрация [!badge variant="warning" text="обязательно для e-commerce"]

+++ Javascript
```jsx
GF.API("event", {
  name: "Signup",
  properties: {
    eventType: "signup-v1",
    hashedEmail: "хешированный ранее адрес",   }
});
// и/или; данные методы могут быть использованы параллельно
GF.API("event", {
  name: "Signup",
  properties: {
    eventType: "signup-v1",
    cuid: "...", 
    cuidType: "..." 
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`signup-v1`" | string |
| **hashedEmail** | Email, переведенный в lowercase и хешированный на стороне клиента | string |
| **cuid** | Если идентификация не с помощью email, передается любой другой customer ID (опционально) | string |
| **cuidType** | При передаче `cuid` передается его тип (обязательно при передаче поля `cuid`) | string |

`сuid` может означать один из заранее заданных типов идентификаторов (допустимые и предопределённые типы - справочник) или иметь значение не из справочника, если на стороне клиента есть свой внутренний идентификатор, например, CRM_ID, мобильный телефон и другие.

!!!danger
Не используйте без хеширования идентификаторы, являющиеся персональными данными.
!!!

### Логин [!badge variant="warning" text="обязательно для e-commerce"]

+++ Javascript
```jsx
GF.API("event", {
  name: "Login",
  properties: {
    eventType: "login-v1",
    // 1. Нормализуйте номер телефона:
    //    "+7 (999) 000-00-00" → "79990000000"
    //    или международный формат без "+" и разделителей
    // 2. Постройте SHA-256 хеш нормализованной строки (UTF-8, lowercase hex)
    cuid: "HASHED_PHONE_STRING", // SHA-256(нормализованный телефон)
    cuidType: "phone_hash"
  }
});
```
+++

Описание полей объекта **properties**:

{.compact}
| Свойство | Описание | Тип |
| --- | --- | --- |
| **eventType** [!badge variant="danger" text="обязательно"] | Должен быть "`login-v1`" | string |
| **cuid** [!badge variant="danger" text="обязательно"] | SHA-256 хеш (lowercase hex) нормализованного номера мобильного телефона. Номер должен содержать только цифры (для РФ/КЗ — формат `7XXXXXXXXXX` без `+`, пробелов, скобок и дефисов; для других стран — международный формат без `+`). Тот же хеш должен использоваться во всех интеграциях (Web, Mobile SDK, Server-Side API, импорт офлайн-данных). | string |
| **cuidType** [!badge variant="danger" text="обязательно"] | Должен быть строковым литералом "`phone_hash`". Используется для явного указания, что в `cuid` передаётся хеш номера телефона. | string |
| **hashedEmail** | Опционально. Email, переведенный в lowercase и хешированный на стороне клиента (SHA-256). Может использоваться для сценариев, где необходима идентификация по email, но не является основным CUID при стандарте по телефону. | string |

`сuid` может означать один из заранее заданных типов идентификаторов (допустимые и предопределённые типы - справочник) или иметь значение не из справочника, если на стороне клиента есть свой внутренний идентификатор, например, CRM_ID, мобильный телефон и другие.

!!!danger
Не используйте без хеширования идентификаторы, являющиеся персональными данными.
!!!

## Кастомные события

Если вы хотите отслеживать событие, не указанное в списке выше, воспользуйтесь для его создания следующей структурой:

```jsx
GF.API("event", {
  name: "EVENT_NAME",
  properties: {  
    [FIRST PROPERTY NAME]: "[PROPERTY VALUE]",  // Optional
    [SECOND PROPERTY NAME]: "[PROPERTY VALUE]",  // Optional
    value: "[MONETARY VALUE]" // Optional
  }
})
```

или

```jsx
GF.API("event", {
  name: "EVENT_NAME"
})
```

---

## Идентификация пользователей

Происходит двумя основными способами.

**Стандартный способ (рекомендуется): через `cuid` на основе номера телефона**

- В событии `Login` в `properties.cuid` **обязательно** передаётся SHA-256 хеш (lowercase hex) нормализованного мобильного телефона.
- Номер телефона перед хешированием должен быть очищен от всех символов, кроме цифр:
  - для РФ/КЗ — формат `7XXXXXXXXXX` (начинается с кода страны `7`, без `+`, пробелов, скобок и тире);
  - для других стран — международный формат без `+` и разделителей.
- В `properties.cuidType` **обязательно** передаётся строка `phone_hash`.
- Тот же хеш и значение `cuidType = phone_hash` должны использоваться во **всех каналах** (Web, мобильные SDK, Server-Side API, импорт офлайн-данных), чтобы профили объединялись в единую сущность.
- Если в CDP или DWH уже рассчитывается этот идентификатор по описанному алгоритму, во всех типах интеграции (включая Web и мобильные SDK) необходимо передавать **именно тот хеш**, который используется в CDP, чтобы обеспечить единый «золотой» ключ пользователя.

**С помощью поля `hashedEmail`**

В нем передается SHA-256 хеш email пользователя.
Если передается email, то адрес переводится в lowercase, затем хешируется.
Пример:

`Test@TEST.com` → `test@test.com` — перевод в lowercase  
`test@test.com` → `f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a` — хеширование

Поле `hashedEmail` может использоваться для сценариев, где идентификация строится по email (например, подписка на рассылку), но при стандарте по телефону оно **не должно** рассматриваться как основной CUID.

**С помощью поля `cuid` (произвольные идентификаторы)**

`cuid` (Customer Unique Identifier) может быть любым уникальным значением, используемым для идентификации пользователя — это может быть CRM ID или любой другой ID.
При выбранном стандарте по телефону значение `cuid` в событии `Login` всегда должно быть хешем телефона с типом `phone_hash`.
 
!!!danger
Не используйте без хеширования идентификаторы, являющиеся персональными данными.
!!!
