ДокументацияРуководства
Рекомендации
Лента, похожие и «дополните заказ», переранжирование, фильтры по свойствам, пагинация и recommendation_id, что не показывается, метрики выдачи, запасная выдача и таймауты.
ДАРА подбирает объекты проекта для конкретного посетителя тремя методами. Пользователь передаётся объектом user, как в событиях; без него выдача неперсональная. Каждый ответ 200 содержит recommendation_id — id выдачи: передавайте его в событиях показа, открытия и цели, по нему считаются метрики.
| Метод | Для чего | Ответ |
|---|---|---|
POST /recommendations/feed |
лента: главная, бесконечная прокрутка | recommendation_id, items: [{id, score, reason}], has_more, mode, identity |
POST /recommendations/similar |
похожие на объект и «дополните заказ» для корзины | recommendation_id, items: [{id, score, reason}], mode, identity |
POST /recommendations/rerank |
упорядочить ваш список id под пользователя | recommendation_id, items: [{id, score}], identity |
Запросы идут с вашего сервера с ключом проекта: Authorization: Bearer ck_XXXXXXXX… — в примерах он в переменной окружения DARA_KEY. Лимит частоты выдачи — 100 запросов в секунду на ключ. Все поля и схемы — в справочнике API.
Лента: POST /recommendations/feed
curl -X POST https://core.daratech.ru/api/v1/recommendations/feed \
-H "Authorization: Bearer $DARA_KEY" \
-H "Content-Type: application/json" \
-d '{"user": {"user_id": "u-501", "anonymous_id": "a-7f3c2e"}, "limit": 24, "offset": 0}'
{"recommendation_id": "01JC8Z6Q9W3M5N7P2R4T6V8X0Y",
"items": [{"id": "v-2210", "score": 0.9132, "reason": "interest"},
{"id": "v-1877", "score": 0.8417, "reason": "together"},
{"id": "v-2301", "score": 0.6205, "reason": "fresh"}],
"has_more": true, "mode": "personal", "identity": "user"}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
user |
object | — | {user_id, anonymous_id, fingerprint_uuid}, хотя бы одно поле — см. Пользователи |
limit |
int от 1 до 100 | 24 | объектов на странице |
offset |
int от 0 до 1000 | 0 | 0 — новая выдача, больше 0 — следующие страницы той же выдачи (пагинация) |
types |
array | все типы | от 1 до 5 разных типов: video, image, audio, text, mixed |
exclude |
array | — | до 500 id объектов, которые не показывать |
filters |
object | — | условия по свойствам объектов — Фильтры |
recommendation_id |
string | — | id выдачи первой страницы; необязателен |
Пустое тело — все умолчания. Неизвестное поле — ответ 422 validation_failed с кодом unknown_field в details.
reason — почему объект в ленте:
reason |
Источник |
|---|---|
interest |
близок к интересам пользователя — по его действиям и указанным вами интересам |
session |
близок к тому, что пользователь смотрит сейчас |
together |
его открывают или покупают вместе с тем, что понравилось пользователю |
author |
новое у близкого или любимого автора |
trending |
набирает популярность в последние дни |
fresh |
новый объект |
popular |
стабильно популярный объект |
segment |
популярный у похожих пользователей: та же страна, город, пол и возраст |
Когда новое для пользователя заканчивается, лента продолжается уже досмотренными объектами — давно досмотренными первыми.
Похожие и «дополните заказ»: POST /recommendations/similar
curl -X POST https://core.daratech.ru/api/v1/recommendations/similar \
-H "Authorization: Bearer $DARA_KEY" \
-H "Content-Type: application/json" \
-d '{"item": "v-1042", "user": {"anonymous_id": "a-7f3c2e"}, "limit": 8}'
{"recommendation_id": "01JC8Z8C3E5G7J9L1N3Q5S7U9W",
"items": [{"id": "v-1188", "score": 0.7311, "reason": "similar"},
{"id": "v-0977", "score": 0.6824, "reason": "together"}],
"mode": "cold", "identity": "anonymous"}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
item |
string | — | id исходного объекта |
items |
array | — | корзина — «дополните заказ»: от 1 до 20 id; неизвестные ДАРА id не учитываются |
user |
object | — | как у ленты |
limit |
int от 1 до 50 | 8 | объектов в ответе |
types, exclude, filters |
— | как у ленты |
Нужно ровно одно из полей item и items, иначе 422 с кодом invalid_value; больше 20 id в items — too_many. Страниц у похожих нет: поля offset и recommendation_id в запросе нет — переданные, они дают 422 с кодом unknown_field; has_more в ответе нет.
- Кандидаты — близкие по содержанию, объекты «вместе» с исходными, новое того же автора (для одного исходного объекта) и, если выдача персональная, объекты по интересам пользователя. Исходные объекты в ответ не попадают.
- Корзина. Для нескольких объектов важнее то, что покупают вместе, чем замены: «дополните заказ» подбирает дополнения к корзине.
- Новый объект участвует в похожих сразу после
PUT— по быстрому вектору из заголовка и описания, ещё до конца анализа. - Удалённый или недоступный исходный объект работает как обычный: похожие считаются по его сохранённым векторам.
- Объекта нет в ДАРА (например, вы не передаёте непубличные страницы) — ответ
200с популярным проекта:mode: fallback,reason: popular, сrecommendation_idдля метрик. Так же, если у исходных объектов нет ни векторов, ни соседей «вместе».
reason у похожих: similar — близок по содержанию, together — покупают или смотрят вместе, author — тот же автор, interest — интересы пользователя, popular — популярное, trending — в тренде (только в запасной выдаче).
Переранжирование: POST /recommendations/rerank
Упорядочивает ваш список — например, результаты поиска или подборку редакции — по оценке ленты для этого пользователя.
curl -X POST https://core.daratech.ru/api/v1/recommendations/rerank \
-H "Authorization: Bearer $DARA_KEY" \
-H "Content-Type: application/json" \
-d '{"user": {"user_id": "u-501"}, "items": ["v-5", "v-9", "v-404", "v-12"]}'
{"recommendation_id": "01JC8Z9D4F6H8K0M2P4R6T8V0X",
"items": [{"id": "v-9", "score": 0.5521}, {"id": "v-5", "score": 0.4108},
{"id": "v-404", "score": null}, {"id": "v-12", "score": null}],
"identity": "user"}
| Поле | Тип | Описание |
|---|---|---|
items |
array, обязательно | от 1 до 1000 id объектов; больше 1000 — ответ 413 payload_too_large |
user |
object | как у ленты |
filters |
object | принимается и не применяется |
- В ответе все переданные id, столько же, сколько в запросе. Сначала — по убыванию оценки (при равной оценке — в исходном порядке), затем в конце, в исходном порядке и с
score: null:- неизвестные ДАРА, удалённые и недоступные объекты;
- объекты без векторов (ещё не проанализированы);
- объекты, скрытые пользователем;
- повторы id после первого вхождения.
- Не применяются: фильтры, скрытые авторы, возраст, досмотренное и приглушение купленного, разведка и разнообразие. Объект скрытого пользователем автора получает оценку как обычно.
- Поля
modeв ответе нет. Если оценить не успели — исходный порядок, у всех объектовscore: null.
Поля ответа
Как определён пользователь: identity
| Запрос | identity |
|---|---|
нет user или в нём нет учитываемых идентификаторов |
none |
есть user_id — пользователь известен ДАРА или ещё нет |
user |
без user_id, устройство узнано — узнавание без входа |
recognized |
без user_id, пользователь найден по anonymous_id или проверенному fingerprint_uuid |
anonymous |
без user_id, anonymous_id или fingerprint_uuid ДАРА ещё не знает |
anonymous |
| идентификатор неверного формата | ответ 422, код invalid_user |
fingerprint_uuidучитывается, только если в проекте подключён DARA Fingerprint; без подключения запрос только с ним —identity: none.- Запрос выдачи пользователей не создаёт: неизвестный пользователь получает неперсональную выдачу, а его события потом создадут пользователя.
Режим выдачи: mode
mode |
Когда | Из чего выдача |
|---|---|---|
personal |
у пользователя достаточно истории действий или указанных вами интересов | интересы профиля, текущая сессия, объекты «вместе» с понравившимся, близкие и любимые авторы, тренды, популярное, новое |
cold |
новый или неизвестный посетитель, user не передан, мало истории, отказ от персонализации (personalization: false) |
тренды, популярное, новое, текущая сессия (кроме отказавшихся), популярное в сегменте пользователя |
fallback |
запасная выдача: подбор не уложился во время ответа, индекс проекта загружается, база данных недоступна; у похожих — исходного объекта нет в ДАРА или у него нет векторов и соседей | трендовый или популярный список проекта |
Пользователь с указанными интересами получает personal сразу, как только интересы получат векторы — обычно в течение минуты после записи профиля; исключение — контрольная группа, её выдача указанные интересы не использует. Лента смещается к новым интересам пользователя в течение минуты после его действий.
Оценка: score
score — оценка объекта для этого пользователя, 4 знака после точки. Сравнивайте оценки только внутри одного ответа: шкала зависит от режима. В fallback score — трендовость или популярность объекта в запасном списке, от 0 до 1. В переранжировании score: null — объект не оценивался (выше).
Фильтры
filters — условия по свойствам объектов (properties), которые отмечены фильтруемыми в кабинете: проект → «Выдача» → «Фильтруемые свойства объектов», с типом свойства.
{"filters": {"in_stock": true, "brand": {"in": ["acme", "nord"]}, "price": {"gte": 100, "lte": 5000},
"regions": {"any": ["msk", "spb"]}}}
| Тип свойства | Условие | Пример |
|---|---|---|
| строка | равенство; in, not_in — от 1 до 100 строк |
"brand": "acme", "brand": {"not_in": ["noname"]} |
| число | равенство; in, not_in; gte, lte |
"price": {"gte": 100, "lte": 5000} |
| да/нет | равенство | "in_stock": true |
| список строк | any — у объекта есть хотя бы одно из значений, от 1 до 100 строк |
"regions": {"any": ["msk", "spb"]} |
-
В одном запросе — до 10 свойств. Несколько свойств и несколько условий одного свойства объединяются по «И».
-
Строки сравниваются точно, с учётом регистра.
-
Нет свойства у объекта или значение другого типа — условие не выполнено, кроме
not_in: оно выполнено. -
Свойство не отмечено фильтруемым, условие не подходит к типу свойства,
null, пустой массив или больше 100 значений — ответ422с кодомunknown_filterи полемfilters.<свойство>:{"error": {"code": "validation_failed", "message": "Поля не прошли проверку", "details": [{"field": "filters.color", "code": "unknown_filter", "message": "свойство не отмечено фильтруемым в настройках выдачи проекта"}]}} -
Где действуют: лента, похожие, следующие страницы и запасная выдача. В переранжировании
filtersне применяются. -
Узкий фильтр. Если подходящих кандидатов мало, выдача добирается популярными объектами, которые проходят фильтр.
-
После изменения фильтруемых свойств фильтры работают сразу, но пока перестраивается индекс проекта (секунды, у больших каталогов — минуты), запросы с фильтрами получают запасную выдачу (
mode: fallback) — тоже только из подходящих объектов.
Пагинация и recommendation_id
- Первая страница (
offset: 0) строит новую выдачу — до 500 объектов — и сохраняет её снимком на 30 минут. - Следующие страницы — тот же запрос с
offset: страница берётся из снимка, без повторов и пропусков.recommendation_idпередавать не обязательно: без него страница находится по идентификаторам пользователя и параметрам запроса. - Передавайте на всех страницах одни и те же
user,types,excludeиfilters. Другиеtypes,excludeилиfilters— это другая выдача: не дописывайте показанные объекты вexcludeмежду страницами. - Первая страница без
anonymous_id(посетитель пришёл впервые и cookie ещё нет), а следующие с ним — лента продолжается. Вход между страницами (добавилсяuser_id) тоже продолжает ту же ленту. - Без
userвыдача одинакова для всех посетителей в течение часа и меняется со следующим часом. has_more— есть ли объекты в снимке после этой страницы. Страница может быть корочеlimit: объекты, которые удалили, скрыли или сделали недоступными после первой страницы, из неё выбрасываются, аhas_moreостаётся честным.offsetза концом снимка —items: [],has_more: false.- Снимок истёк (30 минут) или не найден — строится новая выдача и отдаётся срез от
offset; на стыке возможны повторы. - Узнавание прекратилось между страницами (на устройстве вошёл другой аккаунт, узнавание выключили) — следующие страницы уже не берутся из ленты узнанного пользователя; на стыке возможны повторы.
У похожих и переранжирования страниц нет, но recommendation_id есть в каждом ответе — для метрик.
Что никогда не показывается
В ленте, похожих, на следующих страницах и в запасной выдаче не бывает:
- удалённых и недоступных объектов (
available: false) и объектов без векторов — новый объект получает быстрый вектор вскоре послеPUT; - объектов, скрытых пользователем: события типов с флагом «скрывает объект», например
reportиnot_interested; - недавно досмотренного и дочитанного — типы событий со значением
watch_secondsилиpercent; когда новое заканчивается, лента продолжается досмотренным; - купленного и почти одинаковых с ним объектов — весь срок приглушения типа события (в пресете «Магазин» у покупки 30 дней);
- объектов скрытых авторов (
hidden_authors); - объектов с возрастной отметкой старше возраста пользователя — при включённом фильтре по возрасту и известном годе рождения; пользователю с неизвестным возрастом такие объекты показываются;
- объектов других типов, из
excludeи не прошедшихfilters.
События по удалённым, недоступным и скрытым объектам принимаются и учитываются в профиле: это видно в кабинете, в карточке пользователя. Как скрытые объекты ведут себя в переранжировании — выше. Запасная выдача, собранная без обращения к базе данных (база недоступна или время ответа вышло), применяет то, что есть в памяти ДАРА: объекты, скрытые пользователем, и только что удалённые в ней могут встретиться.
Разведка и разнообразие
- Разведка. Несколько позиций в каждых 24 объектах ленты отдаются новым объектам: они получают показы и статистику, даже если пока проигрывают популярным. Какой новый объект встанет на позицию, решают близость к интересам пользователя и доля случайности. Случайность детерминирована: у одной выдачи порядок один и тот же.
- Разнообразие. Каждый следующий объект выбирается с учётом того, насколько он похож на уже выбранные, — лента не состоит из почти одинаковых объектов. У одного автора — не больше нескольких объектов в любом окне из 24 позиций ленты и в одном ответе похожих.
- Числа. Веса оценки, число кандидатов, позиции разведки и ограничения разнообразия настраивает ДАРА для проекта; в документации они не публикуются и могут меняться без изменения API.
Метрики выдачи
Метрики считаются по событиям, которые вы присылаете. Для каждого показа и открытия объекта из выдачи передайте:
| Поле события | Что передавать |
|---|---|
recommendation_id |
id выдачи из ответа, где был объект |
surface |
место на сайте: feed, next, cart — как вы его называете; сравнивается точно, Feed и feed — разные поверхности |
position |
позиция объекта в выдаче, с 0; на следующих страницах — offset плюс номер на странице |
Показы первой и второй страницы ленты по 24 объекта:
{"events": [
{"id": "imp-91a7-0", "type": "impression", "item": "v-2210", "user": {"anonymous_id": "a-7f3c2e"},
"recommendation_id": "01JC8Z6Q9W3M5N7P2R4T6V8X0Y", "surface": "feed", "position": 0},
{"id": "imp-91a7-1", "type": "impression", "item": "v-1877", "user": {"anonymous_id": "a-7f3c2e"},
"recommendation_id": "01JC8Z6Q9W3M5N7P2R4T6V8X0Y", "surface": "feed", "position": 1},
{"id": "imp-91a7-24", "type": "impression", "item": "v-0412", "user": {"anonymous_id": "a-7f3c2e"},
"recommendation_id": "01JC8Z6Q9W3M5N7P2R4T6V8X0Y", "surface": "feed", "position": 24}
]}
- Цели. Целевое событие без
recommendation_id(досмотр, покупка, в том числе черезPOST /orders) приписывается выдаче, если за 2 часа до него тот же пользователь открыл этот объект из выдачи. - База для сравнения. Показы вашей собственной ленты (хронологической, редакционной) отправляйте с той же
surfaceи безrecommendation_id— они образуют срез «без рекомендаций». - Показатели — в кабинете, проект → «Метрики», по поверхностям и дням по Москве: показы, открытия, CTR (открытия / показы), цели на 100 показов, вовлечённость (средняя дневная по парам «пользователь × объект» у типов со значением
watch_secondsиpercent, не больше 1), доля показов свежих объектов, покрытие каталога (доля доступных объектов, показанных из выдачи за 7 дней), доля запасной выдачи — основная без запросов похожих для объектов, которых нет в ДАРА, и разбивка по причинам. - Контрольная группа. Часть пользователей получает выдачу без ваших данных о пользователях — так измеряется их эффект. Правила — Данные о пользователях, сравнение групп — проект → «Данные о пользователях».
Тайм-аут и запасная выдача
- Тайм-аут на вашей стороне — около 700 мс на запрос выдачи и около 200 мс на соединение. ДАРА отвечает быстрее своего дедлайна: если подбор не успевает, вы получаете запасную выдачу, а не ожидание.
- Запасная выдача — ответ
200сmode: fallback:- лента и похожие, когда подбор не уложился во время ответа, индекс проекта загружается или база данных недоступна, — трендовый список проекта,
reason: trending; - похожие для объекта, которого нет в ДАРА, или без векторов и соседей, — популярный список,
reason: popular; score— трендовость или популярность объекта в списке, от 0 до 1;- удалённое, недоступное,
exclude,types,filtersи данные пользователя, которые ДАРА успела прочитать, учитываются и здесь; - переранжирование — исходный порядок, все
score: null.
- лента и похожие, когда подбор не уложился во время ответа, индекс проекта загружается или база данных недоступна, — трендовый список проекта,
503 unavailableсRetry-After: 2— запасную выдачу собрать не из чего: база данных недоступна, а ключ не проверялся последние минуты. Не повторяйте запрос в том же показе страницы — покажите свою ленту.429 rate_limited— превышен лимит 100 запросов в секунду на ключ (кратковременный всплеск допускается).- На любой ошибке, таймауте и ответе не
200показывайте свою запасную выдачу — например, хронологическую ленту. Доля запасной выдачи видна в кабинете, в «Метриках».
Ошибки полей запроса выдачи (422 validation_failed) приходят одним ответом, до 20 строк details: unknown_field, invalid_type, invalid_value, required, too_long, too_many, unknown_filter, invalid_user — см. Ошибки и лимиты.
Примеры на PHP и Python
<?php
/** Выдача ДАРА или null: при null покажите свою ленту. */
function dara_recs(string $method, array $body): ?array
{
$ch = curl_init('https://core.daratech.ru/api/v1/recommendations/' . $method);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('DARA_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT_MS => 200,
CURLOPT_TIMEOUT_MS => 700,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($response === false || $status !== 200) {
return null;
}
$data = json_decode($response, true);
return is_array($data) ? $data : null;
}
$user = ['anonymous_id' => 'a-7f3c2e'];
if ($userId !== null) {
$user['user_id'] = (string) $userId;
}
$feed = dara_recs('feed', ['user' => $user, 'limit' => 24, 'offset' => $offset]);
$next = dara_recs('similar', ['item' => 'v-1042', 'user' => $user, 'limit' => 8]);
$ids = $feed !== null ? array_column($feed['items'], 'id') : chronological_ids($offset, 24);
import os
import httpx
api = httpx.Client(
base_url="https://core.daratech.ru/api/v1",
headers={"Authorization": f"Bearer {os.environ['DARA_KEY']}"},
timeout=httpx.Timeout(0.7, connect=0.2),
)
def recs(method: str, body: dict) -> dict | None:
"""Выдача ДАРА или None: при None покажите свою ленту."""
try:
response = api.post(f"/recommendations/{method}", json=body)
return response.json() if response.status_code == 200 else None
except (httpx.HTTPError, ValueError): # сеть, таймаут, неразборчивый ответ
return None
user = {"user_id": "u-501", "anonymous_id": "a-7f3c2e"}
page1 = recs("feed", {"user": user, "limit": 24})
page2 = recs("feed", {"user": user, "limit": 24, "offset": 24}) if page1 and page1["has_more"] else None
cart = recs("similar", {"items": ["sku-3107", "sku-2240"], "user": user, "limit": 8})
search = recs("rerank", {"user": user, "items": ["v-5", "v-9", "v-12"]})