API: посетители
Атрибуты посетителей без персональных данных — POST /visitors/attributes, GET /visitors/{visitor_id}, GET /network — и данные о посетителях с сервера POST /users. Примеры на curl, PHP и Python.
Общие правила — ключ, формат, идентификаторы, коды ошибок — и справочник всех методов и схем из описания OpenAPI находятся в разделе API.
Атрибуты посетителей
POST /visitors/attributes возвращает атрибуты посетителей вашего сайта: пол, возрастную группу, географию, детей, компанию, интересы, категории покупок и параметры посетителя. Персональных данных, точного возраста и года рождения в ответе нет.
curl -X POST https://analytics.daratech.ru/api/v1/visitors/attributes \
-H "Authorization: Bearer $DARA_ANALYTICS_KEY" \
-H "Content-Type: application/json" \
-d '{
"visitors": [
{"ref": "u-17", "user_id": "u-17"},
{"ref": "anon-1", "visitor_id": "0b7e6f8a-3c2d-4e5f-9a1b-2c3d4e5f6a7b"}
]
}'
- В одном запросе — до 100 посетителей. В каждом элементе нужен хотя бы один идентификатор:
user_id,visitor_idилиfingerprint_uuid. ref— ваша метка до 64 символов, возвращается как есть. По ней удобно сопоставлять ответы с запросами.fingerprint_uuidучитывается, только если к сайту подключён DARA Fingerprint.- Посетитель ищется по порядку:
user_id→visitor_id→fingerprint_uuid. Используется первый найденный на сайте. - Результаты идут в том же порядке, что элементы запроса.
- Ошибка формы любого элемента — нет идентификатора,
refдлиннее 64 символов,user_idдлиннее 191, неверный UUID, больше 100 элементов — отклоняет весь запрос ответом422с кодомvalidation_failed; вdetails— поле видаvisitors[3].visitor_id. - Метод только читает: он не записывает посетителей и не открывает данных сети.
Ответ 200:
{"results": [{
"ref": "u-17", "found": true,
"attributes": {
"gender": {"value": "female", "confidence": 0.99, "source": "network"},
"age_group": {"value": "25_34", "confidence": 0.95, "source": "own"},
"geo": {"country": "RU", "region": "Татарстан", "city": "Казань", "method": "ip", "source": "own"},
"children": {"value": [{"age_group": "3_6"}], "source": "network"},
"company": {"type": "legal", "industry": "Оптовая и розничная торговля", "region": "Москва", "source": "network"},
"interests": [{"topic_id": 1204, "path": "Семья и дети > Беременность", "share": 0.31, "sensitive": true, "source": "network"}],
"purchases": [{"category_id": 537, "path": "Детские товары > Подгузники", "segment": "mid", "source": "network"}],
"params": {"plan": "gold"}
}}]}
source— откуда значение:own— по наблюдениям ваших сайтов,network— из сети ДАРА. Своё значение важнее сетевого: сетевое приходит, только если своего нет.confidence— уверенность от 0 до 1. Уage_groupуверенность бываетnull.geoприходит со всеми ключами: неизвестная часть —null.geo.method—ip, если место определено по IP-адресу визитов, иform, если по формам и данным сайтов. Регион и город — названиями, не длиннее 100 символов.company— тип, отрасль (раздел ОКВЭД 2) и регион компании. ИНН и название компании в ответ не входят; уindividualотрасли и региона нет.interests— до 20 тем, самые заметные первыми.purchases— категории покупок за 180 дней;segment—null, если для категории сегмент не считается.sensitive— интерес относится к чувствительной теме.params— параметры посетителя в том виде, в каком их видят отчёты «Параметры посетителя»: вложенные объекты разворачиваются в ключи через точку, значения приходят строками. Например,{"company": {"size": 50}}приходит как{"company.size": "50"}.- Неизвестный посетитель —
{"ref": "anon-1", "found": false}.refбез значения в ответ не попадает. - Атрибут без значения в ответ не попадает.
Коды значений
| Поле | Значения |
|---|---|
age_group |
lt14, 14_17, 18_24, 25_34, 35_44, 45_54, 55_64, 65p |
children[].age_group |
0_2, 3_6, 7_10, 11_13, 14_17 |
purchases[].segment |
low — эконом, mid — средний, high — премиум |
company.type |
legal — юрлицо, individual — ИП или физлицо |
gender.value |
male, female |
Когда приходят сетевые значения
- Сайт — участник сети, и хиты с тегом приходили за последние 7 дней. Иначе в ответе только значения с
source: own. - Через API без установленного тега данные сети не выдаются.
- Если посетитель связан с человеком через email или телефон, сетевые значения открываются после окончания визита, в котором ключ ввели, и в пределах суточных лимитов. Посетитель, которому открытие не досталось, приходит без сетевых значений.
- Интересы и категории покупок берутся списком целиком: есть хотя бы один свой интерес — сетевых интересов в ответе нет.
- Пользователь сайта, связанный с email через
POST /users, получает сетевые значения, только если он связан с посетителем сайта, у которого есть хиты не от робота.
Правила подробно — в разделе Сеть ДАРА.
Кеш и проверка ключа
- Ответ кешируется на 60 секунд по сайту и идентификатору: частые повторы одного и того же посетителя не дают свежих данных. Кешируются только найденные посетители —
found: falseпри повторе проверяется заново. - Кеш сбрасывается сам, когда меняются настройки сети или участие сайта в сети. Проверка ключа и лимит запросов действуют и для ответов из кеша.
- Чтобы проверить ключ, достаточно запроса со случайным UUID в
visitor_id: ответ200— ключ действует,401— ключ неверен или отозван,403— сайт заблокирован.
Один посетитель
GET /visitors/{visitor_id} возвращает то же для одного посетителя и дополнительно поля first_visit_at, last_visit_at и visits — первый и последний визит и число визитов на этот сайт. Посетитель ищется только по visitor_id.
curl https://analytics.daratech.ru/api/v1/visitors/0b7e6f8a-3c2d-4e5f-9a1b-2c3d4e5f6a7b \
-H "Authorization: Bearer $DARA_ANALYTICS_KEY"
Ответ 200 — без обёртки results и без ref:
{"found": true,
"attributes": {
"gender": {"value": "female", "confidence": 0.99, "source": "network"},
"age_group": {"value": "25_34", "confidence": 0.95, "source": "own"},
"geo": {"country": "RU", "region": "Татарстан", "city": "Казань", "method": "ip", "source": "own"},
"children": {"value": [{"age_group": "3_6"}], "source": "network"},
"company": {"type": "legal", "industry": "Оптовая и розничная торговля", "region": "Москва", "source": "network"},
"interests": [{"topic_id": 1204, "path": "Семья и дети > Беременность", "share": 0.31, "sensitive": true, "source": "network"}],
"purchases": [{"category_id": 537, "path": "Детские товары > Подгузники", "segment": "mid", "source": "network"}],
"params": {"plan": "gold"}
},
"first_visit_at": "2026-03-02T09:14:05.120Z",
"last_visit_at": "2026-09-14T18:40:11.905Z",
"visits": 17}
- Неизвестный посетитель — тоже
200:{"found": false}. visitor_idне UUID —422с кодомvalidation_failed.first_visit_atиlast_visit_at—null, если визитов за время хранения данных нет.
Настройки сети
GET /network отдаёт настройки сети, которые нужны потребителям атрибутов:
curl https://analytics.daratech.ru/api/v1/network \
-H "Authorization: Bearer $DARA_ANALYTICS_KEY"
{"share_sensitive": true, "settings_version": 12}
share_sensitive: false— передача чувствительных тем между клиентами выключена: такие темы убираются из сетевых интересов в течение 10 минут. Если вы храните атрибуты у себя, не используйте сетевые интересы сsensitive: true.settings_versionрастёт при каждом изменении настроек сети. Запрашивайте метод раз в час.
Данные о посетителях
POST /users передаёт то, что ваш сайт знает о посетителях. Поля и правила — в разделе Данные о посетителях.
curl -X POST https://analytics.daratech.ru/api/v1/users \
-H "Authorization: Bearer $DARA_ANALYTICS_KEY" \
-H "Content-Type: application/json" \
-d '{
"users": [
{"user_id": "u-501", "visitor_id": "0b7e6f8a-3c2d-4e5f-9a1b-2c3d4e5f6a7b", "email": "user@example.com", "gender": "female", "birth_year": 1991, "city": "Казань", "children": [{"birth_year": 2019}], "interests": ["Путешествия"], "params": {"plan": "gold"}},
{"user_id": "u-502", "phone": "+79000000000", "age": 34},
{"user_id": "u-503", "city": null}
]
}'
Ответ 202 Accepted:
{"results": [{"index": 0, "ok": true}, {"index": 1, "ok": true}, {"index": 2, "ok": true}]}
- В одном запросе — до 500 записей, в каждой —
visitor_idилиuser_id. - Переданные поля заменяются,
nullочищает поле, непереданные не меняются. - Повтор записи безопасен: поля заменяются теми же значениями. Пачку после сетевой ошибки,
429или5xxможно отправить ещё раз.interests— сигнал: каждая присланная строка снова усиливает свои темы, поэтому интересы передавайте, когда они изменились. - Запись, в
paramsкоторой есть ключ с персональными данными (email,phone,name,first_name,last_name,middle_name,address,birth_date,passportна любой глубине, без учёта регистра), получает"ok": falseи ошибку с кодомpii_not_allowed. Поляemailиphoneсамой записи — не ошибка. Других кодов отказа записи нет. - Ошибка формы любой записи отклоняет весь запрос ответом
422с кодомvalidation_failed. - Если приём временно недоступен, ответ —
503с кодомunavailableи заголовкомRetry-After: ни одна запись не сохранена, пачку нужно отправить ещё раз. nullочищает поле: отменяет то, что ваш сайт передавал черезPOST /usersпо этому полю. Подробнее — в разделе Данные о посетителях.
Лимиты
| Методы | Лимит на ключ |
|---|---|
/visitors/*, /network |
50 запросов в секунду на все три метода вместе |
/users |
20 запросов в секунду — общий лимит с /conversions и /orders |
Сверх лимита — ответ 429 с кодом rate_limited и заголовком Retry-After. Ответ из кеша тоже расходует лимит. Все пределы — в разделе Ошибки и лимиты.
Примеры на PHP
Функция dara_analytics() та же, что в разделе API.
<?php
function dara_analytics(string $method, string $path, ?array $body = null): array
{
$ch = curl_init('https://analytics.daratech.ru/api/v1' . $path);
$options = [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DARA_ANALYTICS_KEY'),
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_TIMEOUT => 30,
];
if ($body !== null) {
$options[CURLOPT_POSTFIELDS] = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
}
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($response === false || $status >= 400) {
throw new RuntimeException('ДАРА АНАЛИТИКА: HTTP ' . $status . ' ' . ($response ?: curl_error($ch)));
}
return json_decode($response, true, 512, JSON_THROW_ON_ERROR);
}
$attributes = dara_analytics('POST', '/visitors/attributes', ['visitors' => [
['ref' => 'u-17', 'user_id' => 'u-17'],
]]);
foreach ($attributes['results'] as $visitor) {
if (!$visitor['found']) {
continue;
}
$gender = $visitor['attributes']['gender']['value'] ?? 'не определён';
$ageGroup = $visitor['attributes']['age_group']['value'] ?? 'не определена';
echo $visitor['ref'], ': ', $gender, ', ', $ageGroup, "\n";
}
$network = dara_analytics('GET', '/network');
$shareSensitive = $network['share_sensitive'];
dara_analytics('POST', '/users', ['users' => [
['user_id' => 'u-501', 'email' => 'user@example.com', 'gender' => 'female', 'birth_year' => 1991],
]]);
Примеры на Python
import os
import httpx
api = httpx.Client(
base_url="https://analytics.daratech.ru/api/v1",
headers={"Authorization": f"Bearer {os.environ['DARA_ANALYTICS_KEY']}"},
timeout=30,
)
response = api.post("/visitors/attributes", json={"visitors": [
{"ref": "u-17", "user_id": "u-17"},
]})
response.raise_for_status()
for visitor in response.json()["results"]:
if not visitor["found"]:
continue
attributes = visitor["attributes"]
gender = attributes.get("gender", {}).get("value", "не определён")
age_group = attributes.get("age_group", {}).get("value", "не определена")
print(visitor["ref"], gender, age_group)
network = api.get("/network")
network.raise_for_status()
share_sensitive = network.json()["share_sensitive"]
api.post("/users", json={"users": [
{"user_id": "u-501", "email": "user@example.com", "gender": "female", "birth_year": 1991},
]}).raise_for_status()