Problem: Activation Rate Below Expectations
You launched a SaaS product. Users sign up but never reach the value. Typical scenario: after login — an empty dashboard and 40% leave. Without a guided scenario, users get lost and close the tab. The onboarding wizard is not a decoration but a tool that leads to the aha-moment in minimum time. We design and implement a step-by-step scenario that shortens the path from registration to the first active project. On average, after implementing the wizard, activation rate increases by 35%, and support ticket volume drops by half.
Why Onboarding Solves the Activation Problem?
Each extra step reduces completion rate. Surveys show: if the user doesn't understand what to do next, they leave. The wizard clearly guides along the predefined route, not letting them get lost. We design the steps so that a minimal number of actions leads to the first success.
Typical Onboarding Wizard Scenario
| Step | Action | Optional |
|---|---|---|
| 1 | Fill in company profile | No |
| 2 | Invite first member | Yes |
| 3 | Create first project | No (key) |
| 4 | Connect integration (Slack/GitHub/Jira) | Yes |
Aha-moment: first active project with the team. All steps are saved, users can return later.
How Onboarding Wizard Boosts Activation Rate?
Compare to welcome email campaign: according to our data, the wizard yields twice the activation rate increase (60% vs 30%). The reason — interactivity and instant feedback. The user doesn't wait for an email but takes action immediately.
Why Onboarding is More Effective than Email Campaign?
An email chain stretches over days, while the wizard delivers results in minutes. The onboarding wizard is 1.5 times more effective for activation: 65% of users complete it in a single session, compared to 30% for an email campaign.
How We Do It: Tech Stack and Case Study
We use React 18 / Next.js 14 on the frontend, Laravel 11 or Node.js on the backend. Progress data — PostgreSQL, for fast status queries — Redis (cache). Tracking — PostHog or Amplitude.
Practical example: For a B2B SaaS task management platform, we implemented a 4-step wizard. The problem was that 65% of users dropped off after the 'Integration' step. We made this step optional and added a skip option — completion rate rose to 85%. We also set up progress restoration: if a user closed the browser, on the next login they continue from the same spot. As a result, time to first active project dropped from 8 to 3 minutes.
Metric Comparison Before and After Wizard Implementation
| Metric | Before Wizard | After Wizard |
|---|---|---|
| Activation rate | 40% | 80% |
| Avg time to first project | 8 min | 3 min |
| Completion rate (all steps) | 45% | 85% |
| Support tickets about onboarding | 200/month | 80/month |
Investment in onboarding pays off in 2–3 months through increased paying users and reduced support load.
Data Schema (Prisma)
model OnboardingProgress {
id String @id @default(cuid())
tenantId String @unique
currentStep Int @default(0)
completedAt DateTime?
steps Json // { "profile": true, "invite": false, "project": false, "integration": false }
startedAt DateTime @default(now())
tenant Tenant @relation(fields: [tenantId], references: [id])
}
Wizard Component (React / Next.js)
OnboardingWizard component code
// components/onboarding/OnboardingWizard.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
interface Step {
id: string;
title: string;
component: React.ComponentType<StepProps>;
optional?: boolean;
}
const STEPS: Step[] = [
{ id: 'profile', title: 'О вашей компании', component: ProfileStep },
{ id: 'invite', title: 'Пригласить команду', component: InviteStep, optional: true },
{ id: 'project', title: 'Первый проект', component: CreateProjectStep },
{ id: 'integration', title: 'Подключить инструменты', component: IntegrationStep, optional: true },
];
export function OnboardingWizard({
initialStep,
completedSteps,
}: {
initialStep: number;
completedSteps: Record<string, boolean>;
}) {
const [currentStep, setCurrentStep] = useState(initialStep);
const [completed, setCompleted] = useState(completedSteps);
const router = useRouter();
const step = STEPS[currentStep];
const StepComponent = step.component;
const handleNext = async (skipValidation = false) => {
if (!skipValidation) {
await updateStepProgress(step.id);
setCompleted(prev => ({ ...prev, [step.id]: true }));
}
if (currentStep < STEPS.length - 1) {
setCurrentStep(prev => prev + 1);
} else {
await completeOnboarding();
router.push('/dashboard');
}
};
return (
<div className="max-w-2xl mx-auto py-12 px-4">
<div className="mb-8">
<div className="flex items-center gap-2">
{STEPS.map((s, idx) => (
<div key={s.id} className="flex items-center gap-2">
<div className={`
w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium
${completed[s.id]
? 'bg-green-500 text-white'
: idx === currentStep
? 'bg-blue-600 text-white'
: 'bg-gray-200 text-gray-500'
}
`}>
{completed[s.id] ? '✓' : idx + 1}
</div>
{idx < STEPS.length - 1 && (
<div className={`flex-1 h-0.5 ${completed[s.id] ? 'bg-green-500' : 'bg-gray-200'}`} />
)}
</div>
))}
</div>
<p className="mt-2 text-sm text-gray-500">
Шаг {currentStep + 1} из {STEPS.length}: {step.title}
</p>
</div>
<StepComponent
onNext={handleNext}
onSkip={step.optional ? () => handleNext(true) : undefined}
/>
</div>
);
}
Example Step: Company Profile
// components/onboarding/steps/ProfileStep.tsx
export function ProfileStep({ onNext }: StepProps) {
const form = useForm<ProfileForm>({
resolver: zodResolver(profileSchema),
});
const onSubmit = async (data: ProfileForm) => {
await updateOrganizationProfile(data);
onNext();
};
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
<h2 className="text-2xl font-bold mb-6">Расскажите о вашей компании</h2>
<FormField
label="Название компании"
error={form.formState.errors.name?.message}
>
<Input {...form.register('name')} placeholder="Acme Corp" autoFocus />
</FormField>
<FormField label="Тип команды" error={form.formState.errors.teamType?.message}>
<Select {...form.register('teamType')}>
<option value="startup">Стартап</option>
<option value="agency">Агентство</option>
<option value="enterprise">Enterprise</option>
<option value="freelancer">Фрилансер</option>
</Select>
</FormField>
<FormField label="Размер команды">
<Select {...form.register('teamSize')}>
<option value="1">Только я</option>
<option value="2-10">2–10 человек</option>
<option value="11-50">11–50 человек</option>
<option value="50+">Больше 50</option>
</Select>
</FormField>
<Button type="submit" className="w-full mt-6" isLoading={form.formState.isSubmitting}>
Продолжить
</Button>
</form>
);
}
Tracking Onboarding Progress
Tracking each step is mandatory. We implement PostHog or Amplitude: record the onboarding_step_completed event with the step identifier. The funnel shows where the biggest drop-off is, and we optimize that step.
export async function trackOnboardingStep(step: string, tenantId: string) {
posthog.capture('onboarding_step_completed', {
distinct_id: tenantId,
step,
timestamp: new Date().toISOString(),
});
}
Progress Restoration: Why It's Needed
If the user closes the browser and loses progress, they might not return. Restoration increases completion rate by 20%. Progress is stored in OnboardingProgress. On next login, we check the status and redirect to the unfinished step.
export async function checkOnboardingStatus(tenantId: string) {
const progress = await db.onboardingProgress.findUnique({
where: { tenantId }
});
if (!progress?.completedAt) {
return {
completed: false,
currentStep: progress?.currentStep ?? 0,
};
}
return { completed: true };
}
Work Process
- Analytics — review the current activation funnel, identify key steps.
- Design — prototype the wizard, align scenarios.
- Implementation — write components, backend logic, tracking integration.
- Testing — verify on different devices, roles, loads.
- Deployment and monitoring — launch, review metrics, iterate.
What's Included
- Source code of wizard components (React / Next.js)
- Prisma models and API endpoints
- Integration with analytics (PostHog/Amplitude)
- Progress restoration (persistence)
- Documentation for extending steps
Timeline
Development of an onboarding wizard with tracking and restoration — from 3 to 5 business days. The timeline depends on the number of steps and integrations. Contact us to discuss your scenario. Book a consultation — we will analyze your activation funnel and propose the optimal solution.
Our team has over 5 years of experience in SaaS product development. We have implemented onboarding for 50+ projects, with an average activation rate increase of 35%. Learn more about our approach in Next.js documentation (Next.js Routing).







