User Maturity
User maturity is an automatic classification of users into behavioral segments. Instead of manually segmenting users, Presage computes maturity from behavioral signals.
Maturity Segments
Section titled “Maturity Segments”| Segment | Description | Default threshold |
|---|---|---|
new | Just getting started | 3 or fewer sessions |
onboarding | Learning the ropes | 4-10 sessions |
active | Regular user past onboarding | More than 10 sessions, fewer than 5 features used |
power | Heavy feature adopter | 5+ distinct features used |
dormant | Has gone quiet | 14+ days since last seen |
How Maturity Is Computed
Section titled “How Maturity Is Computed”The computation follows this priority order:
- Dormant check — If the user has not been seen for
dormantDaysInactivedays, they aredormant(regardless of other signals) - New check — If
sessionCountis at or belownewMaxSessions, they arenew - Power check — If the number of distinct features used is at or above
powerMinFeatures, they arepower - Onboarding check — If
sessionCountis at or belowonboardingMaxSessions, they areonboarding - Fallback — Otherwise, they are
active
// Simplified version of the actual computationfunction computeMaturity(signals: BehavioralSignals, config: MaturityConfig): Maturity { const daysSinceLastSeen = daysBetween(new Date(signals.lastSeenAt), new Date())
if (daysSinceLastSeen >= config.dormantDaysInactive) return 'dormant' if (signals.sessionCount <= config.newMaxSessions) return 'new'
const featuresUsed = Object.keys(signals.featureUsage).length if (featuresUsed >= config.powerMinFeatures) return 'power' if (signals.sessionCount <= config.onboardingMaxSessions) return 'onboarding'
return 'active'}Configuring Thresholds
Section titled “Configuring Thresholds”Override any threshold via the maturity config:
const client = createAdaptiveClient({ maturity: { newMaxSessions: 5, // Consider "new" for 5 sessions instead of 3 onboardingMaxSessions: 15, // Extend onboarding period powerMinFeatures: 8, // Require more features for "power" status dormantDaysInactive: 30, // Wait longer before marking as dormant }, // ...rules, persistence})The full config interface:
interface MaturityConfig { newMaxSessions: number // Default: 3 onboardingMaxSessions: number // Default: 10 powerMinFeatures: number // Default: 5 dormantDaysInactive: number // Default: 14}Using Maturity in Rules
Section titled “Using Maturity in Rules”Maturity is accessible at the top level of the context (not nested under traits or signals):
{ id: 'new-user-onboarding', adaptationId: 'onboarding', priority: 10, conditions: { all: [ { field: 'maturity', operator: 'eq', value: 'new' }, ], }, action: { type: 'show', variantId: 'guided-tour' },}You can combine maturity with other conditions:
{ id: 'dormant-enterprise-reactivation', adaptationId: 'banner', priority: 20, conditions: { all: [ { field: 'maturity', operator: 'eq', value: 'dormant' }, { field: 'traits.plan', operator: 'eq', value: 'enterprise' }, ], }, action: { type: 'show', variantId: 'reactivation-offer' },}Example: Different Onboarding for Each Maturity Level
Section titled “Example: Different Onboarding for Each Maturity Level”import { createAdaptiveClient, createLocalStorageDriver } from '@presage-kit/core'
const client = createAdaptiveClient({ rules: [ { id: 'new-guided-tour', adaptationId: 'onboarding', priority: 50, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'new' }], }, action: { type: 'show', variantId: 'guided-tour' }, }, { id: 'onboarding-tips', adaptationId: 'onboarding', priority: 40, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'onboarding' }], }, action: { type: 'show', variantId: 'contextual-tips' }, }, { id: 'active-whats-new', adaptationId: 'onboarding', priority: 30, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'active' }], }, action: { type: 'show', variantId: 'whats-new' }, }, { id: 'power-changelog', adaptationId: 'onboarding', priority: 20, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'power' }], }, action: { type: 'show', variantId: 'changelog-only' }, }, { id: 'dormant-reengagement', adaptationId: 'onboarding', priority: 60, conditions: { all: [{ field: 'maturity', operator: 'eq', value: 'dormant' }], }, action: { type: 'show', variantId: 'welcome-back' }, }, ], persistence: { driver: createLocalStorageDriver('my-app'), },})Then in your React component:
import { Adaptive, Variant } from '@presage-kit/react'
function OnboardingFlow() { return ( <Adaptive id="onboarding" defaultVariant="contextual-tips"> <Variant id="guided-tour"> <GuidedTour /> </Variant> <Variant id="contextual-tips"> <ContextualTips /> </Variant> <Variant id="whats-new"> <WhatsNew /> </Variant> <Variant id="changelog-only"> <Changelog /> </Variant> <Variant id="welcome-back"> <WelcomeBack /> </Variant> </Adaptive> )}Maturity Transition
Section titled “Maturity Transition”Maturity is recomputed every time signals change (after each track() call). This means a user can transition between segments within a single session:
- User arrives (session 1) →
new - User returns for session 4 →
onboarding - User uses 5 distinct features →
power - User disappears for 14 days →
dormant
Your UI adapts at each transition without any manual intervention.