Kubesense

Browser RUM Integration

This guide walks through adding Real User Monitoring (RUM) to a browser application using the Kubesense SDK. It covers installation, initialization, and every instrumentation API available.


1. Prerequisites

Before integrating, obtain the following from your Kubesense workspace:

ValueWhere to find it
applicationIdSettings → RUM Application Management → your application → View Details
clientTokenSettings → RUM Application Management → your application → View Details

2. Installation

Full SDK (includes Session Replay):

npm install @kubesense/kubesense-browser-rum
# or
yarn add @kubesense/kubesense-browser-rum

Slim SDK (no Session Replay, smaller bundle):

npm install @kubesense/kubesense-browser-rum-slim
# or
yarn add @kubesense/kubesense-browser-rum-slim

Option B — CDN (script tag)

Add this script in the <head> of your HTML, before any other scripts:

<script>
  (function(h,o,u,n,d){h=h[d]=h[d]||{q:[],onReady:function(c){h.q.push(c)}}
  d=o.createElement(u);d.async=1;d.src=n
  n=o.getElementsByTagName(u)[0];n.parentNode.insertBefore(d,n)
  })(window,document,'script','<CDN_URL>/kubesense-rum.js','KUBESENSE_SDK')
</script>

note: Replace <CDN_URL> with the URL provided by your Kubesense account team.


3. Initialization

Call init() once, as early as possible in your application's entry point. All API calls made before init() are queued and replayed automatically.

npm / ES Module

import { kubesenseSdk } from '@kubesense/kubesense-browser-rum'

kubesenseSdk.init({
  applicationId: '<YOUR_APPLICATION_ID>',
  clientToken: '<YOUR_CLIENT_TOKEN>',
  site: 'app.kubesense.ai',
  service: 'my-web-app',
  env: 'production',
  version: '1.0.0',
  sessionSampleRate: 100,
  trackUserInteractions: true,
  trackResources: true,
  trackLongTasks: true,
  firstPartyDomains: [
    "api.kubesense.ai",                   // exact hostname
    /\.kubesense\.ai/,                    // all subdomains via regex
    (host) => host.endsWith(".internal"), // custom function
  ],
})

CDN

window.KUBESENSE_SDK.onReady(function() {
  window.KUBESENSE_SDK.init({
    applicationId: '<YOUR_APPLICATION_ID>',
    clientToken: '<YOUR_CLIENT_TOKEN>',
    site: 'app.kubesense.ai',
    service: 'my-web-app',
    env: 'production',
    version: '1.0.0',
    sessionSampleRate: 100,
    trackUserInteractions: true,
    trackResources: true,
    trackLongTasks: true,
    firstPartyDomains: [
      "api.kubesense.ai",
      /\.kubesense\.ai/,
      (host) => host.endsWith(".internal"),
    ],
  })
})

React (App.tsx / main.tsx)

import { kubesenseSdk } from '@kubesense/kubesense-browser-rum'

kubesenseSdk.init({
  applicationId: '<YOUR_APPLICATION_ID>',
  clientToken: '<YOUR_CLIENT_TOKEN>',
  site: 'app.kubesense.ai',
  service: 'my-react-app',
  env: process.env.NODE_ENV,
  version: process.env.REACT_APP_VERSION,
  sessionSampleRate: 100,
  trackUserInteractions: true,
  trackResources: true,
  trackLongTasks: true,
  firstPartyDomains: [
    "api.kubesense.ai",
    /\.kubesense\.ai/,
    (host) => host.endsWith(".internal"),
  ],
})

function App() { /* ... */ }
export default App

4. Configuration Reference

Required

OptionTypeDescription
applicationIdstringYour RUM application ID
clientTokenstringYour client authentication token

Common Options

OptionTypeDefaultDescription
sitestringYour Kubesense instance hostname
servicestringService name for this application
envstringDeployment environment (production, staging, etc.)
versionstringApplication version (e.g. 1.2.3)
sessionSampleRatenumber100Percentage of sessions to collect (0–100)

Tracking Behaviour

