A client-side singleton that handles device IDs, sessions, and delivery automatically. No user ID needed on track calls.
No cookies. No IP addresses. No cross-site tracking. Visitors are identified by a random device UUID stored in localStorage. The SDK collects anonymous device metadata only — you choose what properties to send. See Audit & Privacy for the full privacy model.
Quick start
Events called before configure() are queued and replayed once ready.
Verify it works
Open your browser’s DevTools Network tab and look for a POST request to https://collect.tell.app/v1/events. If you see a 202 response, the SDK is sending data successfully. In development mode, the SDK also logs to the console at debug level.
Script tag (no bundler)
If you don’t use a bundler, load the SDK directly from a CDN. The global build exposes a Tell object on window.
All configuration options, tracking methods, and privacy controls work the same as the npm install — only the loading mechanism differs.
SPA page view tracking
For single-page apps without a framework router, hook into the History API to track navigations:
Pin a version
Replace @latest with a specific version to avoid unexpected changes in production:
Configuration
For local development, point the SDK at your Tell server:
Tracking events
No user ID parameter — the SDK tracks the current user automatically (anonymous until you call identify). For a full explanation of the identity model (device ID, anonymous ID, user ID), see Users & Identity.
For details on each event type and when to use them, see Events & Properties.
Standard event names
Constants cover user lifecycle, revenue, subscriptions, trials, shopping, engagement, and communication events. Custom string names always work too.
Super properties
Properties automatically attached to every track, group, and revenue call:
Event-specific properties override super properties when keys conflict. See Events & Properties for more on property patterns.
Structured logging
Nine severity levels from logEmergency to logTrace. See Logs for the full level reference and when to use each.
Sessions
Sessions are managed automatically. The session ID is persisted to localStorage, so page navigations within the same site continue the same session. A new session starts after 30 minutes of inactivity (configurable via sessionTimeout) or after 24 hours (configurable via maxSessionLength). The SDK also captures UTM parameters from the URL as super properties.
For the full session lifecycle model, see Sessions.
Data collected automatically
The browser SDK captures device context on every session. No PII is collected — all fields are anonymous device and browser metadata.
URLs include query strings. If your app puts tokens or sensitive data in URLs (e.g. ?token=abc), use beforeSend or the redact() utility below to strip them before events leave the browser.
Redaction & beforeSend
The beforeSend hook lets you transform or drop events before they’re queued. Return the modified event, or null to drop it entirely.
Drop events from routes
Strip query params from URLs
Remove PII from properties
Scrub log data
User opt-out via beforeSend
redact() utility
For common redaction patterns, use the built-in redact() factory instead of writing beforeSend by hand:
redact() and redactLog() return standard beforeSend functions. You can combine them with your own in an array:
Client-side redaction is your first line of defense. For defense in depth, also configure server-side pipeline redaction to catch anything that slips through.
Error auto-capture
Set captureErrors: true to automatically log uncaught errors and unhandled promise rejections.
What it captures
window.onerror — uncaught exceptions:
message — the error message
filename — source file URL
lineno / colno — line and column number
stack — stack trace (when available)
unhandledrejection — unhandled promise rejections:
message — the rejection reason (or "Unhandled promise rejection")
stack — stack trace (when the reason is an Error)
Both are logged via logError with service "browser" and appear in your Tell logs dashboard.
When to use vs. your own error boundary
captureErrors is a catch-all safety net for errors that escape your application code. If you use React error boundaries or framework error handlers, you may prefer to log to Tell explicitly from those:
Privacy
Opt-out state is persisted to localStorage. Set respectDoNotTrack: true to honor the browser’s Do Not Track setting.
Lifecycle
Error handling
Tracking calls (track, identify, group, revenue, alias) never throw. Validation errors and network failures route through the onError callback:
Retry behavior
On HTTP send failure (5xx or network error), the SDK retries with exponential backoff: 1-second base delay, 1.5x multiplier, 20% jitter, capped at 30 seconds. After maxRetries attempts (default: 5), the batch is dropped and reported via onError.
The SDK also checks navigator.onLine before each attempt and skips if the browser reports offline.
Browser-specific features
Bot detection — automatically disables tracking when navigator.webdriver is set or the user agent contains “headless”. Controlled by botDetection (default: true).
Page unload — the SDK flushes via navigator.sendBeacon on beforeunload and visibilitychange to minimize data loss.
Pre-init queue — events called before configure() are buffered (up to 1,000) and replayed once the SDK is ready.
Configuration reference