SDK reference
Configuration
Section titled “Configuration”Everything beyond apiKey / endpoint / apiEndpoint / service is optional. Defaults are tuned for a typical SaaS frontend. For a minimal setup, see the quickstart.
Required
Section titled “Required”| Field | What it does | Notes |
|---|---|---|
apiKey | Public ingest token sent on every OTLP request, also used to mint session JWTs for replay uploads. | Falls back to OSUITE_INGEST_TOKEN. Public — bundled in your JS. Backend rate-limits per key. |
endpoint | Base URL for OTLP traces and logs. The SDK posts to ${endpoint}/v1/traces and ${endpoint}/v1/logs. | Falls back to OSUITE_INGEST_ENDPOINT. |
apiEndpoint | Base URL for the Osuite control plane (replay presign + session JWT). The SDK posts to ${apiEndpoint}/rum/session/init and ${apiEndpoint}/rum/replay-chunk/presign. | Falls back to OSUITE_API_ENDPOINT. Different host from endpoint because replay blobs go to object storage, not OTLP. |
service.name | Identifies the frontend in your traces (e.g. frontend-web, admin-app). | Required. |
service.version | Build id — git SHA, tag, or semver. Used for source-map matching. | Required. |
service.environment | production, staging, development, etc. | Required — backend filters and dashboards key off this. |
Session
Section titled “Session”A session is a continuous user visit. A new one starts after a long idle, after the hard cap, or when you change the user identity.
session: { inactivityTimeoutMs: 1_800_000, hardCapMs: 10_800_000,}| Field | Default | What it does |
|---|---|---|
inactivityTimeoutMs | 1_800_000 (30 min) | Idle time before the session rotates. Activity = clicks, keystrokes, scrolls, fetches, tab focus. |
hardCapMs | 10_800_000 (3 h) | Maximum session length regardless of activity. Prevents week-long zombie sessions. |
The session id is stored in localStorage and shared across tabs via BroadcastChannel. Calling setUser / clearUser rotates the session immediately so a logged-in session is never conflated with the pre-login one.
Sampling
Section titled “Sampling”Head-based session sampling for traces and logs, with an error-triggered upgrade safety net. See Sampling for the behavior.
sampling: { sessionSampleRate: 1.0, upgradeOnError: true, preSampleBuffer: { maxItems: 500, maxAgeMs: 60_000, },}| Field | Default | What it does |
|---|---|---|
sessionSampleRate | 1.0 | Probability that a session is “sampled” (everything exports immediately). Range [0, 1]. Decided once per session. Set to 0.1 to sample 10% of sessions. |
upgradeOnError | true | When true, an unsampled session is upgraded to sampled the first time an error log fires (window.error, unhandledrejection, React error, captureException, captureMessage('fatal')). Buffered spans/logs drain immediately and exporting stays on for the rest of the session. |
preSampleBuffer.maxItems | 500 | Hard cap on items held for an unsampled session. Older items evicted FIFO. |
preSampleBuffer.maxAgeMs | 60_000 | Items older than this are dropped on each push. |
Replay
Section titled “Replay”rrweb session replay. Privacy defaults are strict — all text and inputs are masked unless you opt in per element. See Session replay for masking and privacy classes.
replay: { mode: 'always', sampleRate: 0.1, bufferSeconds: 30, trailingSeconds: 15, maxBufferMB: 50, maskAllText: true, maskAllInputs: true, blockClass: 'osuite-block', ignoreClass: 'osuite-ignore', unmaskClass: 'osuite-unmask', uploadOnSessionEnd: false,}| Field | Default | What it does |
|---|---|---|
mode | 'always' | always: record + upload everything. probabilistic: roll once per session at sampleRate; sampled sessions behave like always, others don’t record. on-error / hybrid currently fall back to always with a warning. |
sampleRate | 0.1 | Used only by probabilistic. Range [0, 1]. |
bufferSeconds | 30 | Rolling-window length reserved for on-error / hybrid; not active while those fall back to always. |
trailingSeconds | 15 | How long to keep uploading after a trigger fires; not active while on-error / hybrid fall back to always. |
maxBufferMB | 50 | Per-session cap on IndexedDB usage. Oldest non-uploaded chunks evicted first. |
maskAllText | true | All text nodes recorded as ***. Opt back in per element with class="osuite-unmask". |
maskAllInputs | true | All <input> / <textarea> / <select> values masked. |
blockClass | 'osuite-block' | Elements with this class become a placeholder in replay (e.g. payment forms). |
ignoreClass | 'osuite-ignore' | Events on these elements aren’t recorded at all. |
unmaskClass | 'osuite-unmask' | Per-element opt-out of maskAllText. |
uploadOnSessionEnd | false | When true, force-flush the rolling buffer when the session rotates. |
Interactions
Section titled “Interactions”User-action spans. click is always on; richer detection is opt-in.
interactions: { level: 'standard', rageClicks: true, deadClicks: false, scrollDepth: { thresholds: [50, 100] },}| Field | Default | What it does |
|---|---|---|
level | 'standard' | 'minimal' = clicks only. 'standard' = clicks + form submits + input focus/blur + visibility change. |
rageClicks | false | When true (or an object), emits user_interaction.rage_click when 3 clicks happen within 1 s in a 20 px radius. Tunable: {clickCount, windowMs, radiusPx}. |
deadClicks | false | Emits user_interaction.dead_click when a click triggers no DOM mutation or network within max(mutationWaitMs=100, networkWaitMs=500). Off by default — false-positive prone for legitimate “do nothing” clicks. Tunable: {mutationWaitMs, networkWaitMs}. |
scrollDepth | false | Emits user_interaction.scroll_depth when the user crosses configured percentages of page height. Defaults {thresholds: [25, 50, 75, 100]} when set to true. |
Input field values are never captured — only field name and type.
Errors
Section titled “Errors”Which uncaught error sources to listen on. See Frontend errors for how errors are grouped and reported.
errors: { captureWindowError: true, captureUnhandledRejection: true, captureResourceError: true,}| Field | Default | What it does |
|---|---|---|
captureWindowError | true | Listen on window.error for runtime errors. |
captureUnhandledRejection | true | Listen on unhandledrejection for unhandled Promise rejections. |
captureResourceError | true | Listen on window.error for failed <img> / <script> / <link> / <audio> / <video> / <source> loads. |
All routed through osuite.captureException internally — same log schema, distinguished by event.name.
Console
Section titled “Console”Default off. Opt in to capture console.* calls as log records.
console: { capture: ['error', 'warn'],}The default is [] (nothing captured). Each captured call:
- Still calls the original
console.*(your dev tools logs unchanged). - Emits
event.name='browser.console_<level>'. - Serializes args with a circular-and-bigint-safe replacer, capped at 4 KB body.
- Maps
console.log/infoto OTel severityINFO;warn→WARN;error→ERROR;debug→DEBUG.
Off by default because console output is high-volume and app code typically expects console to be side-effect-free.
Navigation
Section titled “Navigation”SPA route-change tracking.
navigation: { enabled: true, framework: 'auto',}| Field | Default | What it does |
|---|---|---|
enabled | true | Set false to disable route_change spans. |
framework | 'auto' | 'auto' sniffs __NEXT_DATA__ / __next_f and uses the Next adapter; otherwise falls back to a generic History API adapter. |
Both adapters patch pushState / replaceState / popstate, then declare the route settled when the DOM is quiet for 500 ms (or hits a 5 s hard cap). Fetch/XHR spans during that window become children of the route_change span automatically.
Propagation
Section titled “Propagation”Which outgoing requests get the traceparent and baggage headers (carrying session.id + user.id).
propagation: { allowlist: [/\/api\//, 'api.example.com'],}- Empty allowlist (default) = same-origin only. Same-origin requests (those starting with
/or matchingwindow.location.origin) get the headers; everything else does not. - Non-empty allowlist replaces same-origin matching. Strings match by substring; regexes match by
.test(url).
Same-origin by default avoids leaking trace context to third-party APIs (analytics, ad pixels, vendor SDKs).
debug: true,Default false. When true, the SDK prints internal diagnostics (init steps, sampling decisions, transport failures) to console.debug. Use during integration; turn off in production.
Public API
Section titled “Public API”import { osuite } from '@osuite/rum';
osuite.setUser({ id: 'u_123', plan: 'pro', tenantId: 't_99' });osuite.clearUser();
osuite.captureException(err, { extra: { feature: 'checkout', cartTotal: 42.5 }, level: 'error' });osuite.captureMessage('payment retried', 'warn', { extra: { attempt: 2 } });
osuite.addSpanAttributes({ 'cart.total': 42.5, 'cart.items': 3 });
osuite.replay.capture('user-reported-issue');
await osuite.flush();await osuite.shutdown();setUser/clearUser— set or clear the user identity. Either call rotates the session so a logged-in session is never conflated with the pre-login one.captureException/captureMessage— report handled errors and messages.extrakeys becomeapp.<key>log attributes. Levels are'debug' | 'info' | 'warn' | 'error' | 'fatal';'fatal'triggers a sampling upgrade.addSpanAttributes— attach attributes to the active span.replay.capture(label)— no-op while replaymodeisalways, which already uploads every chunk.flush— force all buffered telemetry out (useful before navigating away).shutdown— stop everything (useful in tests).
React adapter
Section titled “React adapter”The subpath @osuite/rum/react exposes OsuiteErrorBoundary, a React error boundary that reports render crashes and triggers a sampling upgrade. It is kept off the baseline bundle so the core SDK does not pull React in. See Frontend errors for usage.
Bundle size
Section titled “Bundle size”| Entry | Target (gzip) |
|---|---|
@osuite/rum baseline | < 15 KB |
@osuite/rum/react | < 1 KB |
| Replay (rrweb + pako, lazy-loaded) | ~40 KB |
Replay is loaded via dynamic import() so the cost lands only when replay actually starts.
Browser support
Section titled “Browser support”Modern evergreen browsers (Chrome, Edge, Firefox, Safari). ES2020 target. Requires BroadcastChannel for cross-tab session sync (falls back to the storage event), IndexedDB for replay buffering (falls back to in-memory), and localStorage (falls back to in-memory; cross-tab disabled).