OptionTypeDefaultDescription
trackUserInteractionsbooleantrueAuto-collect clicks and user actions
trackResourcesbooleantrueCollect XHR / Fetch resource events
trackLongTasksbooleantrueCollect long task events (>50ms)
trackViewsManuallybooleanfalseDisable automatic view creation (SPA manual control)
trackBfcacheViewsbooleanfalseCreate separate views for back/forward cache restores
trackEarlyRequestsbooleanfalseCapture requests made before SDK initialises
trackAnonymousUserbooleantrueTrack anonymous user identity and extend cookie expiration
actionNameAttributestringHTML attribute used to name actions (e.g. data-action-name)
excludedActivityUrlsMatchOption[]Request URLs to ignore for page activity calculation
firstPartyDomainsMatchOption[]Additional domains to treat as first-party in resource classification
allowedTracingUrlsArray<MatchOption | TracingOption>URLs to inject distributed trace headers into
allowedGraphQlUrlsArray<MatchOption | GraphQlUrlOption>GraphQL endpoints to track with operation metadata
trackFeatureFlagsForEventsFeatureFlagsForEvents[][]Attach feature flag evaluations to these event types
allowUntrustedEventsbooleanfalseListen to programmatically dispatched DOM events (useful in automated test environments)
allowedTrackingOriginsMatchOption[]Origins where the SDK is allowed to run (browser extension use)

Session Replay & Privacy

OptionTypeDefaultDescription
sessionReplaySampleRatenumber0Percentage of sessions to record (0–100)
startSessionReplayRecordingManuallybooleanfalse if sessionReplaySampleRate > 0, else trueStart recording only when startSessionReplayRecording() is called
defaultPrivacyLevel'mask' | 'mask-user-input' | 'allow''mask'Default text masking level for session replay
enablePrivacyForActionNamebooleanfalseMask action names in session replay
subdomainstringCustom subdomain for session replay share links
trackingConsent'granted' | 'not-granted''granted'Initial user tracking consent state

defaultPrivacyLevel values

ValueBehaviour
'mask'All text content and form inputs are replaced with xxx. Static and dynamic text is hidden.
'mask-user-input'Only form inputs (<input>, <textarea>, <select>) are masked. Static text is visible.
'allow'Nothing is masked. All content is recorded as-is.

Override the privacy level on individual HTML elements using the data-ks-privacy attribute:

<!-- Force mask a specific element even when the global level is 'allow' -->
<div data-ks-privacy="mask">Card number: 4111 1111 1111 1111</div>

<!-- Allow a specific element even when the global level is 'mask' -->
<h1 data-ks-privacy="allow">Welcome to the Dashboard</h1>

<!-- Mask only user input within this container -->
<form data-ks-privacy="mask-user-input">
  <input type="text" placeholder="Name" />
</form>

Distributed Tracing

OptionTypeDefaultDescription
traceSampleRatenumber100Percentage of requests to trace (0–100)
traceContextInjection'sampled' | 'tracecontext''sampled'When to inject trace context into requests
propagateTraceBaggagebooleanfalseInclude user/account IDs in the W3C baggage header

Performance & Transport

OptionTypeDefaultDescription
profilingSampleRatenumber0Percentage of users to profile (0–100)
compressIntakeRequestsbooleanfalseCompress payloads sent to the intake (requires workerUrl)
workerUrlstringURL to the SDK Web Worker file (same origin required)
proxystring | functionProxy URL or function to route SDK requests through a custom endpoint

Session Persistence & Cookies

OptionTypeDefaultDescription
sessionPersistence'cookie' | 'local-storage''cookie'Storage strategy for sessions
useSecureSessionCookiebooleanfalseRestrict session cookie to HTTPS connections only
usePartitionedCrossSiteSessionCookiebooleanfalseUse a partitioned cross-site cookie — required when the SDK runs inside an iframe on another domain
trackSessionAcrossSubdomainsbooleanfalseShare the session across all subdomains of the same site
storeContextsAcrossPagesbooleanfalsePersist global context and user context in localStorage across page navigations

note: sessionPersistence, useSecureSessionCookie, usePartitionedCrossSiteSessionCookie, and trackSessionAcrossSubdomains must be set to identical values if you use both the RUM and Logs SDKs on the same page.

Other Options

OptionTypeDefaultDescription
silentMultipleInitbooleanfalseSuppress the error when init() is called more than once on the same page

firstPartyDomains — Detailed

By default, only the current page's hostname is classified as "first-party" in resource and trace attribution. Use firstPartyDomains to declare additional origins you own so they are correctly attributed instead of appearing as third-party.

Accepts strings (exact hostname), regular expressions, or functions:

