SDK Reference
JavaScript SDK for event tracking and identity resolution
Installation
npm install @retivo/sdk
# or
pnpm add @retivo/sdk
# or
yarn add @retivo/sdkThe SDK ships as ESM and CJS with full TypeScript types.
Quick Start
import { Retivo } from '@retivo/sdk'
const retivo = new Retivo({ apiKey: 'rt_live_...' })
retivo.identify('user-123', { name: 'Jane', plan: 'pro' })
retivo.track('feature_used', { feature: 'ai-sprint-planner' })End-to-End Example
A complete working integration that identifies a user, tracks events, and listens for real-time interventions:
import { Retivo } from '@retivo/sdk'
const retivo = new Retivo({
apiKey: import.meta.env.VITE_RETIVO_API_KEY,
})
// 1. Identify the user after login
retivo.identify('user-123', {
name: 'Jane Smith',
email: 'jane@example.com',
plan: 'pro',
company: 'Acme Inc',
})
// 2. Track meaningful product events
retivo.track('onboarding_step_completed', { step: 'invite_team' })
retivo.track('feature_used', { feature: 'ai-sprint-planner' })
// 3. Listen for real-time in-app messages
const unsubscribe = retivo.onMessage((message) => {
showToast({
title: message.playbookName,
body: message.body,
})
})
// On logout or unmount
function cleanup() {
unsubscribe()
retivo.reset()
}Constructor
new Retivo(options: RetevoOptions)| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | required | Your API key (rt_live_... or rt_test_...) |
baseURL | string | https://retivo.ai | API base URL |
flushInterval | number | 1000 | Batch flush interval in milliseconds |
maxBatchSize | number | 10 | Max events per batch |
Methods
identify(userId, traits?)
Set the current user identity. Must be called before track().
retivo.identify('user-123', {
name: 'Jane Smith',
email: 'jane@example.com',
company: 'Acme Inc',
plan: 'pro',
team_size: 8,
})userId— Unique identifier for the user in your systemtraits— Optional key-value properties stored on the user profile
Calling identify() sends a special $identify event and stores the userId for subsequent track() calls.
track(event, properties?)
Track a user event.
retivo.track('project_created', {
projectName: 'Q1 Roadmap',
templateUsed: true,
})event— Event name (processed by Retivo)properties— Optional event properties
Events are batched and flushed automatically. Each event gets an ISO timestamp and idempotency key.
onMessage(handler)
Register a callback for real-time in-app intervention messages via SSE.
const unsubscribe = retivo.onMessage((message) => {
console.log(message.body) // "Try our new AI sprint planner!"
console.log(message.type) // "in_app"
console.log(message.playbookName) // "Feature Adoption Nudge"
})
// Later: stop listening
unsubscribe()The handler receives a WidgetMessage object:
| Field | Type | Description |
|---|---|---|
interventionId | string | Unique intervention ID |
type | string | Message type (in_app) |
body | string | The personalized message text |
playbookName | string | Name of the triggering playbook |
timestamp | string | ISO timestamp |
reset()
Clear the current user identity, flush pending events, and disconnect SSE. Use this on logout or when switching users.
retivo.reset()
// userId is now null — call identify() again for the new usersetLocale(locale)
Set the user's locale for i18n-aware interventions. Sends a $locale event to Retivo so messages can be localized.
retivo.setLocale('fr-FR')Must be called after identify(). The locale is included in the user context sent to the LLM during message generation.
debug(enabled?)
Enable or disable debug logging to the browser console. Useful during development.
retivo.debug() // enable
retivo.debug(false) // disableWhen enabled, all SDK calls (identify, track, reset, setLocale) are logged with their arguments.
getUser()
Returns the current user identity, or null if not identified.
const user = retivo.getUser()
// { userId: 'user-123', traits: { name: 'Jane', plan: 'pro' }, locale: 'en-US' }
if (!user) {
console.log('No user identified')
}destroy()
Flush pending events and disconnect SSE.
await retivo.destroy()Call this on page unload or when the SDK is no longer needed.
Event Naming Conventions
Use consistent, descriptive event names so Retivo can accurately score activation and match playbooks.
Use snake_case for all event names. This keeps events uniform across your codebase and readable in the Retivo dashboard.
Recommended patterns:
| Pattern | Example | When to use |
|---|---|---|
feature_used | feature_used | User engages with a core product feature |
<noun>_<past_verb> | project_created, report_exported | User completes a discrete action |
<flow>_step_completed | onboarding_step_completed | User progresses through a multi-step flow |
<noun>_<state> | trial_started, subscription_upgraded | Lifecycle or billing state changes |
Events by Lifecycle Area
Different lifecycle areas rely on different event types. Here are the key events for each area:
| Area | Key Events | Purpose |
|---|---|---|
| Onboarding | onboarding_step_completed, feature_used, invite_sent | Track progress toward first value |
| Churn Prevention | subscription_cancelled, usage_dropped, support_ticket_created | Detect disengagement signals |
| Retention | feature_used, milestone_reached, streak_continued | Measure ongoing engagement depth |
| Upsell | plan_limit.approaching, feature_gate.hit, usage_threshold_crossed | Identify expansion readiness |
| Win-back | page_viewed (from returning users), reactivation_started | Detect returning churned users |
The feature_gate.hit event is particularly important for upsell detection — track it whenever a user attempts to use a feature they don't have access to on their current plan.
Why this matters: Retivo uses event names for two things:
- Activation scoring — events are matched against activation milestones to compute health scores. Inconsistent names (e.g.,
createProjectvsproject_created) fragment your signals. - Playbook matching — playbook triggers reference event names directly. A playbook targeting
feature_usedwill not fire onfeatureUsed.
Avoid generic names like click or action. Include enough context in the event name itself so it is meaningful without inspecting properties.
Common Integration Patterns
SPA Route Tracking
Track page views on client-side route changes. Useful for understanding navigation patterns and drop-off points.
import { useEffect } from 'react'
import { useLocation } from 'react-router-dom'
function useRouteTracking(retivo: Retivo) {
const location = useLocation()
useEffect(() => {
retivo.track('page_viewed', {
path: location.pathname,
search: location.search,
})
}, [location.pathname])
}Form Submission Tracking
Capture form completions with relevant metadata. Pair with onboarding_step_completed for multi-step flows.
async function handleFormSubmit(data: FormData) {
await api.submitOnboardingProfile(data)
retivo.track('onboarding_step_completed', {
step: 'profile_setup',
fields_filled: Object.keys(data).length,
})
}Feature Adoption Tracking
Wrap key product features to measure adoption depth. This feeds directly into Retivo's activation scoring.
function trackFeatureUsage(retivo: Retivo, feature: string, metadata?: Record<string, unknown>) {
retivo.track('feature_used', {
feature,
...metadata,
})
}
// Usage throughout your app
trackFeatureUsage(retivo, 'ai-sprint-planner', { items_planned: 12 })
trackFeatureUsage(retivo, 'csv-export', { row_count: 340 })
trackFeatureUsage(retivo, 'team-invite', { invitee_count: 3 })Test Mode
API keys starting with rt_test_ put the SDK into test mode. In test mode:
- Events are tagged with
test: truemetadata - Interventions are logged but not delivered to real channels
- All data appears in the dashboard with a test mode indicator
// Development
const retivo = new Retivo({ apiKey: 'rt_test_...' })
// Production
const retivo = new Retivo({ apiKey: 'rt_live_...' })Use test keys during development and CI to avoid sending real emails or webhooks.
Event Batching
The SDK batches events to minimize HTTP requests:
- Events queue in memory
- Flushed when batch reaches
maxBatchSize(default: 10) - Or when
flushIntervalelapses (default: 1000ms) - Each batch is a single
POST /api/trackcall
This keeps latency under 1 second while preventing excessive API calls.
TypeScript
The SDK is fully typed. Import types directly:
import type { RetevoOptions, TrackEvent, MessageHandler } from '@retivo/sdk'