Пиксель
Пиксель slimTDS — это лёгкий JavaScript-сниппет, который идентифицирует посетителей на внешних лендингах, записывает события страниц и связывает эти события с кликами, прошедшими через TDS. Он построен на основе FingerprintJS Community Edition.
![]()
Что такое пиксель
Заголовок раздела «Что такое пиксель»GET /p.js отдаёт скомпилированный скрипт пикселя (артефакт сборки Bun по адресу public/p.js). При загрузке скрипт автоматически генерирует FingerprintJS CE visitor ID и отправляет событие pageview на /p/event. Скрипт отдаётся с 5-минутным публичным кэшем (Cache-Control: public, max-age=300, stale-while-revalidate=60) и стандартной обработкой 304 на основе ETag, поэтому повторные загрузки быстрые.
Встраивание пикселя
Заголовок раздела «Встраивание пикселя»У каждой кампании есть страница пикселя по адресу /admin/campaigns/{cid}/pixel. Там показан сниппет для встраивания и кнопка копирования. Форма сниппета такая:
<script async src="https://your-domain.com/p.js?c=CAMPAIGN_SLUG"></script>Разместите тег в <head> или <body> каждого лендинга. Параметр запроса ?c= — это slug кампании; он обязателен и привязывает события к нужной кампании.
Кастомные события
Заголовок раздела «Кастомные события»После инициализации скрипта становится доступна функция window.slimTDS.track() для кастомных событий. На странице пикселя показан такой пример:
window.slimTDS && slimTDS.track('purchase', { amount: 99, sku: 'X1' })Первый аргумент — имя события; второй — произвольный объект свойств, который будет сохранён как есть в JSONB-колонке props таблицы stats.pixel_events.
Запись сессий
Заголовок раздела «Запись сессий»Помимо событий, пиксель записывает визит с помощью rrweb и стримит запись на POST /p/rec чанками. В админке из них собираются просматриваемые реплеи — см. Реплеи сессий.
Отправка событий
Заголовок раздела «Отправка событий»События принимаются на POST /p/event. Тело может быть JSON (Content-Type: application/json) или form-encoded. Принимаемые поля:
| Поле | Тип | Примечания |
|---|---|---|
c | string | Slug кампании — обязательно |
event | string | Имя события (по умолчанию: pageview) |
fp | string | visitorId FingerprintJS CE |
url | string | URL текущей страницы |
ref | string | URL реферера |
ua | string | User-Agent (перекрывает заголовок, если задан) |
lang | string | Язык браузера |
tz | string | Строка таймзоны |
sw | int | Ширина экрана |
sh | int | Высота экрана |
t | int | Клиентский Unix-таймстамп (информационно) |
props | object | Произвольные кастомные свойства |
Ответы: 400, если c отсутствует; 404, если slug кампании неизвестен; 204 при успехе. Заголовок Set-Cookie: vu=… добавляется, когда запрос принадлежит новому посетителю.
/p/event рассчитан на вызовы с любого внешнего домена лендинга. Поведение CORS:
- OPTIONS-preflight на
/p/eventвозвращает204с разрешающими заголовками. - Для фактических
POST-запросов ответ возвращает заголовокOriginзапроса обратно вAccess-Control-Allow-Origin(а не*), чтобы ответ был валиден, когда браузер отправляет учётные данные — это необходимо, потому чтоnavigator.sendBeaconс типизированным payload-омBlobинициирует запрос с credentials. - Когда заголовка
Originнет, используетсяAccess-Control-Allow-Origin: *. Access-Control-Allow-Credentials: trueдобавляется при наличииOrigin.Access-Control-Max-Age: 86400(24 часа) сокращает число preflight-обменов.- Разрешённые методы:
POST, OPTIONS. Разрешённые заголовки:Content-Type.
Сам скрипт (GET /p.js) тоже отдаётся с Access-Control-Allow-Origin: *.
Куда попадают события
Заголовок раздела «Куда попадают события»Обработчик запроса записывает строку с сырым payload-ом в stats.pixel_events_inbox — UNLOGGED промежуточную таблицу — и сразу возвращает ответ. В пути запроса не происходит ни GeoIP-поиска, ни разбора UA.
Cron-команда inbox:flush (расписание: * * * * *, каждую минуту) запускает цикл внутри одного процесса примерно на 55 секунд. На каждой итерации она читает до 500 строк из inbox, обогащает каждую данными GeoIP (MaxMind GeoLite2) и определением устройства/ОС/браузера, выполняет обнаружение ботов, затем вставляет в партиционированную таблицу stats.pixel_events и удаляет обработанные строки inbox. Поскольку команда повторно опрашивает каждые 5 секунд, когда inbox пуст, события обычно появляются в админке в течение 5–6 секунд после поступления.
Как побочный эффект обработки очереди, если событие пикселя несёт FingerprintJS visitorId, а у посетителя был недавний клик, залогированный до того, как inbox был обработан, inbox:flush дозаписывает fp_js в эти строки кликов, чтобы связать два идентификатора посетителя задним числом.