@bricksworks/sdk
v0.4.1
Published
Browser SDK for AI-interpretable event tracking and retention
Maintainers
Readme
@bricksworks/sdk
Browser SDK for AI-interpretable event tracking and session recording.
Features
- Click Tracking - Capture user clicks with element fingerprinting
- Form Tracking - Track form submissions (without field values for privacy)
- Navigation Tracking - Monitor page navigation including SPA transitions
- Session Recording - Record DOM state for replay
- Exception Capture - Track unhandled errors and promise rejections
- Network Error Capture - Monitor failed HTTP requests (4xx, 5xx, network failures)
- Rage Click Detection - Detect frustrated rapid clicking on the same element
- Dead Click Detection - Find broken UI elements that don't respond to clicks
- Element Fingerprinting - Reliable element identification in minified React apps
- React Integration - First-class React provider and hooks
- Privacy-First - No field values captured by default
Installation
npm install @bricksworks/sdk
# or
pnpm add @bricksworks/sdk
# or
yarn add @bricksworks/sdkQuick Start
import { createBricks } from '@bricksworks/sdk';
const sdk = createBricks({
apiKey: 'your-workspace-api-key',
});
sdk.start();
// After user logs in, identify them
sdk.identify('user-123', {
email: '[email protected]',
name: 'John Doe',
});That's it! The SDK automatically tracks clicks, forms, navigation, and records sessions.
User Identification
Important: Call identify() after your user logs in to link their session to their identity. This enables personalized AI insights and cross-session tracking.
// Basic identification with user ID and traits
sdk.identify('user-123', {
email: '[email protected]',
name: 'John Doe',
});
// With additional business context
sdk.identify('user-123', {
email: '[email protected]',
name: 'John Doe',
plan: 'pro',
company: 'Acme Inc',
role: 'admin',
});
// Anonymous traits (no user ID)
sdk.identify({
email: '[email protected]',
});When to Call Identify
- After login - As soon as you know who the user is
- After signup - Link the new user to their browsing session
- On page load - If user is already authenticated, identify them immediately
// Example: React login flow
async function handleLogin(credentials) {
const user = await api.login(credentials);
// Identify user after successful login
sdk.identify(user.id, {
email: user.email,
name: user.name,
plan: user.subscription.plan,
});
}Full Example
import { createBricks } from '@bricksworks/sdk';
const sdk = createBricks({
apiKey: 'your-workspace-api-key',
});
sdk.start();
// Identify user after login
sdk.identify({
externalId: 'user-123',
email: '[email protected]',
plan: 'pro',
});
// Complete session when user finishes (e.g., checkout complete)
await sdk.complete();React Integration
For React applications, use the provider and hook for a more idiomatic experience:
Setup
import { BricksProvider } from '@bricksworks/sdk/react';
import { ENDPOINTS } from '@bricksworks/sdk';
function App() {
return (
<BricksProvider
apiKey="your-workspace-api-key"
endpoint={ENDPOINTS.local} // optional, defaults to production
debug={true} // optional
>
<YourApp />
</BricksProvider>
);
}Using the Hook
import { useBricks } from '@bricksworks/sdk/react';
function UserProfile({ userId }) {
const bricks = useBricks();
useEffect(() => {
bricks.identify({ externalId: userId });
}, [userId]);
return <div>...</div>;
}Provider Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| apiKey | string | required | Your workspace API key |
| endpoint | string | production | Backend URL |
| debug | boolean | false | Enable debug logging |
| compression | boolean | true | Gzip compress payloads |
| sessionTimeout | number | 30 min | Session timeout in ms |
| plugins | object | all enabled | Plugin configuration |
| onError | function | - | Error callback |
| fallback | ReactNode | - | Error boundary fallback |
Requirements
- React 16.8+ (hooks support required)
- React is an optional peer dependency (not required for vanilla JS usage)
SSR Considerations
The React provider is client-only. For SSR frameworks like Next.js:
// Next.js App Router - mark as client component
'use client';
import { BricksProvider } from '@bricksworks/sdk/react';
export function Providers({ children }) {
return (
<BricksProvider apiKey="your-api-key">
{children}
</BricksProvider>
);
}// Next.js Pages Router - use dynamic import
import dynamic from 'next/dynamic';
const BricksProvider = dynamic(
() => import('@bricksworks/sdk/react').then((mod) => mod.BricksProvider),
{ ssr: false }
);Configuration
createBricks(config)
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiKey | string | required | Your workspace API key |
| endpoint | string | production | Backend URL (use ENDPOINTS.local for dev) |
| debug | boolean | false | Enable debug logging to console |
| compression | boolean | true | Gzip compress payloads |
| sessionTimeout | number | 30 min | Session timeout in milliseconds |
Endpoints
import { createBricks, ENDPOINTS } from '@bricksworks/sdk';
// Production (default)
createBricks({ apiKey: '...' });
// Local development
createBricks({
apiKey: '...',
endpoint: ENDPOINTS.local,
});Plugins
All plugins are enabled by default. You can disable or configure individual plugins:
const sdk = createBricks({
apiKey: 'your-api-key',
plugins: {
// Disable a plugin
recording: false,
// Configure a plugin
deadClick: {
waitTimeMs: 3000,
ignoreSelectors: ['.no-dead-click'],
},
},
});Available Plugins
| Plugin | Description | Default |
|--------|-------------|---------|
| recording | Session recording with rrweb | enabled |
| clickCapture | Click event tracking | enabled |
| formCapture | Form submission tracking | enabled |
| navigationCapture | Page navigation tracking | enabled |
| exceptionCapture | Unhandled error tracking | enabled |
| networkErrorCapture | Failed HTTP request tracking | enabled |
| rageClick | Rapid click detection | enabled |
| deadClick | Unresponsive element detection | enabled |
| performance | Performance metrics | enabled |
Plugin Options
recording
plugins: {
recording: {
blockSelector: '.sensitive', // CSS selector for elements to block
maskInputSelector: 'input[type="password"]',
maskAllInputs: true, // Mask all input values (default: true)
},
}deadClick
Detects clicks on interactive elements (buttons, links, etc.) that don't cause any DOM changes within a timeout period. Uses MutationObserver to watch for DOM mutations after clicks.
plugins: {
deadClick: {
waitTimeMs: 2500, // Time to wait for DOM mutation (default: 2500ms)
ignoreSelectors: ['.external'], // CSS selectors to ignore
},
}How it works:
- User clicks an interactive element (button, link, element with
role="button", etc.) - SDK watches for any DOM changes using MutationObserver
- If no changes occur within
waitTimeMs, it's flagged as a dead click - Links that navigate away and clicks with modifier keys (Ctrl, etc.) are ignored
rageClick
Detects rapid, frustrated clicking on the same element.
plugins: {
rageClick: {
clickThreshold: 3, // Clicks needed to trigger (default: 3)
timeWindowMs: 1000, // Time window in ms (default: 1000)
radiusPixels: 30, // Max distance between clicks (default: 30)
},
}networkErrorCapture
Tracks failed HTTP requests from both fetch and XMLHttpRequest.
plugins: {
networkErrorCapture: {
urlPatterns: ['/api/'], // Only track URLs matching these patterns
minStatus: 400, // Minimum status code to capture (default: 400)
captureNetworkFailures: true, // Capture network failures (default: true)
},
}exceptionCapture
Tracks unhandled errors and promise rejections.
plugins: {
exceptionCapture: {
captureUnhandledErrors: true, // Capture window.onerror (default: true)
captureUnhandledRejections: true, // Capture unhandledrejection (default: true)
},
}SDK Methods
.start()
Start capturing events.
sdk.start();.stop()
Stop capturing events.
sdk.stop();.identify(params)
Identify the current user. Call after login.
sdk.identify({
externalId: 'user-123', // Your user ID
email: '[email protected]',
name: 'John Doe',
plan: 'pro',
company: 'Acme Inc',
});
// Or just traits without externalId
sdk.identify({ email: '[email protected]' });.flush()
Force send any buffered events immediately.
await sdk.flush();.complete()
Complete the session and notify the backend. Call when the user completes their journey (e.g., after checkout).
await sdk.complete();.resetSession()
Start a new session. Returns the new session ID.
const newSessionId = sdk.resetSession();.getSessionId()
Get the current session ID.
const sessionId = sdk.getSessionId();.destroy()
Completely destroy the SDK and release all resources.
sdk.destroy();Element Fingerprinting
The SDK uses multi-layer element identification to reliably track elements even in minified React applications:
- Data attributes (priority):
data-testid,data-analytics-id - ARIA:
aria-label,aria-labelledby - Semantics:
id,name,href,type - Content: element text
- Structure: DOM path
Tip: Add data-testid attributes to important elements for the most reliable tracking:
<button data-testid="checkout-button">Complete Purchase</button>TypeScript Support
Full TypeScript support with exported types:
import type { BricksConfig, BricksInstance } from '@bricksworks/sdk';
// React types
import type { BricksProviderProps, BricksContextValue } from '@bricksworks/sdk/react';Browser Support
- Chrome 80+
- Firefox 78+
- Safari 14+
- Edge 80+
Bundle Size
~150KB gzipped (includes session recording capabilities)
License
MIT