kubesenseSdk.init({
  // ...
  firstPartyDomains: [
    'api.myapp.com',                        // exact hostname
    /\.myapp\.com$/,                        // all subdomains of myapp.com
    (host) => host.endsWith('.internal'),   // function — matches *.internal
  ],
})

With this configuration, requests to api.myapp.com, cdn.myapp.com, or payments.internal are classified as first-party resources, and distributed trace headers are automatically injected if those origins also appear in allowedTracingUrls.

Callbacks & Plugins

OptionTypeDescription
beforeSend(event, context) => booleanInspect, modify, or discard events before sending. Return false to drop (not applicable to view events).
pluginsRumPlugin[]SDK plugin extensions

beforeSend example — drop health-check errors

kubesenseSdk.init({
  // ...
  beforeSend: (event) => {
    if (event.type === 'error' && event.error.message.includes('health-check')) {
      return false // drop this event
    }
    return true
  },
})

beforeSend example — enrich resource events

kubesenseSdk.init({
  // ...
  beforeSend: (event) => {
    if (event.type === 'resource' && event.resource.url.includes('/api/graphql')) {
      event.context.graphql_operation = getGraphQlOperation(event.resource.url)
    }
    return true
  },
})

5. View Tracking

A view represents a page or screen the user is on. The SDK creates views automatically on URL changes. For Single-Page Apps with custom routing, you may want manual control.

Automatic (default)

Views are created automatically on every history.pushState or hashchange. No code needed.

Manual View Control (SPA)

Set trackViewsManually: true in init(), then call startView() on each route change.

// React Router example
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { kubesenseSdk } from '@kubesense/kubesense-browser-rum'

function RouteTracker() {
  const location = useLocation()

  useEffect(() => {
    kubesenseSdk.startView({ name: location.pathname })
  }, [location])

  return null
}
// Vue Router example
router.afterEach((to) => {
  kubesenseSdk.startView({ name: to.name ?? to.path })
})

View API

// Start a new view with a name
kubesenseSdk.startView('checkout')

// Start with full options (name, service, version)
kubesenseSdk.startView({ name: 'checkout', service: 'payments', version: '2.1.0' })

// Change the name of the current view after it started
kubesenseSdk.setViewName('checkout-confirmation')

// Attach context to the current view only
kubesenseSdk.setViewContext({ cart_id: 'abc123', item_count: 3 })
kubesenseSdk.setViewContextProperty('experiment_variant', 'B')

// Read current view context
const ctx = kubesenseSdk.getViewContext()

6. User Context

Attach user identity to all events. Call this after login or session restore.

// Set user (id is required)
kubesenseSdk.setUser({
  id: 'usr-1234',
  name: 'Jane Smith',
  email: 'jane@example.com',
  // Any custom properties:
  plan: 'enterprise',
  role: 'admin',
})

// Update a single property
kubesenseSdk.setUserProperty('plan', 'pro')

// Read current user
const user = kubesenseSdk.getUser()

// Remove a property
kubesenseSdk.removeUserProperty('role')

// Clear on logout
kubesenseSdk.clearUser()

note: Calling setUser() with a different id automatically expires the current session to prevent cross-user data contamination on shared devices.


7. Account Context

Attach account/organization information to all events (useful for B2B applications).

kubesenseSdk.setAccount({
  id: 'acct-5678',
  name: 'Acme Corp',
  plan: 'enterprise',
})

// Update a single property
kubesenseSdk.setAccountProperty('plan', 'enterprise-plus')

// Read current account
const account = kubesenseSdk.getAccount()

// Remove a property
kubesenseSdk.removeAccountProperty('plan')

// Clear
kubesenseSdk.clearAccount()

8. Error Tracking

Automatic Error Collection

The SDK automatically captures:

  • Unhandled JavaScript exceptions (window.onerror)
  • Unhandled promise rejections
  • Console errors (console.error)
  • Network errors (for tracked resource URLs)

No code needed for these.

Manual Error Reporting

Report handled errors you catch yourself:

try {
  processPayment(order)
} catch (error) {
  kubesenseSdk.addError(error, {
    order_id: order.id,
    amount: order.total,
  })
}
// Report a plain string
kubesenseSdk.addError('Payment failed: insufficient funds', {
  user_id: currentUser.id,
})

React Error Boundary

import { Component } from 'react'
import { kubesenseSdk } from '@kubesense/kubesense-browser-rum'

