Главная/Документация/Кастом-метрики
Контракт кастом-метрик
Кастом-метрики позволяют сервису вашего расширения слать любые важные для него числа (конверсии, выручку, здоровье бэкенда, воронки) в ту же панель, которая уже отслеживает установки и здоровье Chrome Web Store. Контракт metadata-driven и dual-surface: каждая метрика объявляет, где и как она появляется и на дашборде, и в Telegram-статусе, поэтому панель остаётся generic-рендерером без продуктового кода.
1. Как это работает (dual-surface)
Ваш сервис отдаёт один эндпоинт метрик. Ext Ops Panel – клиент: он пуллит этот эндпоинт (никогда наоборот) и рендерит ответ. Ответ управляет двумя поверхностями сразу:
- Табы дашборда в Detail-виде расширения: табы, секции и типы рендера по метрикам.
- Telegram-статус: логические строки, собранные из тех же метрик, с фильтрацией и форматированием по метрике.
Панель мержит ваши метрики с базовыми first-party метриками (установки / удаления / возвраты / фидбек / Chrome Web Store / здоровье), которые живут в зарезервированном табе base и строке Telegram.
2. Эндпоинт и авторизация
Панель вызывает ваш эндпоинт методом GET и ждёт payload v2 в ответе 200. Два режима пула используют одинаковую структуру:
- On-demand: срабатывает, когда пользователь открывает Detail. Лимит – не чаще 1 запроса в минуту на источник, на всех тарифах включая Free.
- Monitoring: по расписанию (только Trial/Paid), компонует Telegram-статус и edge-алерты.
Авторизация – одна из none, bearer или api_key_header. Секреты хранятся зашифрованными at rest на бэкенде панели и никогда не передаются дашборд-расширению. Если пул падает, панель деградирует gracefully (last snapshot или скрыто), не ломая базовые метрики.
3. Структура payload
Верхнеуровневый payload несёт раскладку (табы, секции, строки Telegram) и массив метрик.
| Поле | Тип | Заметки |
|---|---|---|
schema_version | string | Обязательно. Должно быть "2.0". |
generated_at | string (date-time) | Когда payload собран (свежесть / idle-детект). |
tabs | Tab[] | Табы дашборда. См. раздел 4. |
sections | Section[] | Группы метрик внутри таба (tab, id, title, order). |
telegram | TelegramMeta | Шаблон header + lines[]. См. раздел 7. |
metrics | Metric[] | Сами метрики. См. разделы 5 и 6. |
4. Табы и иконки табов
Tab – это { id, title, order, icon? }. Зарезервированный таб
base – наш
(icon="layout-dashboard"); ваш сервис добавляет остальные. Когда
табов много, активный таб показывает иконку + название, а остальные схлопнуты
до иконки (название остаётся в tooltip и aria-label).
Значение icon – одно из двух:
- Имя иконки Lucide в kebab-case ASCII (матчит
^[a-z][a-z0-9-]*$), напримерtrending-up. Корректное по форме, но неподдержанное имя деградирует к дефолтной иконке (square), так что бар не ломается. - Один эмодзи, например 💰 или 🚀, рендерится как текст.
Панель везёт curated-подмножество из 37 имён Lucide (держим MV3-бандл лёгким):
- layout-dashboard
- activity
- gauge
- layers
- plug
- dollar-sign
- banknote
- wallet
- credit-card
- receipt
- bar-chart-3
- line-chart
- pie-chart
- trending-up
- trending-down
- users
- user
- alert-triangle
- bell
- clock
- git-branch
- package
- box
- database
- server
- cpu
- zap
- globe
- puzzle
- funnel
- filter
- square
- circle
- hash
- percent
- tag
- flag
5. Метрика: значение + два блока размещения
Метрика несёт типизированное значение плюс два независимых блока:
dashboard (где и как в расширении) и telegram (где и
как в сообщении). Любой можно опустить или скрыть через show:false,
так что метрика может жить только на одной поверхности.
| Поле | Заметки |
|---|---|
id | Стабильный id метрики, уникальный в payload. |
kind | Тип данных (раздел 5.1). Определяет, какие поля значения применяются. |
label | Каноническое человекочитаемое имя. |
value и поля по kind | Поля payload зависят от kind (раздел 5.1). |
severity | Одно из ok, info, warn, crit (маппится в цвет / эмодзи). |
shareable | Необяз. boolean, default true. При false метрика owner-only: на расшаренном read-only проекте отсекается на сервере и не доходит до наблюдателя / public (для финансовых метрик). Управляет доступом, не размещением. |
dashboard | { show, tab, section, order, name, render, options } (раздел 5.2). |
telegram | { show, line, pos, format, sep, when } (разделы 6 и 8). |
5.1. Kinds (тип данных + payload)
Kinds – открытое множество: неизвестный kind рендерер игнорирует (forward-compat).
| kind | Поля payload | Пример использования |
|---|---|---|
number | value (+ опц. delta, unit) | счётчики установок / фидбека |
delta | value, delta (рендер 1200 (+72)) | total (+today) |
percent | value (0 до 100) | engine success rate |
duration | seconds или minutes | p50/p95/avg, свежесть |
bytes | bytes или kb | размер вывода (~522KB) |
rating | value, count | 5.0★ (1) |
money | value, currency, опц. delta | MRR, расход |
status | state + severity | health-светофор |
series | points:[{date,count}], опц. мульти series:[{name,points}] | daily installs, active users |
intraday | series:[{name,intraday:[{minute,value}]}], опц. step_min (по умолчанию 15), tz | сегодня по 15-минутным бакетам |
hour_histogram | { weekdays:[...], start, end, tz } | конверсии по часам |
funnel | steps:[{key,label,value}] | pricing до checkout |
breakdown | items:[{label,value,unit?,sub?/money?}] | подписки по плану, by engine, by surface |
list | items:[{text,count?,severity?}] | последние ошибки |
text | value (string) | произвольный текст |
5.2. Render (как показать на дашборде)
dashboard.render выбирает визуал (обычно совпадает с kind,
но может отличаться, напр. показать percent как badge).
Тоже открытое множество.
| render | Вид | Опции (dashboard.options) |
|---|---|---|
kpi | Карточка: имя + крупное значение + дельта | tone |
badge | Статус-пилюля / пиктограмма по severity | – |
chart | Линейный график (Month/Lifetime, rolling-7 avg, hover) | series, defaultMode |
intraday | Сегодня по бакетам (96 за UTC-сутки): стек-бары или сглаженные линии, ось времени HH:MM, hover-ридаут по всем сериям | mode (bars | lines, по умолчанию lines) |
hour_histogram | Почасовые бары, группировка Weekdays / Weekend / By day of week | series |
funnel | Ступени с конверсией между ними | – |
breakdown | Горизонтальные категорийные бары со значением + долей от суммы | items |
table | Таблица (напр. фидбек) | columns |
text | Абзац / inline | – |
status | Состояние-светофор по severity | – |
list | Список элементов с опц. count / severity | – |
intraday vs chart. Ось chart –
дневная (points[].date = YYYY-MM-DD), а режим Month
режет её до последних 30 точек: 96 внутридневных бакетов туда не помещаются.
intraday – это наш первопартийный Today-график, вынесенный в контракт: та
же договорённость, где minute – минуты от начала UTC-суток
(0, 15, …, 1425), но серии и данные объявляет источник. Присылайте только непустые
бакеты – остальное уплотняет панель.
Пустой бакет – это null, а не 0. Для среднего
(например, среднее время конвертации) ноль был бы неправдой, поэтому линия
рвётся, а не падает в пол. Пропущенный бакет и value: null
эквивалентны: линия разрывается, бара нет, в ридауте «–».
6. Палитрой владеет панель
Цвета графиков и серий назначает панель из бренд-токенов, а не
источник. options.series[] несёт только идентичность
({key,label,order}); поле color в payload – advisory и
игнорируется. Семантические ключи маппятся на фикс-токены
(paid в accent, free в приглушённый нейтрал,
failed/error в danger,
ready/success в success); прочие ключи берут
категориальную бренд-палитру позиционно. Контраст остаётся не ниже 4.5:1 в обеих
темах. Это защищает бренд от произвольного внешнего hex.
7. Шаблоны Telegram
telegram.header – заголовок сообщения;
telegram.lines[] – логические строки
({ id, order, prefix, when }). Композер собирает все метрики с
данной telegram.line, фильтрует по when, сортирует по
pos, рендерит каждую по шаблону format и склеивает
через sep метрики. Сначала печатается prefix строки.
Всё – plain text.
| Плейсхолдер | Выход |
|---|---|
{value} | По kind (number 1,200; percent 99%) |
{value:k} | 1.2k / 3.0M (компактно) |
{delta:+} | +72 / -3 |
{value:pct} | 99% |
{seconds:dur} | 28s / 5m 47s |
{minutes:age} | 45m / 2h 30m / never |
{bytes:size} | ~522KB / 1.4MB |
{value}★ ({count}) | 5.0★ (1) |
{sev} | Эмодзи по severity: 🟢 ok, 🟡 warn, 🔴 crit, ⚪ idle |
{trend} | ↗ / ↘ (±5pp к 7d) |
8. Условия показа (when)
when управляет тем, показывается ли поле метрики (или целая строка
Telegram). Значения:
| when | Показывает поле |
|---|---|
always | Всегда (по умолчанию). |
nonzero | Только когда значение не 0 / не пусто. |
severity>=warn | Только когда severity warn или crit. |
changed | Только когда изменилось с прошлого снапшота. |
Неизвестные значения when ведут себя как always (forward-compat).
9. Пример payload
{
"schema_version": "2.0",
"generated_at": "2026-07-02T23:17:30Z",
"tabs": [
{ "id": "conv", "title": "Conversions", "order": 1, "icon": "trending-up" }
],
"sections": [
{ "tab": "conv", "id": "by_hour", "title": "By hour", "order": 0 }
],
"telegram": {
"header": "{name} • {cws.users} • {cws.rating}★ ({cws.rating_count})",
"lines": [
{ "id": "base", "order": 0 },
{ "id": "conv", "order": 1, "prefix": "{sev} Conv " }
]
},
"metrics": [
{
"id": "conv_today",
"kind": "number",
"label": "Conversions today",
"value": 254,
"severity": "ok",
"shareable": true,
"dashboard": {
"show": true,
"tab": "conv", "section": "by_hour", "order": 10,
"name": "Today", "render": "kpi", "options": {}
},
"telegram": {
"show": true,
"line": "conv", "pos": 20,
"format": "today {value}", "sep": " • ", "when": "always"
}
}
]
}10. Машиночитаемый контракт
Формальное, импортируемое описание этого эндпоинта – файл OpenAPI 3.1. Он несёт ту же версию контракта (2.0.0) и является единственным каноническим машинным артефактом, общим для всех языков.