Гибридная интеграция

Гибридная интеграция сочетает возможности API и Web-интеграции. Критичные кампании можно запрашивать через API на сервере и включать персонализированный контент в HTML-разметку до загрузки страницы. При этом web-скрипт остаётся доступен для клиентских кампаний, сбора событий и быстрых гипотез.

Для новых server-side и headless-сценариев используйте API V2. Если у вас уже работает интеграция через /ssapi/*, её можно оставить на API V1 и переносить сценарии постепенно.

Как это работает

В гибридной модели главный путь выбора вариации проходит через backend сайта. Web-скрипт подключается уже на клиенте и закрывает клиентские сценарии: cookie, web-кампании и события.

Такой подход нужен, когда важно показать персонализированный контент без задержки и мерцания, но при этом сохранить возможности Web-интеграции: сбор событий, web-кампании, клиентские взаимодействия и единые идентификаторы пользователя.

sequenceDiagram
    participant Browser as Браузер
    participant Backend as Backend сайта
    participant GFAPI as Gravity Field API
    participant WebScript as Web-скрипт Gravity Field
    participant Tracking as Gravity Field tracking

    Browser->>Backend: GET /page<br/>Cookie: _slid_server, _slid, _slsession
    Backend->>Backend: Читает cookie из HTTP-запроса
    Backend->>GFAPI: POST /v2/choose или /ssapi/choose
    GFAPI-->>Backend: Возвращает вариацию, идентификаторы и tracking-данные
    Backend->>Backend: Подставляет вариацию в серверный шаблон
    Backend-->>Browser: HTML с готовым блоком<br/>Set-Cookie при необходимости
    Browser->>WebScript: Загружает web-скрипт
    Browser->>Tracking: Отправляет показы, visible impression и клики

В результате пользователь получает готовую страницу с выбранной вариацией, а Gravity Field продолжает связывать показы, клики и события с тем же профилем пользователя.

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

Если Web-интеграция уже завершена, то в браузере пользователя в корневом домене сайта есть cookie:

Если вы ещё не выставляете cookie _slid_server, завершите настройку 1st-party cookie.

API V1

Перед запросом V1 прочитайте cookie _slid_server или _slid, а также _slsession.

user.slid:

  • значение cookie _slid_server, если оно есть;
  • иначе значение cookie _slid, если оно есть;
  • иначе null.

session.sl:

  • значение cookie _slsession, если оно есть;
  • иначе null.
<?php
$user_id = $_COOKIE['_slid_server'] ?? $_COOKIE['_slid'] ?? null;
$session_id = $_COOKIE['_slsession'] ?? null;

$requestParams = [
    "user" => [
        "slid" => $user_id,
    ],
    "session" => [
        "sl" => $session_id,
    ],
];
?>

Если платформа сгенерировала новый ID пользователя или сессии, в ответе V1 будут значения для установки cookie. Обновляйте значения и срок жизни cookie при каждом получении cookies[]. Для этих cookie не должен быть установлен параметр HttpOnly, если они должны быть доступны web-скрипту.

{
  "user": {
    "slid": "6495a07d71568849c607a6ed"
  },
  "session": {
    "sl": "43F9AD00-2D33-4AA3-8EE4-5638E8EB5976"
  },
  "cookies": [
    {
      "name": "_slid_server",
      "value": "6495a07d71568849c607a6ed",
      "maxAge": "31556926"
    },
    {
      "name": "_slsession",
      "value": "43F9AD00-2D33-4AA3-8EE4-5638E8EB5976",
      "maxAge": "1800"
    }
  ]
}
<?php
if (isset($data['cookies']) && is_array($data['cookies'])) {
    foreach ($data['cookies'] as $cookie) {
        if (isset($cookie['name'], $cookie['value'], $cookie['maxAge'])) {
            setcookie(
                $cookie['name'],
                $cookie['value'],
                time() + (int)$cookie['maxAge'],
                "/",
                $site_root_domain
            );
        }
    }
}
?>

API V2

В web-hybrid сценарии V2 использует те же идентификаторы пользователя и сессии, которые уже живут в web-cookie. Отличается только название полей в API-запросе:

Web cookie Поле в API V2
_slid_server, если есть; иначе _slid user.uid
_slsession user.ses
const uid = getCookie('_slid_server') || getCookie('_slid') || null;
const ses = getCookie('_slsession') || null;

const requestBody = {
  user: {
    uid,
    ses
  }
};

В V2 пользователь и сессия передаются в одном объекте user:

{
  "user": {
    "uid": "USER_UID",
    "ses": "SESSION_ID"
  }
}

Храните uid между сессиями пользователя, а ses - для текущей browser session. На сайте это означает, что uid нужно сохранять в _slid_server, а ses - в _slsession. Если пользователь новый, первый запрос можно отправить без uid и ses: Gateway создаст идентификаторы и вернёт их в response.user.

После ответов /user, /visit, /event или /choose обновляйте сохранённые значения, если они пришли в ответе:

if (response.user?.uid) {
  setCookie('_slid_server', response.user.uid, { maxAge: 31556926, path: '/' });
}

if (response.user?.ses) {
  setCookie('_slsession', response.user.ses, { maxAge: 1800, path: '/' });
}

Если в hybrid-сценарии одновременно используется web-скрипт и V2, web-идентификаторы остаются общими для обоих слоёв: web-скрипт продолжает работать с cookie _slid, _slid_server и _slsession, а backend мапит их значения в поля user.uid и user.ses для V2-запросов.

Получение кампаний

API V1: /ssapi/choose

V1-запрос использует selector.names[], context.page, user.slid и session.sl.

{
  "user": {
    "slid": "6495a07d71568849c607a6ed"
  },
  "session": {
    "sl": "43F9AD00-2D33-4AA3-8EE4-5638E8EB5976"
  },
  "context": {
    "page": {
      "type": "HOMEPAGE",
      "location": "https://shop.ru/"
    }
  },
  "selector": {
    "names": ["homepage_cta_test"]
  }
}

В ответе V1 используйте choices[].variations[].payload для рендера контента, choices[].decisionId для tracking и cookies[] для обновления cookie.

API V2: /v2/choose

V2-запрос использует sec, user.uid, user.ses, ctx, device, options и data[].selector.

{
  "sec": "YOUR_SECTION_ID",
  "user": {
    "uid": "VALUE_FROM__slid_server_OR__slid",
    "ses": "VALUE_FROM__slsession"
  },
  "ctx": {
    "type": "HOMEPAGE",
    "data": [],
    "location": "https://shop.ru/"
  },
  "device": {
    "ua": "Mozilla/5.0",
    "ip": "54.100.200.255"
  },
  "options": {
    "isImplicitPageview": true,
    "isBuildEngagementUrl": true
  },
  "data": [
    {
      "selector": "homepage_cta_test"
    }
  ]
}

Для ручного рендера обычно включайте options.isBuildEngagementUrl: true. Тогда Gateway вернёт готовые tracking URL:

  • content.events[].urls[] - для tracking контентного блока;
  • products.slots[].events[].urls[] - для tracking отдельных товарных карточек.

Эти URL нужно вызвать в момент показа, видимого показа, клика или другого действия, которое описано в ответе кампании.

Обработка ошибок

Для server-side запроса задайте короткий timeout. Если API не ответил вовремя или вернул ошибку, рендерьте безопасный fallback: базовый баннер, стандартный CTA, обычную выдачу товаров или другой контент по умолчанию. Tracking отправляйте только для реально показанной вариации.