Overview
Onboarding tracking helps you measure how effectively new users complete your activation flow. Track step completion, identify dropoff points, and optimize your onboarding experience to improve user retention.
Important: The OnboardingTracker is a helper class that formats and sends events. You must manually call tracker methods when users complete steps. It does not automatically detect onboarding progress.
Quick Start
Define Your Onboarding Steps
Create a configuration object defining your onboarding flow:const onboardingConfig = {
steps: [
{ name: "account_created", index: 0, required: true },
{ name: "profile_completed", index: 1, required: true },
{ name: "preferences_set", index: 2, required: false },
{ name: "first_action", index: 3, required: true },
],
};
Initialize the Tracker
Use the useOnboardingTracker hook in your onboarding flow:import { useOnboardingTracker, useMentiqAnalytics } from "mentiq-sdk";
function OnboardingFlow() {
const analytics = useMentiqAnalytics();
const tracker = useOnboardingTracker(analytics, onboardingConfig);
useEffect(() => {
// Start tracking when user begins onboarding
tracker?.start({
signup_method: "email",
source: "landing_page",
});
}, []);
return <OnboardingSteps tracker={tracker} />;
}
Track Step Completion
Call completeStep() when users finish each step:const handleProfileComplete = async () => {
await saveProfile();
tracker?.completeStep("profile_completed", {
fields_filled: ["name", "email", "company"],
});
};
How It Works
From src/onboarding-tracker.ts:16-197, the tracker sends events at each stage:
- You call tracker methods → Events are sent to backend
- Events stored in database with metadata (step_index, timing, properties)
- Backend analyzes events → Calculates funnel statistics
- Dashboard displays analytics → Completion rates, dropoff points, time metrics
Events Sent Automatically
onboarding_started - When onboarding begins
onboarding_step_completed - When each step is completed
onboarding_step_skipped - When optional steps are skipped
onboarding_completed - When all required steps are done
onboarding_abandoned - When user exits early
Configuration
interface OnboardingConfig {
steps: OnboardingStep[]; // Array of steps
autoTrack?: boolean; // Reserved for future use
}
interface OnboardingStep {
name: string; // Unique step identifier
index: number; // Step order (0-based)
required?: boolean; // Is this step mandatory?
}
Example Configuration
const config = {
steps: [
// Required steps
{ name: "signup", index: 0, required: true },
{ name: "verify_email", index: 1, required: true },
{ name: "complete_profile", index: 2, required: true },
// Optional steps
{ name: "invite_team", index: 3, required: false },
{ name: "connect_integrations", index: 4, required: false },
// Final required step
{ name: "first_project", index: 5, required: true },
],
};
Tracker API
start(properties?)
Start the onboarding process:
tracker.start({
signup_method: "google",
referral_source: "product_hunt",
user_role: "developer",
});
Sends event:
{
"event": "onboarding_started",
"properties": {
"total_steps": 6,
"signup_method": "google",
"referral_source": "product_hunt",
"user_role": "developer"
}
}
completeStep(stepName, properties?)
Mark a step as completed:
tracker.completeStep("profile_completed", {
fields_filled: ["name", "company", "role"],
time_spent: 45, // seconds
});
Sends event:
{
"event": "onboarding_step_completed",
"properties": {
"step_name": "profile_completed",
"step_index": 2,
"required": true,
"steps_completed": 3,
"total_steps": 6,
"progress": 50,
"time_since_start": 120000,
"fields_filled": ["name", "company", "role"],
"time_spent": 45
}
}
skipStep(stepName, reason?)
Skip an optional step:
tracker.skipStep("invite_team", "user_choice");
You can only skip steps marked with required: false.
complete(properties?)
Mark onboarding as complete:
tracker.complete({
completion_source: "manual",
});
Sends event:
{
"event": "onboarding_completed",
"properties": {
"steps_completed": 6,
"total_steps": 6,
"completion_rate": 100,
"duration_ms": 180000,
"duration_seconds": 180,
"completion_source": "manual"
}
}
abandon(reason?)
Track when users abandon onboarding:
tracker.abandon("too_complex");
getProgress()
Get current onboarding progress:
const progress = tracker.getProgress();
console.log(progress);
// {
// currentStep: "profile_completed",
// currentStepIndex: 2,
// completedSteps: ["signup", "verify_email", "profile_completed"],
// totalSteps: 6,
// progressPercent: 50,
// duration: 120000
// }
Complete Example
import { useOnboardingTracker, useMentiqAnalytics } from "mentiq-sdk";
import { useState, useEffect } from "react";
function OnboardingWizard() {
const analytics = useMentiqAnalytics();
const [currentStep, setCurrentStep] = useState(0);
const config = {
steps: [
{ name: "account_created", index: 0, required: true },
{ name: "profile_completed", index: 1, required: true },
{ name: "preferences_set", index: 2, required: false },
{ name: "first_action", index: 3, required: true },
],
};
const tracker = useOnboardingTracker(analytics, config);
useEffect(() => {
// Start tracking when component mounts
tracker?.start({
signup_method: "email",
source: "marketing_site",
});
}, [tracker]);
const handleStepComplete = (stepName: string, properties?: any) => {
tracker?.completeStep(stepName, properties);
setCurrentStep(currentStep + 1);
// Check if onboarding is complete
const progress = tracker?.getProgress();
if (progress?.progressPercent === 100) {
tracker?.complete();
}
};
const handleSkip = (stepName: string) => {
tracker?.skipStep(stepName, "user_choice");
setCurrentStep(currentStep + 1);
};
return (
<div>
{currentStep === 0 && (
<ProfileForm
onComplete={(data) =>
handleStepComplete("profile_completed", { fields: Object.keys(data) })
}
/>
)}
{currentStep === 1 && (
<PreferencesForm
onComplete={() => handleStepComplete("preferences_set")}
onSkip={() => handleSkip("preferences_set")}
/>
)}
{currentStep === 2 && (
<FirstActionStep
onComplete={() => handleStepComplete("first_action")}
/>
)}
</div>
);
}
Use Cases
SaaS Onboarding
function SaaSOnboarding() {
const analytics = useMentiqAnalytics();
const tracker = useOnboardingTracker(analytics, {
steps: [
{ name: "account_setup", index: 0, required: true },
{ name: "team_invited", index: 1, required: false },
{ name: "first_project_created", index: 2, required: true },
{ name: "integration_connected", index: 3, required: false },
{ name: "first_deployment", index: 4, required: true },
],
});
useEffect(() => {
tracker?.start({ plan: "starter" });
}, []);
const handleProjectCreated = (project) => {
tracker?.completeStep("first_project_created", {
project_name: project.name,
project_type: project.type,
});
};
return <ProjectSetup onCreate={handleProjectCreated} />;
}
Product Tour
function ProductTour() {
const analytics = useMentiqAnalytics();
const tracker = useOnboardingTracker(analytics, {
steps: [
{ name: "tour_started", index: 0, required: true },
{ name: "feature_a_viewed", index: 1, required: false },
{ name: "feature_b_viewed", index: 2, required: false },
{ name: "feature_c_viewed", index: 3, required: false },
{ name: "tour_completed", index: 4, required: true },
],
});
const handleTourStep = (stepName: string) => {
tracker?.completeStep(stepName, {
timestamp: Date.now(),
});
};
return (
<TourComponent
onStepComplete={handleTourStep}
onSkip={() => tracker?.abandon("user_skipped")}
/>
);
}
E-commerce Checkout
function CheckoutFlow() {
const analytics = useMentiqAnalytics();
const tracker = useOnboardingTracker(analytics, {
steps: [
{ name: "cart_viewed", index: 0, required: true },
{ name: "shipping_info", index: 1, required: true },
{ name: "payment_info", index: 2, required: true },
{ name: "order_review", index: 3, required: true },
{ name: "purchase_complete", index: 4, required: true },
],
});
const handleCheckoutStep = (step: string, data: any) => {
tracker?.completeStep(step, data);
};
return (
<CheckoutWizard
onStepComplete={handleCheckoutStep}
onAbandon={() => tracker?.abandon("cart_abandoned")}
/>
);
}
Dashboard Analytics
View onboarding metrics in your MentiQ dashboard:
- Completion Rate: Percentage of users who finish onboarding
- Step-by-Step Breakdown: Completion rate for each step
- Dropoff Points: Steps where users abandon most frequently
- Average Time: Time taken per step and total duration
- User Journeys: Individual user progress tracking
- Cohort Analysis: Compare onboarding performance across user segments
Progress Monitoring Component
function OnboardingProgress({ tracker }) {
const [progress, setProgress] = useState(tracker?.getProgress());
useEffect(() => {
const interval = setInterval(() => {
setProgress(tracker?.getProgress());
}, 1000);
return () => clearInterval(interval);
}, [tracker]);
if (!progress) return null;
return (
<div className="onboarding-progress">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${progress.progressPercent}%` }}
/>
</div>
<p>
Step {progress.currentStepIndex + 1} of {progress.totalSteps}
</p>
<p>
{progress.completedSteps.length} steps completed
</p>
</div>
);
}
Best Practices
Onboarding Tracking Tips:
- Keep onboarding flows short (3-5 required steps)
- Make early steps easy to build momentum
- Track time spent on each step
- Mark some steps as optional to reduce friction
- Send contextual properties with each step
- Monitor abandonment reasons
- A/B test different onboarding flows
Troubleshooting
Events Not Appearing
- Verify tracker is initialized:
tracker !== null
- Check you’re calling
tracker.start() before other methods
- Enable debug mode:
config.debug = true
Progress Not Updating
Ensure you’re calling completeStep() with exact step names from your config:
// ❌ Wrong - typo in step name
tracker.completeStep("profile_complete");
// ✅ Correct - matches config
tracker.completeStep("profile_completed");
Completion Not Triggering
Call tracker.complete() manually, or check all required steps are completed:
const progress = tracker.getProgress();
if (progress.progressPercent === 100) {
tracker.complete();
}