DebugBundle
SDKs

Browser SDK

Capture exceptions, breadcrumbs, network activity, and user interactions from front-end applications. Beacon-safe flush, session controls, and storm suppression included.

Installation

npm install @debugbundle/sdk-browser

Quick Setup

import DebugBundle from '@debugbundle/sdk-browser';

DebugBundle.init({
  projectToken: 'tok_xxxx',   // Your project token (write-only)
  environment: 'production',
  service: 'my-spa',
});

Calling init() automatically:

  • Hooks window.onerror and window.onunhandledrejection
  • Registers beforeunload / visibilitychange for unload-safe flushing
  • Starts breadcrumb capture (clicks, route changes, console, network)
  • Fetches remote config once from the relay or API

Configuration

OptionTypeDefaultDescription
projectTokenstringRequired. Project-scoped write-only token.
environmentstring"production"Environment name.
servicestringdocument.title or "browser-app"Service identifier.
endpointstringAuto-resolvedIngestion endpoint. Prefers relay path, falls back to direct API.
enabledbooleantrueKill switch.
sampleRatenumber (0–1)1.0Event-level sampling rate.
logLevelLogLevel"warning"Minimum log level to capture.
redactFieldsstring[]["password", "secret", "token", "authorization", "cookie", "ssn", "credit_card"]Field names to redact from captured data.
maxBreadcrumbsnumber50Maximum breadcrumbs retained in the ring buffer.
breadcrumbsOnErrorOnlybooleanfalseWhen true, breadcrumbs attach only to error events, not standalone logs.
captureNetworkbooleantrueCapture fetch and XMLHttpRequest calls as breadcrumbs.
captureClicksbooleantrueCapture click events with CSS selector paths.
captureRouteChangesbooleantrueCapture popstate and pushState/replaceState route changes.
captureConsolebooleanfalseOpt-in: capture console.error and console.warn.
networkFilterBrowserNetworkFilterConfigFilter captured network requests by URL pattern, header, or status code.
sessionSampleRatenumber (0–1)1.0Session-level sampling. Decided once at session start.
maxEventsPerSessionnumber100Hard cap per session. After this, events are silently dropped.
batchSizenumber25Events per flush batch.
flushIntervalnumber (ms)3000Auto-flush interval.
maxBufferedEventsnumber500Max events in buffer before oldest are dropped.
requestTimeoutMsnumber (ms)5000HTTP transport timeout.
onDiagnostic(diagnostic) => voidCallback for SDK self-diagnostic events.

Transport Resolution

The Browser SDK resolves its transport endpoint in this order:

  1. Explicit endpoint — If you set endpoint in config, the SDK uses it directly.
  2. Same-origin relay — The SDK probes for a relay handler at /_debugbundle/browser on the current origin. If found, all events route through your backend.
  3. Direct API — Falls back to https://api.debugbundle.com/v1/events.

The relay path is preferred because it avoids CORS, ad-blocker interference, and content security policy issues.


Breadcrumbs are a chronological trail of user actions and system events leading up to an error. They attach automatically to every captured exception.

Captured Types

TypeSourceExample
clickDOM click listenerbutton.submit-btn clicked
navigationpopstate / History APINavigated to /dashboard
networkfetch / XMLHttpRequestGET /api/users → 200 (142ms)
consoleconsole.error, console.warnconsole.error("timeout")
customDebugBundle.addBreadcrumb()User-defined context events

Manual Breadcrumbs

DebugBundle.addBreadcrumb({
  type: 'custom',
  category: 'checkout',
  message: 'Payment form submitted',
  data: { paymentMethod: 'card' },
});

Ring Buffer

The SDK maintains a fixed-size ring buffer (default: 50). When the buffer is full, the oldest breadcrumb is dropped. On exception capture, the entire buffer attaches to the error event.


Network Capture

When captureNetwork is enabled, the SDK intercepts fetch and XMLHttpRequest to log:

  • Method and URL
  • Response status code
  • Duration (ms)
  • Request/response content length

Network Filtering

Use networkFilter to control what gets captured:

