Skip to content

Error reporting

Reporting adapters

Each adapter is its own exports entry point, so an adapter you don't import never reaches your bundle.

ts
import { createConsoleReporter } from 'vue-error-boundary-kit/adapters/console'
import { createHttpReporter } from 'vue-error-boundary-kit/adapters/http'
import { createSentryReporter } from 'vue-error-boundary-kit/adapters/sentry'
import { createBugsnagReporter } from 'vue-error-boundary-kit/adapters/bugsnag'
import { createLogRocketReporter } from 'vue-error-boundary-kit/adapters/logrocket'
import { createOtelReporter } from 'vue-error-boundary-kit/adapters/otel'
  • adapters/consolecreateConsoleReporter({ logger?, prefix? }), plus a ready-made consoleReporter instance. Logs via console.error by default; good dev-mode default. Messages are prefixed with [vue-error-boundary-kit] — pass prefix: '[my-app]' to rebrand it, or prefix: '' to drop it.
  • adapters/httpcreateHttpReporter({ endpoint, batchInterval?, maxBatchSize?, headers?, serialize? }). POSTs via fetch (batched if batchInterval > 0); a pagehide listener force-flushes any pending batch via navigator.sendBeacon, since an in-flight fetch can be aborted when the page is actually closing.
  • adapters/sentrycreateSentryReporter({ client, tags? }). @sentry/vue is never imported by this package — pass in your own already-initialized Sentry client (anything with a captureException(error, hint?) method); this stays a thin, structurally-typed wrapper.
  • adapters/bugsnagcreateBugsnagReporter({ client, severity? }). Wraps Bugsnag.notify(error, onError), setting event.context/event.severity and attaching an errorBoundary metadata section via event.addMetadata(...). @bugsnag/js is never imported — pass in your own initialized client.
  • adapters/logrocketcreateLogRocketReporter({ client, tags? }). Wraps LogRocket.captureException(error, { tags, extra }); since LogRocket requires scalar extra values, non-scalar context is JSON.stringify'd automatically. logrocket is never imported — pass in your own initialized client.
  • adapters/otelcreateOtelReporter({ tracer, spanName?, attributes? }). Starts a span per error via your own already-initialized OTel Tracer (e.g. trace.getTracer('my-app')), calls recordException() + setStatus({ code: ERROR }), attaches the CapturedError fields as span attributes, then ends the span. @opentelemetry/api is never imported — pass in your own tracer. Want errors attached to the current span instead of a fresh one? Pass { startSpan: () => trace.getActiveSpan() ?? realTracer.startSpan(name) } as the tracer.

All six destination adapters accept a CapturedError and forward it somewhere; you can pass a reporter (or an array) to any <ErrorBoundary>, to useErrorBoundary(), or to useGlobalErrorCapture().

Rate-limiting & dedup

adapters/rate-limit wraps any reporter(s) to protect them from a mass-failure storm — e.g. a broken list re-rendering hundreds of times a second, which would otherwise spam Sentry/HTTP/etc. with near-identical reports:

ts
import { createRateLimitedReporter } from 'vue-error-boundary-kit/adapters/rate-limit'

const reporter = createRateLimitedReporter([sentryReporter, consoleReporter], {
  maxPerWindow: 10, // at most 10 reports forwarded per window (default: 10)
  windowMs: 10_000, // window size (default: 10s)
  dedupWindowMs: 10_000, // suppress identical repeats within this window (default: windowMs)
  onSuppressed: (error, { reason, count }) => {
    // reason: 'dedup' | 'rate-limit'
  },
  internalErrorPrefix: '[vue-error-boundary-kit]', // safety-net log if onSuppressed/a wrapped reporter throws; '' to omit
})

"Identical" means the same source + componentName + message. This is itself an ErrorReporter, so it composes with everything else — pass it wherever you'd pass any other reporter.

adapters/breadcrumbs — a rolling window of "things that happened before the error", attached to reports automatically. Nothing is auto-instrumented: call addBreadcrumb() yourself from wherever you already have the information (a router hook, a click handler, a state-management action) — the same opt-in spirit as useGlobalErrorCapture().

ts
import { createBreadcrumbTrail, withBreadcrumbs } from 'vue-error-boundary-kit/adapters/breadcrumbs'

const trail = createBreadcrumbTrail({ limit: 20 })

router.afterEach((to) => {
  trail.addBreadcrumb({ category: 'navigation', message: `→ ${to.fullPath}` })
})

const reporter = withBreadcrumbs(sentryReporter, { trail })
vue
<ErrorBoundary :reporter="[reporter, trail.record]">…</ErrorBoundary>
  • createBreadcrumbTrail({ limit? })entries (chronological, oldest first — the reverse of createErrorHistory()'s most-recent-first, matching how breadcrumbs read as a timeline elsewhere), addBreadcrumb({ category, message, timestamp?, data? }), clear(), and record — itself an ErrorReporter, so passing it alongside your real reporter(s) auto-adds every captured error to the trail too, meaning a later error's breadcrumbs include earlier ones.
  • withBreadcrumbs(reporter, { trail, contextKey?, internalErrorPrefix? }) — wraps any reporter(s) so every report() call's context includes the trail's current entries under contextKey (default: 'breadcrumbs').