Skip to main content

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

1

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 },
  ],
};
2

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} />;
}
3

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:
  1. You call tracker methods → Events are sent to backend
  2. Events stored in database with metadata (step_index, timing, properties)
  3. Backend analyzes events → Calculates funnel statistics
  4. 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

  1. Verify tracker is initialized: tracker !== null
  2. Check you’re calling tracker.start() before other methods
  3. 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();
}

Build docs developers (and LLMs) love