DebugBundle.init({
  projectToken: 'tok_xxxx',
  captureNetwork: true,
  networkFilter: {
    denyUrls: [/analytics\.example\.com/, /\/health$/],
    allowUrls: [/\/api\//],
    captureRequestHeaders: ['content-type', 'x-request-id'],
    captureResponseHeaders: ['x-request-id'],
    captureRequestBody: false,
    captureResponseBody: false,
  },
});
Filter OptionTypeDescription
denyUrls(string | RegExp)[]URLs matching any pattern are excluded.
allowUrls(string | RegExp)[]If set, only matching URLs are captured.
captureRequestHeadersstring[]Allowlist of request headers to capture.
captureResponseHeadersstring[]Allowlist of response headers to capture.
captureRequestBodybooleanCapture request body (default: false).
captureResponseBodybooleanCapture response body (default: false).

Sensitive headers (authorization, cookie) are always redacted regardless of allowlist.


Session Controls

Session Sampling

sessionSampleRate determines whether an entire session is captured. The decision is made once when the session starts and persists for that session, so you get either full context or nothing.

DebugBundle.init({
  projectToken: 'tok_xxxx',
  sessionSampleRate: 0.1,  // Capture 10% of sessions
});

Per-Session Event Cap

maxEventsPerSession prevents runaway event volume from a single user session:

DebugBundle.init({
  projectToken: 'tok_xxxx',
  maxEventsPerSession: 50,  // Hard cap per session
});

Session API

// Get current session ID
const sessionId = DebugBundle.getSessionId();

// Reset session (e.g., on logout)
DebugBundle.resetSession();

Trace Correlation

The Browser SDK adds an X-DebugBundle-Trace-Id header to outgoing fetch requests. Your backend SDK reads this header to correlate frontend and backend events into a single incident timeline.

// Automatic — no setup needed if captureNetwork is enabled
// The header is added to all fetch requests to same-origin URLs

// To include cross-origin URLs:
DebugBundle.init({
  projectToken: 'tok_xxxx',
  traceOrigins: ['https://api.example.com'],
});

Device Context

Every event includes automatically collected device context from the browser runtime:

FieldExample
userAgentMozilla/5.0 ... Chrome/125.0.6422.142 Safari/537.36
browserChrome 125.0.6422.142
osmacOS 15.1
deviceTypedesktop
screen2560x1440
viewport1280x720
devicePixelRatio2
touchCapablefalse
languageen-US
connectionType4g
colorSchemePreferencedark

This metadata improves incident triage, but it also increases the amount of browser-identifying context attached to each event. In combination, fields such as user agent, screen size, viewport, language, touch capability, connection type, and color-scheme preference can contribute to browser fingerprinting.

If your privacy posture does not allow that level of client metadata, do not deploy the Browser SDK on those surfaces. There is no field-level device-context toggle today; the safe boundary is to keep capture server-side only or avoid browser instrumentation for the affected application.


Manual Capture

Exceptions

try {
  await riskyClientOperation();
} catch (error) {
  DebugBundle.captureException(error, {
    tags: { component: 'checkout-form' },
  });
}

Logs

DebugBundle.captureLog('Feature flag loaded', 'info', {
  tags: { feature: 'new-checkout' },
});

Context

DebugBundle.setContext('user', { id: '123', plan: 'team' });
DebugBundle.setContext('feature-flags', { newCheckout: true });

Unload-Safe Flushing

The SDK ensures events are delivered even when the user navigates away or closes the tab:

  1. visibilitychange → hidden: Triggers immediate flush via navigator.sendBeacon()
  2. beforeunload: Fallback flush via fetch() with keepalive: true
  3. Beacon payload limit: If the payload exceeds the browser's beacon limit (~64 KB), the SDK splits into multiple beacon calls

No events are lost during normal page navigation, tab close, or browser quit.


Volume Control

The Browser SDK enforces the same storm suppression as the Node SDK:

ControlThresholdBehavior
Duplicate dedup3 events in 30sIdentical events beyond the 3rd are suppressed
Loop detection10+ events in 2sEnters suppression mode
Suppression checkpointEvery 30sOne aggregate error_suppressed event
Auto-recovery60s silenceResets to normal capture

Combined with sessionSampleRate and maxEventsPerSession, you have three independent layers of volume control.


Trigger Tokens

Trigger tokens let support teams or internal tools force-enable capture for a specific user session, even if that session was excluded by sampling.

// Append ?_dbtoken=<trigger-token> to any page URL
// or programmatically:
DebugBundle.activateTriggerToken('trg_xxxx');

When activated, the SDK overrides sessionSampleRate and enables full capture for the remainder of that session.


Safety Guarantees

The Browser SDK is designed to be invisible to your application:

  • Never throws — All SDK code runs inside try/catch. Failures are swallowed silently.
  • Never blocks rendering — Event capture and flush are asynchronous.
  • Never mutates user data — Events are serialized from copies, never references.
  • Minimal bundle size — Tree-shakeable, no heavy dependencies.
  • CSP-friendly — No eval(), no inline scripts, no dynamic code generation.

Next Steps

  • Node.js SDK — Server-side capture with framework and logger integrations
  • SDKs Overview — Universal interface and language support matrix

On this page