SDK Guide

Integrate Bandit into any JavaScript or TypeScript application in minutes.

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.

OptionTypeDefaultDescription
apiUrlstringrequiredYour API base URL
apiKeystringrequiredYour API key (from dashboard)
timeoutnumber5000Request timeout in ms
batchSizenumber100Max events per batch
flushIntervalnumber10000Auto-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

NameTypeRequiredDescription
experimentIdstringrequiredThe experiment to get an assignment for
userIdstringrequiredUnique identifier for the user
contextContextualFeaturesoptionalOptional 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

NameTypeRequiredDescription
assignmentIdstringrequiredThe assignmentId returned from getAssignment()
eventTypeEventTyperequiredASSIGNMENT | CONVERSION | CLICK | VIEW | CUSTOM
valuenumberoptionalNumeric value for the event (e.g. revenue amount)
metadataRecord<string, any>optionalArbitrary 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.

Deprecated: Prefer trackEvent() with an assignmentId for precise attribution. The legacy method can misattribute events when a user participates in multiple experiments simultaneously.

Parameters

NameTypeRequiredDescription
experimentIdstringrequiredThe experiment ID
treatmentIdstringrequiredThe treatment ID shown to the user
userIdstringrequiredThe user ID
eventTypeEventTypeoptionalDefaults to CONVERSION
valuenumberoptionalNumeric value for the event
metadataRecord<string, any>optionalArbitrary 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.

ASSIGNMENT

Automatically created when getAssignment() is called. You should not track this type manually.

CONVERSION

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.

CLICK

Track when a user clicks on the treatment variant. Useful for measuring engagement with CTAs, buttons, or links.

VIEW

Track when a user sees or views the treatment variant. Useful for measuring impressions and calculating click-through or conversion rates.

CUSTOM

Track any custom event that doesn't fit the predefined types. Use metadata to add context about the specific action.

Best Practices

1

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.

2

Clean up on unmount

Call destroy() when your component or application unmounts. This stops the auto-flush timer and sends any remaining queued events.

3

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.

4

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.