Introduction
Browsonic SDK is a lightweight, zero-dependency
JavaScript library that automatically captures frontend errors and
anomalies in real time. It is published on the public npm registry
as @browsonic/sdk under the Apache 2.0 licence.
What it captures
console.error, warn, infowindow.onerror eventsKey features
| Feature | Description |
|---|---|
| Zero dependencies | No external libraries required. |
| Automatic collection | Intercepts console, errors, and fetch automatically. |
| Smart batching | Groups events and flushes at a configurable interval. |
| Deduplication | Prevents duplicates via fingerprinting. |
| Offline support | Persists the queue to localStorage when offline. |
| Privacy first | Automatic redaction of sensitive keys. |
| Circuit breaker | Auto-disables on repeated internal errors. |
Installation
Install with your preferred package manager.
npm
npm install @browsonic/sdkpnpm
pnpm add @browsonic/sdkyarn
yarn add @browsonic/sdkQuick Start
Get up and running in under two minutes.
Basic setup
import { Browsonic } from '@browsonic/sdk';
const sdk = new Browsonic();sdk.init({ apiEndpoint: 'https://api.browsonic.com', appKey: 'your-app-key', apiKey: 'sk_live_…', // mint in dashboard (required when trackPageViews is on, which is the default)});
// That's it. Errors are now captured automatically.React integration
import React from 'react';import ReactDOM from 'react-dom/client';import { Browsonic } from '@browsonic/sdk';import App from './App';
const sdk = new Browsonic();sdk.init({ apiEndpoint: import.meta.env.VITE_BROWSONIC_API, appKey: import.meta.env.VITE_BROWSONIC_APP_KEY, apiKey: import.meta.env.VITE_BROWSONIC_API_KEY, environment: import.meta.env.MODE, clientVersion: import.meta.env.VITE_GIT_SHA, debug: import.meta.env.DEV,});
ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <App /> </React.StrictMode>);
Framework-specific adapters (@browsonic/react, @browsonic/vue, @browsonic/svelte, @browsonic/angular, @browsonic/nextjs, @browsonic/astro, @browsonic/remix) add
router instrumentation and navigation breadcrumbs on top of the
core SDK. See the
integration guide
for framework-specific wiring.
Configuration
Every option accepted by init(), grouped by purpose.
Required
| Parameter | Type | Description |
|---|---|---|
apiEndpoint | string | Base URL of your Browsonic API. |
appKey | string | Application identifier for multi-tenant routing. |
apiKey | string | Tenant API key — sent as X-API-KEY. Required when trackPageViews is on (the default). |
Environment & release
| Parameter | Type | Default | Description |
|---|---|---|---|
environment | string | "production" | Environment name. |
clientVersion | string | null | null | Client version tag (surfaced as Versions in the dashboard). |
debug | boolean | false | Verbose console logging. |
Batching & transport
| Parameter | Type | Default | Description |
|---|---|---|---|
flushIntervalMs | number | 10000 | Interval between batch sends (ms). |
maxBatchSize | number | 25 | Maximum events per batch. |
maxPayloadBytes | number | 51200 | Maximum batch payload size (bytes; sized to stay under the 64 KB sendBeacon ceiling). |
Event capture
| Parameter | Type | Default | Description |
|---|---|---|---|
captureLevels | EventLevel[] | ["error"] | Console levels to capture. |
cooldownMs | number | 60000 | Dedup time window (ms). |
Queue & persistence
| Parameter | Type | Default | Description |
|---|---|---|---|
maxQueueSize | number | 200 | Maximum events held in memory. |
persistQueue | boolean | false | Save queue to localStorage across reloads. |
Ignore rules
| Parameter | Type | Default | Description |
|---|---|---|---|
ignoreExtensions | boolean | true | Auto-ignore browser extension errors. |
ignoreScriptErrors | boolean | true | Ignore cross-origin "Script error" messages. |
ignorePatterns | string[] | [] | Stack trace patterns to ignore. |
ignoreMessages | string[] | [] | Error message patterns to ignore. |
ignoreUrls | string[] | [] | URL patterns to ignore errors from. |
Complete example
import { COMMON_THIRD_PARTY_PATTERNS } from '@browsonic/sdk';
sdk.init({ // Required apiEndpoint: 'https://api.browsonic.com', appKey: 'my-production-app', apiKey: 'sk_live_…',
// Environment environment: 'production', clientVersion: 'v2.1.0', debug: false,
// Batching flushIntervalMs: 10000, maxBatchSize: 25,
// Deduplication cooldownMs: 60000,
// Capture captureLevels: ['warn', 'error'],
// Queue maxQueueSize: 300, persistQueue: true,
// Privacy redactKeys: ['token', 'password', 'secret'],
// Ignore Rules (filter noise) ignoreExtensions: true, ignoreScriptErrors: true, ignorePatterns: COMMON_THIRD_PARTY_PATTERNS, ignoreMessages: ['ResizeObserver loop'],});API Reference
All methods available on the SDK instance.
captureMessage(message, level?)
Capture a message manually. level defaults to info.
sdk.captureMessage('User completed checkout', 'info');sdk.captureMessage('Payment failed', 'error');captureError(error)
Capture an Error instance manually.
try { await riskyOperation();} catch (error) { sdk.captureError(error as Error);}setUser(user) · clearUser()
Attach a user context to all subsequent events. Sensitive keys (token / password / secret / auth) are redacted before transport.
sdk.setUser({ id: 'user-123', email: 'user@example.com', plan: 'premium',});
// On logoutsdk.clearUser();addMetadata(key, value) · removeMetadata(key) · clearMetadata()
Attach custom key/value pairs to every subsequent event.
sdk.addMetadata('feature', 'checkout');sdk.addMetadata('cartValue', 99.99);sdk.addMetadata('isNewUser', true);
sdk.removeMetadata('feature');sdk.clearMetadata();Lifecycle: flush(), pause(), resume(), destroy()
| Method | Description |
|---|---|
flush() | Force immediate flush of queued events. Returns a Promise. |
pause() / resume() | Pause and resume event collection without losing the in-memory queue. |
destroy() | Destroy the SDK and release all listeners and timers. |
getState() | Returns 'uninitialized' | 'initializing' | 'running' | 'paused' | 'destroyed'. |
getPendingCount() | Number of events currently queued for transport. |
Event Types
Built-in event types captured by the SDK.
| Type | Level | Source | Description |
|---|---|---|---|
console_debug | info | console.debug() | Debug log (verb preserved on telemetry). |
console_info | info | console.info() | Informational log. |
console_warn | warn | console.warn() | Warning log. |
console_error | error | console.error() | Error log. |
error | error | window.onerror | Unhandled exception. |
fatal | fatal | manual | Capture-on-purpose fatal report. |
unhandledrejection | error | Promise rejection | Unhandled promise rejection. |
network_error | warn / error | fetch() / XHR | HTTP 4xx / 5xx response. |
Wire format
interface BrowsonicEvent { eventId: string; // Unique UUID timestamp: string; // ISO 8601 type: EventType; level: EventLevel; message: string; stack?: string | null; context: EventContext; // url, referrer, pageAge telemetry?: Timeline; // events leading up to error metadata?: MetadataEntry[];}
interface EventBatch { batchId: string; timestamp: string; appKey: string; environment: string; clientVersion?: string; sessionId: string; sessionContext: SessionContext; user?: UserContext; events: BrowsonicEvent[];}Telemetry Timeline
Chronological events leading up to each error — the debugging context that turns a stack trace into a story.
Categories
console.log, warn, error calls.How it works
- The SDK collects events in a ring buffer (FIFO, configurable size).
- When an error fires, the last N events ship with the error payload.
- The dashboard renders the timeline in the Timeline tab of each event.
- It answers the only question that matters: what happened right before this error?
Configuration
sdk.init({ apiEndpoint: 'https://api.browsonic.com', appKey: 'my-app', apiKey: 'sk_live_…',
// Telemetry Timeline maxTelemetryEntries: 50, // ring buffer size (default 20) includeTelemetry: true, // attach with errors (default true)
// Network telemetry captureXHR: true, networkTelemetry: true,
// Navigation trackNavigation: true,
// Visitor (see Visitor Tracking) trackVisitor: false, // OFF by default for privacy});Visitor Tracking
Track user interactions (clicks, inputs) in a privacy-safe manner.
Visitor tracking is off by default. When you enable it, actual input values are never stored — only patterns and lengths. Password fields are skipped entirely.
What is collected
| Data | Example | Purpose |
|---|---|---|
| Element tag | button, input | Identify element type. |
| Element text | "Submit Order" | Human-readable identification. |
| Element ID | submit-btn | Identify specific element. |
| CSS classes | btn primary | Debugging context. |
| Input type | email, text | Understand input purpose. |
| Value length | 16 | Know input size without content. |
| Value pattern | email, numeric | Understand input format. |
What is never collected
- Actual input values (e.g.
"john@example.com"). - Password field content — completely skipped.
- Credit card numbers.
- Any typed text content.
Configuration
sdk.init({ trackVisitor: true, visitor: { click: true, // track click events input: true, // track input events inputThrottleMs: 500, // throttle (default 500 ms) },});Privacy & Security
How Browsonic handles sensitive data and what compliance posture you inherit by default.
Data collection summary
| Data type | Collected | How it is stored |
|---|---|---|
| Error messages | ✅ Yes | Full text. |
| Stack traces | ✅ Yes | Full text. |
| Console logs | ✅ Yes | Full text (telemetry). |
| Network URLs | ✅ Yes | Full URL — no body / headers. |
| User clicks | ⚠️ Optional | Element info only. |
| User inputs | ⚠️ Optional | Pattern + length only. |
| Input values | ❌ Never | N/A. |
| Passwords | ❌ Never | Completely skipped. |
Privacy-safe defaults
| Setting | Default | Description |
|---|---|---|
trackVisitor | false | Visitor tracking off by default. |
trackNavigation | true | URL changes only, no user data. |
networkTelemetry | true | URLs only — no request / response bodies. |
captureAsyncStack | false | Performance opt-in feature. |
Automatic redaction
These keys are automatically redacted in
localStorage, sessionStorage, cookies, and
user context:
const DEFAULT_REDACT_KEYS = [ 'token', 'password', 'authorization', 'secret', 'key', 'credential', 'auth',];
sdk.init({ redactKeys: [ ...DEFAULT_REDACT_KEYS, 'ssn', 'creditCard', 'bankAccount', ], redactCookieNames: ['session_id', 'csrf_token'],});Pattern-based redaction
In addition to key-based redaction, the SDK scans free-text values
(error messages, telemetry payloads, captured network metadata)
and replaces matches with [REDACTED]:
| Pattern | What it catches |
|---|---|
name@host.tld tokens anywhere in a value. | |
| JWT | eyJ… three-segment Base64 tokens. |
| Credit card | 12–19 digit runs (with optional spaces / hyphens). |
| Opaque secret | 32-char-or-longer continuous [A-Za-z0-9_-] tokens. |
HTTP header filtering
Network telemetry captures only headers on an explicit allowlist — everything else is dropped. A hard blocklist (authorization, cookie, set-cookie, token, api-key, password, …) is dropped even if a user tries to add it to the allowlist. Header values are also passed through pattern redaction as defense in depth.
Compliance
For the full security policy, see SECURITY.md on GitHub.
Troubleshooting
Common issues and how to resolve them.
SDK not capturing events
- Check initialization —
sdk.getState()should return"running". - Enable debug mode:
sdk.updateConfig({ debug: true }). - Verify
captureLevelsincludes the event type you expect.
Events not reaching the server
- Check pending count —
sdk.getPendingCount(). - Force flush —
await sdk.flush(). - Verify
apiEndpointis correct and CORS is configured. - Check the Network tab for 4xx / 5xx responses.
High event volume
- Increase cooldown —
cooldownMs: 300000(5 minutes). - Reduce capture levels —
captureLevels: ['error']. - Increase flush interval —
flushIntervalMs: 60000.