class ErrorBoundary extends Component {
  componentDidCatch(error: Error, info: React.ErrorInfo) {
    kubesenseSdk.addError(error, {
      component_stack: info.componentStack,
    })
  }

  render() {
    return this.props.children
  }
}

9. Action Tracking

Automatic Action Collection

When trackUserInteractions: true (default), the SDK automatically tracks clicks and names them from:

  1. The element's data-action-name attribute (configure via actionNameAttribute)
  2. The element's aria-label, title, or alt attribute
  3. The element's inner text (truncated)

Custom Actions

// Track a programmatic or non-click action
kubesenseSdk.addAction('export_csv', {
  row_count: 1500,
  format: 'csv',
})

kubesenseSdk.addAction('search', {
  query: searchTerm,
  results_count: results.length,
})

Naming Clicks via HTML Attribute

<!-- Using default attribute (data-action-name) -->
<button data-action-name="Add to cart">+</button>

<!-- Using a custom attribute configured at init -->
<!-- kubesenseSdk.init({ actionNameAttribute: 'data-rum-action' }) -->
<button data-rum-action="checkout">Buy Now</button>

10. Resource & Long Task Tracking

Both are enabled by default. No code needed.

kubesenseSdk.init({
  trackResources: true,  // default: true
  trackLongTasks: true,  // default: true
})

To stop collecting resources or long tasks entirely:

kubesenseSdk.init({
  trackResources: false,
  trackLongTasks: false,
})

11. Custom Timings & Performance Vitals

Custom View Timings

Mark key moments within the current view (e.g. "time to data loaded"):

// After data is fetched and rendered
kubesenseSdk.addTiming('data_ready')

// Pass an explicit timestamp (ms since page load)
kubesenseSdk.addTiming('hero_image_loaded', performance.now())

Timings appear in the view event under view.custom_timings.

Duration Vitals

Measure elapsed time for arbitrary operations:

// Option 1: start / stop
const ref = kubesenseSdk.startDurationVital('checkout_flow')
// ... user completes checkout ...
kubesenseSdk.stopDurationVital(ref, {
  context: { steps_completed: 4 },
})

// Option 2: start by name and stop by name
kubesenseSdk.startDurationVital('report_generation')
generateReport().then(() => {
  kubesenseSdk.stopDurationVital('report_generation')
})

// Option 3: add a completed vital with known start/duration
kubesenseSdk.addDurationVital('pdf_render', {
  startTime: renderStartTime,
  duration: renderDuration,
  context: { page_count: 12 },
})

12. Feature Operations

Track multi-step operations (e.g. checkout flows, onboarding) as a series of steps with pass/fail outcomes.

// Start tracking a named operation
kubesenseSdk.startFeatureOperation('onboarding', {
  context: { step: 'profile_setup' },
})

// Mark succeeded
kubesenseSdk.succeedFeatureOperation('onboarding', {
  context: { steps_completed: 3 },
})

// Mark failed with a reason
kubesenseSdk.failFeatureOperation('onboarding', 'profile_incomplete', {
  context: { missing_fields: ['phone'] },
})

13. Global Context

Attach custom properties to every event (views, errors, resources, actions).

// Set at startup
kubesenseSdk.setGlobalContext({
  deployment_region: 'us-east-1',
  feature_set: 'beta',
})

// Add or update a single property at any time
kubesenseSdk.setGlobalContextProperty('ab_test_group', 'variant_B')

// Read current context
const ctx = kubesenseSdk.getGlobalContext()

// Remove one property
kubesenseSdk.removeGlobalContextProperty('feature_set')

// Clear everything
kubesenseSdk.clearGlobalContext()

14. Session Replay

Session Replay records the user's screen so you can replay exactly what happened around an error or frustration signal.

Enable Replay

kubesenseSdk.init({
  // ...
  sessionReplaySampleRate: 20, // record 20% of sessions
})

Manual Recording Control

kubesenseSdk.init({
  // ...
  sessionReplaySampleRate: 100,
  startSessionReplayRecordingManually: true, // don't start automatically
})

// Start recording only for important flows (e.g. after login)
function onUserLoggedIn() {
  kubesenseSdk.startSessionReplayRecording()
}

// Stop recording when leaving a sensitive screen
function onEnterPaymentPage() {
  kubesenseSdk.stopSessionReplayRecording()
}

Privacy Masking

