Installation
Install the SDK with your preferred package manager:
npm
npm install @bandit/sdk
yarn
yarn add @bandit/sdk
pnpm
pnpm add @bandit/sdk
Quick Start
Get up and running with just a few lines of code. The example below initializes the client, requests an assignment, renders the variant, and tracks a conversion event.
import { BanditClient } from '@bandit/sdk'
const bandit = new BanditClient({
apiUrl: 'https://api.yourdomain.com',
apiKey: 'your-api-key'
})
// Get the best variant for a user
const assignment = await bandit.getAssignment('experiment-id', 'user-123')
// Show the variant content
document.querySelector('#headline').textContent = assignment.config.content
// Track when they convert
bandit.trackEvent({
assignmentId: assignment.assignmentId,
eventType: 'CONVERSION',
value: 29.99
})Configuration
Pass a configuration object when creating a new BanditClient instance. Only apiUrl and apiKey are required.
| Option | Type | Default | Description |
|---|---|---|---|
| apiUrl | string | required | Your API base URL |
| apiKey | string | required | Your API key (from dashboard) |
| timeout | number | 5000 | Request timeout in ms |
| batchSize | number | 100 | Max events per batch |
| flushInterval | number | 10000 | Auto-flush interval in ms |
Methods
getAssignment(experimentId, userId, context?)
Request a treatment assignment for a user. The bandit algorithm selects the best-performing variant based on historical data. When context is provided, contextual bandit algorithms can use it for smarter decisions.
Returns: Promise<Assignment>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| experimentId | string | required | The experiment to get an assignment for |
| userId | string | required | Unique identifier for the user |
| context | ContextualFeatures | optional | Optional contextual features (device type, location, etc.) for contextual bandit algorithms |
// Basic assignment
const assignment = await bandit.getAssignment('exp-headline', 'user-123')
// With contextual features
const assignment = await bandit.getAssignment('exp-headline', 'user-123', {
deviceType: 'mobile',
location: 'US',
timeOfDay: 'evening'
})
// Assignment shape
// {
// assignmentId: "asgn_abc123",
// treatmentId: "treat_xyz",
// experimentId: "exp-headline",
// userId: "user-123",
// config: { content: "Try it free today!", color: "#4f46e5" }
// }trackEvent(event)
Track an event using assignment-based attribution. This is the recommended approach because it ties the event directly to the assignment, ensuring accurate measurement even when users see multiple experiments.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| assignmentId | string | required | The assignmentId returned from getAssignment() |
| eventType | EventType | required | ASSIGNMENT | CONVERSION | CLICK | VIEW | CUSTOM |
| value | number | optional | Numeric value for the event (e.g. revenue amount) |
| metadata | Record<string, any> | optional | Arbitrary key-value metadata to attach to the event |
// Track a conversion with revenue
bandit.trackEvent({
assignmentId: assignment.assignmentId,
eventType: 'CONVERSION',
value: 29.99,
metadata: { product: 'premium-plan' }
})
// Track a click
bandit.trackEvent({
assignmentId: assignment.assignmentId,
eventType: 'CLICK'
})
// Track a custom event
bandit.trackEvent({
assignmentId: assignment.assignmentId,
eventType: 'CUSTOM',
metadata: { action: 'added-to-cart', sku: 'WIDGET-42' }
})track(experimentId, treatmentId, userId, eventType?, value?, metadata?)
Legacy event tracking method that uses explicit IDs instead of an assignmentId. Events are queued and flushed automatically in batches.
trackEvent() with an assignmentId for precise attribution. The legacy method can misattribute events when a user participates in multiple experiments simultaneously.Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| experimentId | string | required | The experiment ID |
| treatmentId | string | required | The treatment ID shown to the user |
| userId | string | required | The user ID |
| eventType | EventType | optional | Defaults to CONVERSION |
| value | number | optional | Numeric value for the event |
| metadata | Record<string, any> | optional | Arbitrary key-value metadata |
// Legacy tracking (not recommended)
bandit.track(
'exp-headline',
'treat-a',
'user-123',
'CONVERSION',
29.99,
{ product: 'premium-plan' }
)flush()
Manually flush all queued events to the server. Events are normally sent automatically based on the batchSize and flushInterval configuration, but you can force a flush before a page unload or navigation.
Returns: Promise<void>
// Flush before the user leaves the page
window.addEventListener('beforeunload', () => {
bandit.flush()
})destroy()
Stop the auto-flush timer and flush any remaining queued events. Call this when your application unmounts or the client is no longer needed to prevent memory leaks.
Returns: void
// React cleanup example
useEffect(() => {
const client = new BanditClient({ apiUrl, apiKey })
// ... use client
return () => client.destroy()
}, [])
// SPA route change cleanup
router.beforeEach(() => {
bandit.destroy()
})Event Types
Each event has a type that determines how it is used in the optimization algorithm. Use the right event type for accurate measurement.
Automatically created when getAssignment() is called. You should not track this type manually.
The primary success metric. Track when a user completes a desired action such as a purchase, signup, or form submission. Include a value for revenue-based optimization.
Track when a user clicks on the treatment variant. Useful for measuring engagement with CTAs, buttons, or links.
Track when a user sees or views the treatment variant. Useful for measuring impressions and calculating click-through or conversion rates.
Track any custom event that doesn't fit the predefined types. Use metadata to add context about the specific action.
Best Practices
Use assignment-based tracking
Always prefer trackEvent() with an assignmentId over the legacy track() method. Assignment-based tracking prevents misattribution when users participate in multiple experiments.
Clean up on unmount
Call destroy() when your component or application unmounts. This stops the auto-flush timer and sends any remaining queued events.
Let auto-batching work
The SDK automatically batches events and flushes them at the configured interval. Avoid calling flush() after every event -- let the batch system handle it for better performance and fewer network requests.
Store the assignmentId
If a conversion can happen later (e.g. a purchase after browsing), persist the assignmentId in localStorage or your session store. This lets you track the conversion accurately even if the user returns in a different session.