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 { getBrowsonic } from '@browsonic/sdk';
const sdk = getBrowsonic();sdk.init({ apiEndpoint: 'https://api.browsonic.com', appKey: 'your-app-key', apiKey: 'pk_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 { getBrowsonic } from '@browsonic/sdk';import App from './App';
const sdk = getBrowsonic();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 framework adapter guides for install and quick-start code for each one.
Configuration
Every option init() honours on @browsonic/sdk 3.27, grouped by purpose. Defaults are the SDK's own; the server can lower sampleRate and the replay ceiling at runtime, never raise them.
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 shown with every event. |
release | string | null | null | Release / build identifier of the host app — the value source maps are uploaded under and symbolication resolves against. |
clientVersion | string | null | null | Client version tag (surfaced as Versions in the dashboard). |
debug | boolean | false | Verbose console logging. |
Sampling & consent
| Parameter | Type | Default | Description |
|---|---|---|---|
sampleRate | number | 0.1 | Head-based session sampling for non-error events (0–1). Errors and fatals are always sent; page views, Web Vitals and breadcrumb-only events ship from the sampled share of sessions. The server can push a lower rate. |
minSampleRate | number | 0 | Floor (0–1) below which the server-pushed sample rate cannot drive the effective rate. |
pageViewSampleRate | number | 1 | Sample rate for non-initial page views on high-traffic SPAs; the first page view is always sent. |
respectGPC | boolean | true | Honour Global Privacy Control: when the browser signals it, the visitor ID falls back to a fresh, unlinkable UUID per call. |
hasConsented | () => boolean | null | Host-supplied consent gate. Until it answers, events are held (page views up to 10 s); only an explicit false drops them. |
visitorIdStrategy | 'cookie' | 'localStorage' | 'session' | 'none' | "session" | Where the visitor ID lives: "cookie" (1-year host-only cookie), "localStorage", "session" or "none". |
Page views & App Atlas
| Parameter | Type | Default | Description |
|---|---|---|---|
trackPageViews | boolean | true | Page-view events that power the App Atlas route map. Needs apiKey. |
atlas | boolean | false | The one switch that turns App Atlas on: page views, screen titles, navigation triggers and the task lifecycle. |
normalizePageViewRoutes | boolean | true | Collapse page-view URLs to a stable route key at source (/users/123 → /users/:id; query and fragment dropped). |
pageViewRoutePatterns | Array<{ test: RegExp; replace: string }> | [] | Declarative route rewrites ({ test, replace }) applied to the raw URL before generic normalisation. |
beforeSendPageView | ((url: string) => string | null) | null | null | Final hook on a page-view route after normalisation and redaction; return a string to override, null to drop. |
hashRouting | boolean | false | Treat the URL fragment as the route for hash-router apps (#/users/123 → /users/:id). |
manualPageViews | boolean | false | Keep the collector live for trackPageView(route) but do not auto-fire page views. |
captureNavTriggers | boolean | true | Attach the accessible name of the click or submit that caused each route change. |
captureDocumentTitle | boolean | true | Send document.title (redacted, 120 chars) with page views so Atlas can name screens. |
Timeline & network
| Parameter | Type | Default | Description |
|---|---|---|---|
includeTelemetry | boolean | true | Attach the telemetry timeline (console, network, navigation, interactions) to errors. |
captureLevels | EventLevel[] | ["error"] | Console levels captured as events. |
captureXHR | boolean | true | Capture XMLHttpRequest in addition to fetch. |
networkTelemetry | boolean | true | Record successful network requests as timeline entries (failures are always recorded). |
trackNavigation | boolean | true | Route-change breadcrumbs in single-page apps. |
trackVisitor | boolean | false | Click / input interaction breadcrumbs. Off for privacy; values are never captured, only element identity, type, length and pattern. |
visitor | object | { click: true, input: true } | Which interactions to record when trackVisitor is on. |
captureStorage | object | { local: false, session: false } | Snapshot localStorage / sessionStorage alongside an error; optional keys allow-list. |
captureCookieValues | boolean | false | Include cookie values (names are always visible). A built-in session / CSRF cookie blocklist applies regardless. |
sessionContext | object | { allowKeys: [] } | App-defined session-level context with an explicit allowKeys egress policy — an allow list, not a deny list. |
Redaction
| Parameter | Type | Default | Description |
|---|---|---|---|
redactPatterns | RegExp[] | [] | Extra PII regular expressions applied to outgoing messages, URLs and referrers, on top of the built-in e-mail / phone / national-ID / card rules. |
redactKeys | string[] | built-in set | Exact key names redacted from storage, cookies and user context (extends the built-in set). |
redactKeyPatterns | string[] | ["token", …] | Key-name patterns matched on token boundaries, the slow-path fallback to redactKeys. |
redactCookieNames | string[] | [] | Cookie names whose values are always redacted. |
Web Vitals, replay & widget
| Parameter | Type | Default | Description |
|---|---|---|---|
trackWebVitals | boolean | false | Collect LCP / FCP / CLS / TTFB / FID / INP from config — the route for a script-tag host that cannot import webVitalsPlugin(). |
disableReplay | boolean | false | Hard kill-switch: sessionReplayPlugin() never starts, whatever the plan allows. |
widgetRules | WidgetRule[] | [] | Client-side in-app prompt rules, evaluated in the browser. |
widgetRulesEndpoint | string | boolean | false | Fetch server-defined widget rules: true for the default path, or a URL. |
widgetPosition | WidgetPosition | "bottom-right" | Corner the in-app widget renders in. |
cspNonce | string | null | Nonce attached to the widget's shadow-root <style> under a strict Content Security Policy. |
Transport & diagnostics
| Parameter | Type | Default | Description |
|---|---|---|---|
compress | boolean | auto | Gzip event batches via CompressionStream when the server says it decodes them; false never, true always. |
persistQueue | boolean | false | Persist the offline event queue to localStorage across reloads. Dismissal sends that miss the keepalive budget are parked and retried regardless. |
internalDiagnostics | boolean | false | POST the SDK's own metrics (init and flush latency, queue depth, drop reasons) to /v1/diagnostics. |
captureAsyncStack | 'manual' | 'global' | false | false | Longer async stack traces: "manual" wraps what you hand it; "global" is deprecated. |
Hooks
| Parameter | Type | Default | Description |
|---|---|---|---|
onError | (event: BrowsonicEvent) => boolean | void | null | Called before an error is reported; return false to suppress, or mutate the event. |
onErrorStorm | (phase: 'enter' | 'exit', count: number) => void | null | Called once when the SDK enters storm mode (too many errors in a short window) and once when it exits. |
onUnsupportedVersion | (minVersion: string, currentVersion: string) … | null | Called when the server says this SDK version is below its minimum. |
onIngestRejected | object | null | Called when ingest permanently refuses a batch (a 4xx other than 429); those events are dropped. |
Ignore rules & guards
| Parameter | Type | Default | Description |
|---|---|---|---|
ignoreExtensions | boolean | true | Ignore errors thrown from browser-extension code. |
ignoreScriptErrors | boolean | true | Ignore opaque cross-origin "Script error" messages. |
ignorePatterns | string[] | [] | Stack-trace substrings that suppress an error. |
ignoreMessages | string[] | [] | Error-message patterns that suppress an error. |
ignoreUrls | string[] | [] | URL patterns whose errors are ignored. |
abortInExtensionContext | boolean | false | Refuse to initialise inside a browser-extension context. |
abortForBots | boolean | false | Refuse to initialise for known bot user agents. |
botPatterns | readonly string[] | built-in list | Custom bot user-agent fragments; replaces the built-in list. |
Accepted, but no longer configurable
Since SDK 3.25.0 these keys are internal constants. init() still accepts them for compatibility, names the ones you set once on the console, and ignores them — each was a tuning number no deployment could get right (a 1 ms flush interval or a batch size of 0 used to switch error tracking off with a single console line as the only sign):flushIntervalMs, requestTimeoutMs, maxBatchSize, cooldownMs, maxPayloadBytes, errorStormThreshold, errorStormWindowMs, errorStormCooldownMultiplier, internalDiagnosticsIntervalMs, maxStackFrames, maxQueueSize, maxValueLength, maxTelemetryEntries.
Complete example
import { COMMON_THIRD_PARTY_PATTERNS } from '@browsonic/sdk';
sdk.init({ // Required apiEndpoint: 'https://api.browsonic.com', appKey: 'my-production-app', apiKey: 'pk_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();identify(subscriber) · clearIdentity()
Declares which subscriber this browser belongs to — the person behind the account — and keys the cross-app user journey (Professional).setUser describes the account in your own system;identify names the person.
trackPageView(route?, options?)
Reports a page view, optionally with a route template such as/users/:id. Automatic with trackPageViews; use it with manualPageViews: true when your router owns navigation.
addBreadcrumb(breadcrumb) · setTag(key, value) · setContext(name, ctx) · setExtra(key, value)
Attach a manual timeline entry, an indexed key/value, a named object of structured context, or a free-form value to every subsequent event. Each has a matching remove… / clear….
newSession() · getSessionHealth() · markSessionCrashed()
Sessions end after 30 minutes without telemetry, on destroy()and on clearIdentity(); newSession() ends one in place. getSessionHealth() answers 'ok','errored' or 'crashed';markSessionCrashed() declares the session unrecoverable.
enterCriticalPath(options) · exitCriticalPath() · isInCriticalPath()
Marks a business-critical flow (checkout, sign-up) so errors inside it are weighted and surfaced as such.
register(plugin) · updateConfig(partial)
register adds an opt-in plugin and must be called beforeinit(). updateConfig changes config at runtime; keys a collector snapshots at install are refused with a console message.
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: 'pk_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) },});Session Replay
Reconstruct what the user saw and did in the moments around an error — a DOM-level recording that plays back next to the stack trace. Session Replay is an opt-in plugin; it is not part of the default SDK.
Session Replay is a Professional-tier feature. On lower plans the plugin registers cleanly but the server withholds the recording entitlement, so nothing is captured. The effective sample rate is min(sampleRate × 100, plan ceiling %).
Setup
Import the plugin from the @browsonic/sdk/replaysub-path and register it before init(), exactly like any other plugin.
import { getBrowsonic } from '@browsonic/sdk';import { sessionReplayPlugin } from '@browsonic/sdk/replay';
const sdk = getBrowsonic();
// Register the plugin BEFORE init().sdk.register(sessionReplayPlugin());
sdk.init({ apiEndpoint: 'https://api.browsonic.com', appKey: 'web', apiKey: 'pk_live_…', clientVersion: '1.0.0',});Masking defaults
Recording is privacy-first by default — matching Sentry parity. You have to loosen masking deliberately; you never have to remember to turn it on.
| Option | Default | Effect |
|---|---|---|
maskAllText | true | Every text node is masked before it leaves the browser. |
maskAllInputs | true | Input values are masked. Password inputs stay masked even when this is false. |
blockAllMedia | true | Images, video and <canvas> render as sized placeholders. |
sampleRate | 1 | Host-requested rate (0–1); clamped by the plan ceiling. |
sdk.register(sessionReplayPlugin({ maskAllText: true, // default — mask every text node (Sentry parity) maskAllInputs: true, // default — password inputs stay masked even if false blockAllMedia: true, // default — images / video / canvas become placeholders blockSelector: '.pii', // extra elements to block, rendered as a sized box}));Recordings are kept for 90 days on Professional and30 days on Enterprise, in a per-workspace store of5 GiB (Professional) or 10 GiB(Enterprise) — the numbers your workspace is on are shown underSettings → Session Replay. When the store passes 90 % the SDK is told to record a smaller sample, and at 100 % it stops recording rather than upload segments ingest would refuse; the dashboard says so on the Replay page.
The active sample ceiling is controlled from the dashboard underSettings → Session Replay — there is no server-bypassing replay switch in the browser.
Web Vitals
Report Core Web Vitals from real sessions. Like Session Replay, it is an opt-in plugin: the collector is a small native PerformanceObserver, but it changes what the SDK reports, so you turn it on consciously.
Setup
webVitalsPlugin is exported from the main@browsonic/sdk entry. Register it beforeinit().
import { getBrowsonic, webVitalsPlugin } from '@browsonic/sdk';
const sdk = getBrowsonic();
// Register BEFORE init(). Not in the default plugin set —// you opt in explicitly.sdk.register(webVitalsPlugin());
sdk.init({ apiEndpoint: 'https://api.browsonic.com', appKey: 'web', apiKey: 'pk_live_…', clientVersion: '1.0.0',});What it collects
| Metric | Name | Measures |
|---|---|---|
LCP | Largest Contentful Paint | Loading — when the largest element renders. Attribution: the element and the resource URL behind it. |
INP | Interaction to Next Paint | Responsiveness — latency of user interactions. Attribution: the target and the input / processing / presentation phases. |
CLS | Cumulative Layout Shift | Visual stability — unexpected layout movement. Attribution: the element that shifted. |
FCP | First Contentful Paint | Loading — when the first text or image renders. |
TTFB | Time to First Byte | Server and network — with the DNS / connect / request / response breakdown. |
FID | First Input Delay | Responsiveness of the first interaction (kept for older browsers; INP is the primary metric). |
Each sample carries the route it was measured on, and since SDK 3.27 the attribution above plus long-animation-frame breadcrumbs, so a slow score points at a component rather than a page.
Samples surface in the dashboard on the Performance page. A per-session cap (maxSamples, default 30) guards against runaway observers in long-lived SPAs.
Source Maps
Ship minified bundles and still read original TypeScript in every stack frame. @browsonic/build-tools provides bundler plugins for Vite, Webpack, Rollup and esbuild that emit and upload source maps to Browsonic at build time.
Symbolication of uploaded maps is a Professional-tier feature. The upload runs on any plan; symbolicated frames appear once the tenant is entitled.
The release you upload maps under has to match theclientVersion you pass to init()byte-for-byte — that string is the only key the service uses to pair a runtime error with its map. If they drift, frames stay minified.
Vite plugin
Emit hidden source maps (generated, uploaded, but not referenced from the shipped bundle) and add the plugin. Webpack, Rollup and esbuild use the matching sub-path (@browsonic/build-tools/webpack, /rollup,/esbuild).
import { defineConfig } from 'vite';import { browsonicSourceMaps } from '@browsonic/build-tools/vite';
export default defineConfig({ // Emit hidden maps: symbolication works, but the map URL is // NOT referenced from the shipped bundle. build: { sourcemap: 'hidden' }, plugins: [ browsonicSourceMaps({ appKey: 'web', release: '1.0.0', // MUST equal the SDK's clientVersion // token: process.env.BROWSONIC_SOURCEMAP_TOKEN (default) baseUrl: 'https://api.browsonic.com', }), ],});Upload token
Uploads authenticate with a dedicated source-map token. It is abuild-time secret — read fromBROWSONIC_SOURCEMAP_TOKEN when thetoken option is omitted. Never inline it into browser code. If the token is missing, the plugin prints a warning and skips the upload rather than failing the build.
# Build-time secret — mint under Settings → Source Maps in the# dashboard. Never expose this in the browser bundle.export BROWSONIC_SOURCEMAP_TOKEN=bsm_…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. |
| Session Replay (DOM) | ⚠️ Opt-in plugin | Reconstructed DOM + interactions; text, inputs and media masked by default. |
| App Atlas screenshots | ⚠️ Opt-in | Rendered from masked replay data; masked titles are rejected, not un-masked. |
| 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 inlocalStorage, 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 — how to report a vulnerability, response targets, scope and the current state of npm release provenance — see the security page.
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.