Ext Ops Panel
Подключить

Главная/Документация/Кастом-метрики

Контракт кастом-метрик

Версия контракта 2.0.0 · schema_version payload 2.0

Кастом-метрики позволяют сервису вашего расширения слать любые важные для него числа (конверсии, выручку, здоровье бэкенда, воронки) в ту же панель, которая уже отслеживает установки и здоровье Chrome Web Store. Контракт metadata-driven и dual-surface: каждая метрика объявляет, где и как она появляется и на дашборде, и в Telegram-статусе, поэтому панель остаётся generic-рендерером без продуктового кода.

↓ Скачать OpenAPI 3.1 (YAML) /custom-metrics-openapi.yaml · info.version 2.0.0

1. Как это работает (dual-surface)

Ваш сервис отдаёт один эндпоинт метрик. Ext Ops Panel – клиент: он пуллит этот эндпоинт (никогда наоборот) и рендерит ответ. Ответ управляет двумя поверхностями сразу:

Панель мержит ваши метрики с базовыми first-party метриками (установки / удаления / возвраты / фидбек / Chrome Web Store / здоровье), которые живут в зарезервированном табе base и строке Telegram.

2. Эндпоинт и авторизация

Панель вызывает ваш эндпоинт методом GET и ждёт payload v2 в ответе 200. Два режима пула используют одинаковую структуру:

Авторизация – одна из none, bearer или api_key_header. Секреты хранятся зашифрованными at rest на бэкенде панели и никогда не передаются дашборд-расширению. Если пул падает, панель деградирует gracefully (last snapshot или скрыто), не ломая базовые метрики.

3. Структура payload

Верхнеуровневый payload несёт раскладку (табы, секции, строки Telegram) и массив метрик.

ПолеТипЗаметки
schema_versionstringОбязательно. Должно быть "2.0".
generated_atstring (date-time)Когда payload собран (свежесть / idle-детект).
tabsTab[]Табы дашборда. См. раздел 4.
sectionsSection[]Группы метрик внутри таба (tab, id, title, order).
telegramTelegramMetaШаблон header + lines[]. См. раздел 7.
metricsMetric[]Сами метрики. См. разделы 5 и 6.

4. Табы и иконки табов

Tab – это { id, title, order, icon? }. Зарезервированный таб base – наш (icon="layout-dashboard"); ваш сервис добавляет остальные. Когда табов много, активный таб показывает иконку + название, а остальные схлопнуты до иконки (название остаётся в tooltip и aria-label).

Значение icon – одно из двух:

Панель везёт curated-подмножество из 37 имён Lucide (держим MV3-бандл лёгким):

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Пример использования
numbervalue (+ опц. delta, unit)счётчики установок / фидбека
deltavalue, delta (рендер 1200 (+72))total (+today)
percentvalue (0 до 100)engine success rate
durationseconds или minutesp50/p95/avg, свежесть
bytesbytes или kbразмер вывода (~522KB)
ratingvalue, count5.0★ (1)
moneyvalue, currency, опц. deltaMRR, расход
statusstate + severityhealth-светофор
seriespoints:[{date,count}], опц. мульти series:[{name,points}]daily installs, active users
intradayseries:[{name,intraday:[{minute,value}]}], опц. step_min (по умолчанию 15), tzсегодня по 15-минутным бакетам
hour_histogram{ weekdays:[...], start, end, tz }конверсии по часам
funnelsteps:[{key,label,value}]pricing до checkout
breakdownitems:[{label,value,unit?,sub?/money?}]подписки по плану, by engine, by surface
listitems:[{text,count?,severity?}]последние ошибки
textvalue (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 weekseries
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"
      }
    }
  ]
}
Поддерживается только нативный v2. Ваш сервис возвращает метрики плюс готовую раскладку по этому контракту; коннекторов легаси-форматов нет. Kinds и типы рендера – из объявленных множеств выше; неизвестные игнорируются, так что новый источник никогда не ломает старую сборку панели.

10. Машиночитаемый контракт

Формальное, импортируемое описание этого эндпоинта – файл OpenAPI 3.1. Он несёт ту же версию контракта (2.0.0) и является единственным каноническим машинным артефактом, общим для всех языков.

↓ Скачать OpenAPI 3.1 (YAML) /custom-metrics-openapi.yaml