nuxt-error-tracker
| Install | |
|---|---|
npm install nuxt-error-tracker |
|
| Latest Version: | 0.1.22 |
| Vue: | 3 |
| License: | PolyForm-Shield-1.0.0 |
| Last Updated: | Aug 9, 2026 |
| Links: | npm |
nuxt-error-tracker
English · Українська
Легкий трекер frontend-помилок для Nuxt 3 / 4. Перехоплює неопрацьовані помилки, невдалі запити та ланцюжок дій користувача (breadcrumbs), після чого відправляє їх на ваш власний Observer ingest-endpoint. Працює лише на клієнті, батчами, і збудований так, щоб ніколи не ламати застосунок-хост — якщо його не налаштовано, він не робить нічого.
Ви даєте URL і публічний ключ; пакет робить перехоплення. Усе відправлене потрапляє під ваш проєкт у вашому Observer-дашборді, де ви самі переглядаєте, шукаєте та керуєте логами.
Зміст
- Як це працює (складові)
- Встановлення
- Отримати endpoint і ключ
- Налаштування
- Конфігурація через змінні середовища
- Опції
- Runtime-хелпери
- Що відправляється на API
- Формат передачі та типи даних
- Перегляд і контроль ваших логів
- Приватність
- Ліцензія
Як це працює (складові)
Складових три. Цей пакет — лише перша.
| Складова | Що це | За що відповідає |
|---|---|---|
Цей пакет (nuxt-error-tracker) |
Nuxt-модуль, який ви ставите у застосунок | Підключається до браузера, перехоплює помилки + breadcrumbs, батчить їх і POSTить на ваш endpoint. Працює лише на клієнті. |
Ваш ingest-endpoint (.../v1/ingest) |
Observer API, який ви хостите (або маєте доступ) | Автентифікує запит за публічним ключем + origin, валідує та rate-лімітує, дедуплікує помилки за fingerprint і зберігає. |
| Ваш дашборд | Консоль Observer | Де ви переглядаєте, шукаєте та керуєте логами — стек-трейси, occurrences, breadcrumb-ланцюжки, retention. |
Пакет ніколи не вирішує, куди йдуть дані — вирішуєте ви, вказавши
endpoint на свій хост. Дефолтного URL немає. Змініть хост — логи підуть за
ним. Це і є «bring your own backend»: той самий пакет працює проти localhost під
час розробки та проти вашого прод-Observer у релізі, лише зміною endpoint.
Усередині самого пакета:
module.ts— Nuxt-модуль. Читає ваші опції та реєструє плагін перехоплення лише колиenabled+endpoint+publicKeyприсутні всі. Немає будь-чого → плагін не додається, застосунок працює недоторканим. Також нормалізує опції (обрізаєmaxBatch ≤ 20,maxBreadcrumbs ≤ 50під серверні ліміти) і додає TypeScript-типи для хелперів.plugin.client.ts— власне рушій перехоплення (лише браузер). Слухає помилки, обгортаєfetch, патчитьconsole.error, пише breadcrumbs і керує чергою відправки.plugin.server.ts— маленька SSR-заглушка. Дає no-op$trackError/$addBreadcrumb, щоб виклик під час серверного рендеру ніколи не кидав помилку.ingest.codec.ts— саморобний protobuf-енкодер (без залежностей), що перетворює батч на бінарний формат, який очікує API.
Встановлення
npm i nuxt-error-tracker
# або: bun add nuxt-error-tracker
Отримати endpoint і ключ
Модулю потрібні рівно дві речі, щоб почати звітувати: ingest-endpoint (ваш URL) і публічний ключ (якому проєкту належать помилки). Обидва беруться з вашого Observer-дашборда.
- Відкрийте дашборд за адресою
https://<ваш-observer-хост>/dashboard. - Створіть акаунт — введіть email і пароль (мін. 8 символів), надішліть. Ви лишаєтесь залогіненим через захищений httpOnly-cookie.
- Натисніть New project, дайте назву (напр.
my-app) і за бажанням перелічіть origins, на яких працює ваш сайт (через кому, напр.https://my-app.com, http://localhost:3000). Порожньо = приймати будь-який origin. Це серверний allowlist — запити з інших origins відхиляються. - Проєкт тепер показує публічний ключ (
pk_…) і готовий сніпетnuxt.config. Використайте Copy key / Copy config. - Endpoint — це ваш хост +
/v1/ingest, тобтоhttps://<ваш-observer-хост>/v1/ingest.
Що насправді роблять ці два значення
endpoint— куди відправляти. Це ваш URL. Вказуйте на будь-який хост, де крутиться Observer API. Хостованого дефолту немає; ви завжди шлете на свій бекенд.publicKey— чий проєкт помилки. На кожному запиті API шукає проєкт за цим ключем (заголовокX-Public-Keyабо query?key=для beacon-шляху), потім застосовує allowlist origins і rate-ліміт цього проєкту. Це публічне значення — безпечно класти у клієнтські бандли. Воно дає лише запис (ingest) в один проєкт; воно не дає нікому читати ваші логи. Читання вимагає логіну в дашборд.
Origins важливі. Якщо ви задали allowlist, він мусить містити кожен origin, з якого віддається застосунок — прод-домени та
http://localhost:3000для локальної розробки — інакше запити браузера отримають401. Лишіть порожнім під час експериментів, звузьте для продакшену.
Після налаштування (нижче) і деплою перехоплені помилки з'являються під цим проєктом у дашборді. Відкрийте Logs на проєкті, щоб їх переглянути.
Налаштування
Додайте модуль і вкажіть йому ingest-endpoint з публічним ключем вашого проєкту:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-error-tracker'],
errorTracker: {
endpoint: 'https://<ваш-observer-хост>/v1/ingest',
publicKey: 'pk_xxxxxxxxxxxxxxxxxxxxxxxx',
},
})
Це мінімум. Усе решта має розумні дефолти.
Немає ключів? Не проблема
Якщо endpoint чи publicKey порожні (або enabled: false), плагін не
реєструється, і застосунок працює недоторканим. Тому модуль можна лишати
встановленим, підключаючи ключі по-середовищах — dev-збірки без ключа просто не
трекають. Ні падіння, ні шуму в консолі, ні мережевого виклику.
Конфігурація через змінні середовища
Кожну опцію можна задати зі змінних середовища замість хардкоду, за конвенцією
публічних env у Nuxt runtimeConfig:
NUXT_PUBLIC_ERROR_TRACKER_ENDPOINT=https://<ваш-observer-хост>/v1/ingest
NUXT_PUBLIC_ERROR_TRACKER_PUBLIC_KEY=pk_xxxxxxxxxxxxxxxxxxxxxxxx
NUXT_PUBLIC_ERROR_TRACKER_APP_VERSION=1.4.2
Підключіть їх у nuxt.config.ts:
export default defineNuxtConfig({
modules: ['nuxt-error-tracker'],
runtimeConfig: {
public: {
errorTracker: {
endpoint: process.env.NUXT_PUBLIC_ERROR_TRACKER_ENDPOINT,
publicKey: process.env.NUXT_PUBLIC_ERROR_TRACKER_PUBLIC_KEY,
appVersion: process.env.NUXT_PUBLIC_ERROR_TRACKER_APP_VERSION,
},
},
},
})
Це рекомендований спосіб націлити ту саму збірку на різний endpoint за середовищем (staging vs. production) без правки коду.
Опції
| Опція | Тип | Дефолт | Опис |
|---|---|---|---|
endpoint |
string |
'' |
Ingest URL (.../v1/ingest). Обовʼязково — ваш хост. |
publicKey |
string |
'' |
Публічний ключ вашого проєкту (pk_…). Обовʼязково. |
appVersion |
string |
'unknown' |
Тегує кожен батч релізом/версією для фільтрації. |
enabled |
boolean |
true |
Головний вимикач. false = повністю вимкнено, плагін не реєструється. |
captureFetch |
boolean |
true |
Обгортає fetch, щоб breadcrumbʼити запити і звітувати про збої / 5xx. |
captureFetchDetails |
boolean |
true |
Додає повну деталь запиту/відповіді (метод, статус, тайминг, заголовки, тіло запиту, тіло відповіді) до кожного fetch-breadcrumb. Чутливі заголовки редагуються, тіла обрізаються до 2 КБ. false — лишити fetch-крихти лише-повідомленням (не захоплювати payload / PII). |
captureConsole |
boolean |
true |
Патчить console.error, щоб ловити залоговані-але-не-кинуті помилки. |
captureInDev |
boolean |
false |
Реєструвати плагін і під nuxt dev. Вимкнено за замовчуванням: dev-сервер зазвичай успадковує прод-.env і слав би помилки в той самий проєкт, що й реальні користувачі. Вмикати лише проти тестового проєкту. |
captureInputs |
boolean |
false |
Записує значення полів форм як breadcrumbs (на change/blur). Чутливі поля маскуються. Opt-in — захоплює введені користувачем дані. |
flushDelay |
number |
2000 |
Debounce (мс) перед відправкою черги-батча. |
minFlushInterval |
number |
0 |
Мін. пауза (мс) між флашами — throttle частоти запитів під час шторму помилок. 0 = вимкнено. |
sampleRate |
number |
1 |
Частка (0..1) захоплених помилок, що реально шлються; решта дропається при capture. 0.3 ≈ 30%. Ріже обʼєм до серверного rate limit. |
maxPerMinute |
number |
0 |
Клієнтський ліміт помилок у чергу за rolling-хвилину (fixed window); понад — дроп. Дзеркалить серверний per-project rate limit. 0 = без ліміту. |
dedupeWindowMs |
number |
0 |
Схлопує повтори тієї самої помилки (однакові message + source) у межах N мс в один occurrence. Для клієнтських retry-циклів: повторний запит летить через мілісекунди, має той самий fingerprint і подвоює лічильник для одного видимого користувачу збою. 0 = вимкнено. |
maxPerSession |
number |
5 |
Макс. кількість occurrences тієї самої помилки за сесію. |
maxBatch |
number |
20 |
Макс. помилок на запит (обрізається серверним лімітом 20). |
maxBreadcrumbs |
number |
30 |
Breadcrumbs у ring buffer / на помилку (обрізається до 50). |
Runtime-хелпери
Плагін інʼєктить два хелпери для ручного використання:
const { $trackError, $addBreadcrumb } = useNuxtApp()
// Звітувати про опрацьовану помилку самому — опційний рівень серйозності
// ('fatal' | 'error' | 'warning' | 'info' | 'debug', дефолт 'error')
try {
await mayFail()
} catch (e) {
$trackError(e, 'warning')
}
// Додати власний breadcrumb у ланцюжок
$addBreadcrumb({
type: 'custom',
category: 'checkout',
message: 'user clicked pay',
level: 'info',
})
Обидва хелпери завжди викликаються. Реальне перехоплення — лише на клієнті; на
сервері (SSR — напр. верхньорівневий <script setup>) це безпечні no-opʼи, тож
виклик ніколи не кидає помилку.
$trackError і $addBreadcrumb повністю типізовані — модуль постачає
augmentation для NuxtApp і Vue ComponentCustomProperties, тож і
useNuxtApp(), і використання в шаблоні бачать їх як функції (без unknown /
TS18046). Ручний .d.ts не потрібен.
Що відправляється на API
Нічого не відправляється, доки не станеться помилка. Пакет тримає в памʼяті ring buffer breadcrumbs, поки користувач взаємодіє; при перехопленні помилки він знімає снапшот цього ланцюжка, ставить помилку в чергу і (після debounce) POSTить батч.
Батч має дві частини: meta (раз на батч, застосовується до всіх помилок у
ньому) і errors (масив перехоплених помилок).
meta (раз на батч)
| Поле | Тип | Джерело | Нотатки |
|---|---|---|---|
device |
object |
navigator / window |
userAgent, language, platform, screen (ШxВ), viewport (ШxВ), online (bool), memory (deviceMemory, ГБ або null), connection (effectiveType або null). Сервер обрізає JSON до 2 КБ. |
userId |
string | null |
cookie user_id |
Читається з cookie user_id, якщо є, інакше null. Пакет ніколи не вигадує id. Макс. 100 символів. |
appVersion |
string |
ваша опція appVersion |
Дефолт 'unknown'. Макс. 50 символів. |
errors[] (на кожну перехоплену помилку)
| Поле | Тип | Опис | Ліміт |
|---|---|---|---|
message |
string |
Повідомлення помилки. | ≤ 1000 симв. |
stack |
string |
Стек-трейс. | ≤ 8000 симв. |
source |
string |
Звідки: vue, window, promise, fetch чи console. |
≤ 20 симв. |
level |
string |
Серйозність: fatal | error | warning | info | debug. |
одне зі списку |
url |
string |
window.location.href на момент перехоплення. |
≤ 2000 симв. |
route |
string |
Nuxt-route fullPath. |
≤ 500 симв. |
occurredAt |
string |
ISO-8601 timestamp. | ISO-8601 |
breadcrumbs |
Breadcrumb[] |
Ланцюжок, що привів до помилки (нижче). | ≤ 50 елементів |
Кожен Breadcrumb:
| Поле | Тип | Опис | Ліміт |
|---|---|---|---|
type |
string |
click, input, navigation, fetch, console чи ваш кастомний тип. |
≤ 30 симв. |
category |
string |
напр. ui.click, ui.input, navigation, http, console. |
≤ 60 симв. |
message |
string |
Людиночитний рядок, напр. POST /api/pay → 500. |
≤ 500 симв. |
level |
string |
info | error | … |
≤ 20 симв. |
timestamp |
string |
ISO-8601. | ISO-8601 |
data |
object |
Опційний структурований payload (деталі fetch: метод, статус, тайминг, заголовки, тіла запиту/відповіді). | JSON |
Ліміти батча: щонайбільше 20 помилок на запит; клієнт також повертає в
чергу невдалі батчі (обмежено 200 у памʼяті) і дедуплікує ту саму помилку до
maxPerSession (5) occurrences за сесію, тож одна повторювана помилка не
затопить вашу квоту.
Формат передачі та типи даних
Payloadʼи кодуються у protobuf (proto3) і POSTяться як
application/x-protobuf. Енкодер саморобний і без залежностей — жодного
protobufjs, тож споживачам не потрібні ні Vite optimizeDeps, ні
CJS-interop-конфіг.
Схема (номери полів визначальні — вони мусять збігатися з декодером API):
message Breadcrumb {
string type = 1;
string category = 2;
string message = 3;
string level = 4;
string timestamp = 5;
string data = 6; // обʼєкт у вигляді JSON-рядка
}
message Error {
string message = 1;
string stack = 2;
string source = 3;
string url = 4;
string route = 5;
string userId = 6; // per-error override (цим клієнтом не використовується)
string appVersion = 7; // per-error override (цим клієнтом не використовується)
string device = 8; // per-error override (цим клієнтом не використовується)
string occurredAt = 9;
repeated Breadcrumb breadcrumbs = 10;
string level = 11;
}
message Meta { string device = 1; string userId = 2; string appVersion = 3; }
message Batch { Meta meta = 1; repeated Error errors = 2; }
device і breadcrumb data — обʼєкти, тож їдуть як JSON-рядки всередині
protobuf. Порожні рядки опускаються (дефолт proto3). Бінарне обрамлення лише
тримає мережеву панель охайною — це не шифрування; схема публічна, тож
будь-хто з нею може декодувати payload.
Як передається
- Звичайний шлях:
fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-protobuf', 'X-Public-Key': <ключ> }, body: <bytes>, keepalive: true }). - Шлях page-hide: черга примусово скидається через `navigator.sendBeacon(endpoint
- '?key=<ключ>', Blob)
— оскільки beacon не може ставити заголовки, ключ їде в query-параметрі?key=. Відкат доfetch(..., { keepalive: true }), якщоsendBeacon` недоступний чи відмовив.
- '?key=<ключ>', Blob)
API також приймає звичайний JSON на тому самому endpoint (та сама валідація), що зручно для скриптових тестових POSTів, але SDK завжди шле protobuf.
Перегляд і контроль ваших логів
Сенс власного endpoint: після відправки пакетом ви володієте даними і керуєте ними повністю зі свого дашборда — без сторонньої консолі.
- Перегляд — відкрийте Logs на проєкті, щоб побачити групи помилок, кожну
з повідомленням, лічильником, first/last seen, зачепленими routes і
стек-трейсом + breadcrumb-ланцюжком на кожну occurrence (включно з захопленими
fetch payload/response, коли
captureFetchDetailsувімкнено). - Дедуплікація — API групує occurrences за fingerprint (хеш нормалізованого повідомлення + верхні стек-фрейми), тож повторювана помилка — це один рядок із лічильником, а не тисячі дублікатів.
- Rate-ліміт і origins — кожен проєкт має власний per-minute rate-ліміт і allowlist origins. Звузьте origins, щоб відкидати сторонній трафік; самого ключа недостатньо, щоб дані зайшли з неперелічeного origin.
- Retention — occurrences видаляються після вікна retention (за замовчуванням 7 днів на сервері), тож сховище лишається обмеженим без жодних дій з вашого боку.
Оскільки ключ — лише на запис, а читання під логіном, публікація ключа у клієнтському бандлі не відкриває жодних збережених даних.
Приватність
Click-breadcrumbs записують елемент (tag / id / class / короткий текст / data-*
атрибути) — ніколи значення полів. Нічого не захоплюється, доки не станеться
помилка; breadcrumbs живуть лише в памʼяті і їдуть прикріпленими до помилки.
Значення полів захоплюються лише коли ви явно вмикаєте captureInputs: true.
Навіть тоді чутливі поля маскуються (зберігаються як [masked, N chars], ніколи
у відкритому вигляді): будь-який type="password", а також поля, чиї name /
id / autocomplete збігаються з pass, secret, token, otp, cvv,
card, iban, ssn, pin, auth тощо. Нечутливі значення обрізаються до 100
символів.
Захоплення деталей fetch (captureFetchDetails, увімкнено за замовчуванням)
редагує чутливі заголовки запиту/відповіді (authorization, cookie,
x-api-key, CSRF-токени, …) і обрізає тіла до 2 КБ. Поставте false, якщо не
хочете, щоб payloadʼи запитів чи тіла відповідей взагалі покидали браузер.
Ліцензія
PolyForm Shield 1.0.0 — source-available. Безкоштовно ставити й
використовувати для будь-якої мети, окрім створення продукту, що конкурує з
цим ПЗ або з тим, що ліцензіар надає з його допомогою. Не можна форкнути у
конкурента. Повні умови у LICENSE; авторські права лишаються за
автором.
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.1.22 | ^3.0 | PolyForm-Shield-1.0.0 | |
| 0.1.20 | ^3.0 | PolyForm-Shield-1.0.0 | |
| 0.1.19 | ^3.0 | PolyForm-Shield-1.0.0 | |
| 0.1.18 | ^3.0 | PolyForm-Shield-1.0.0 | |
| 0.1.17 | ^3.0 | ||
| 0.1.16 | ^3.0 | ||
| 0.1.15 | ^3.0 | ||
| 0.1.14 | ^3.0 | ||
| 0.1.13 | ^3.0 | ||
| 0.1.12 | ^3.0 | ||
| 0.1.10 | ^3.0 | ||
| 0.1.9 | ^3.0 | ||
| 0.1.8 | ^3.0 | ||
| 0.1.7 | ^3.0 | ||
| 0.1.6 | ^3.0 | ||
| 0.1.5 | ^3.0 | ||
| 0.1.4 | ^3.0 | ||
| 0.1.3 | ^3.0 |