kubesenseSdk.init({
  defaultPrivacyLevel: 'mask-user-input', // 'mask' | 'mask-user-input' | 'allow'
})
LevelBehaviour
maskAll text and inputs are masked (default)
mask-user-inputOnly form inputs are masked; static text is visible
allowNothing is masked

Override per element:

<!-- Force masking an element -->
<div data-ks-privacy="mask">Sensitive data</div>

<!-- Allow a specific element in a masked view -->
<p data-ks-privacy="allow">Public content</p>
const replayUrl = kubesenseSdk.getSessionReplayLink()
// Share or store this URL to view the recording later

15. Distributed Tracing

Correlate frontend RUM events with backend traces by injecting trace headers into outgoing requests.

kubesenseSdk.init({
  // ...
  allowedTracingUrls: [
    'https://api.example.com',               // exact origin
    /https:\/\/.*\.example\.com/,            // regex
    (url) => url.startsWith('https://api.'), // function
  ],
  traceSampleRate: 100, // trace 100% of allowed requests
})

Custom Propagator Format

kubesenseSdk.init({
  allowedTracingUrls: [
    {
      match: 'https://api.example.com',
      propagatorTypes: ['tracecontext', 'kubesense'], // W3C + Kubesense headers
    },
  ],
})

Propagate User/Account in Baggage

kubesenseSdk.init({
  propagateTraceBaggage: true, // includes user.id and account.id in the baggage header
})

If you require explicit consent before collecting data (e.g. GDPR):

kubesenseSdk.init({
  // ...
  trackingConsent: 'not-granted', // start with no collection
})

// After user accepts your consent banner:
kubesenseSdk.setTrackingConsent('granted')

// If user withdraws consent:
kubesenseSdk.setTrackingConsent('not-granted')

Stop a Session

kubesenseSdk.stopSession()
// No new events collected until next page load or user activity

17. Feature Flag Tracking

Track which feature flags were evaluated during a session or action:

// After evaluating a flag
const flagValue = featureFlags.get('new_checkout')
kubesenseSdk.addFeatureFlagEvaluation('new_checkout', flagValue)

To attach flag evaluations to specific event types, configure at init:

kubesenseSdk.init({
  trackFeatureFlagsForEvents: ['action', 'vital', 'long_task', 'resource'],
})

18. GraphQL Tracking

Track GraphQL requests with operation metadata:

kubesenseSdk.init({
  allowedGraphQlUrls: [
    {
      match: 'https://api.example.com/graphql',
      trackPayload: false,       // don't capture request body
      trackResponseErrors: true, // capture GraphQL errors in response
    },
  ],
})

19. TypeScript Support

The SDK ships full TypeScript types. Import them directly:

import type {
  RumInitConfiguration,
  RumEvent,
  RumEventDomainContext,
} from '@kubesense/kubesense-browser-rum'

const config: RumInitConfiguration = {
  applicationId: '<YOUR_APPLICATION_ID>',
  clientToken: '<YOUR_CLIENT_TOKEN>',
  service: 'my-app',
  env: 'production',
  beforeSend: (event: RumEvent, context: RumEventDomainContext): boolean => {
    // type-safe access to event fields
    return true
  },
}

Quick Reference

// Initialization
kubesenseSdk.init({ applicationId, clientToken, /* ... */ })

// Views
kubesenseSdk.startView(name)
kubesenseSdk.setViewName(name)
kubesenseSdk.setViewContext(context)
kubesenseSdk.setViewContextProperty(key, value)

// User & Account
kubesenseSdk.setUser({ id, name, email, /* ...custom */ })
kubesenseSdk.clearUser()
kubesenseSdk.setAccount({ id, name, /* ...custom */ })
kubesenseSdk.clearAccount()

// Global Context
kubesenseSdk.setGlobalContext(context)
kubesenseSdk.setGlobalContextProperty(key, value)
kubesenseSdk.clearGlobalContext()

// Errors & Actions
kubesenseSdk.addError(error, context)
kubesenseSdk.addAction(name, context)

// Timings & Vitals
kubesenseSdk.addTiming(name)
kubesenseSdk.startDurationVital(name)
kubesenseSdk.stopDurationVital(nameOrRef)

// Session Replay
kubesenseSdk.startSessionReplayRecording()
kubesenseSdk.stopSessionReplayRecording()
kubesenseSdk.getSessionReplayLink()

// Consent
kubesenseSdk.setTrackingConsent('granted' | 'not-granted')
kubesenseSdk.stopSession()