Onboarding Experience
Quick Access: Get new users productive in under 10 minutes with guided setup, interactive tutorials, and contextual help.
Overview
The Onboarding Experience provides a structured, interactive journey for new users from signup to their first successful email campaign, reducing time-to-value and improving activation rates.
Key Components
-
Guided Setup Wizard: Step-by-step infrastructure configuration
-
Interactive Checklist: Track progress toward first campaign
-
Contextual Tooltips: In-app guidance and feature discovery
-
Video Tutorials: Quick how-to videos at key moments
-
Progress Tracking: Visual progress indicators
-
Achievement Milestones: Celebrate user progress
Level 1: Onboarding Flow Overview
New User Journey
1. Sign Up → 2. Workspace Setup → 3. Domain Configuration →
4. Payment → 5. First Email Account → 6. First Campaign → 7. Success!
Time to Complete: 8-10 minutes
Step-by-Step Walkthrough
Step 1: Sign Up (1 min)
Fields:
-
Email address
-
Password
-
Company name
-
User name
Welcome Screen:
Welcome to PenguinMails! 🐧
Let's get your professional email infrastructure
set up in under 10 minutes.
[Start Setup] [Skip Tour]
Step 2: Create Workspace (1 min)
Create Your First Workspace
Workspaces help you organize campaigns by client,
project, or brand.
Workspace Name: [_______________]
Example: "Main Company" or "Client: Acme Corp"
[Continue]
Tooltip: “You can create unlimited workspaces. Start with one for now.”
Step 3: Add Domain (2 min)
Step 3 of 6: Add Your Sending Domain
This is the domain you'll send emails from
(e.g., yourdomain.com)
Domain: [_______________]
☐ I have access to DNS settings for this domain
[Continue] [Need help?]
If “Need help?” clicked:
-
Show video: “What is a sending domain?”
-
Link to: Domain setup guide
Step 4: Verify Domain (2 min)
Step 4 of 6: Verify Domain Ownership
Add this DNS record to verify you own this domain:
TXT Record:
Host: _penguinmails-verify
Value: abc123xyz...
[Copy Record] [I've Added the Record]
OR
[Auto-Configure with Cloudflare] [Auto-Configure with Route53]
Auto-detection:
-
System polls for DNS record every 10 seconds
-
Shows “Verifying…” animation
-
Auto-advances when verified
Step 5: Set Up Payment (1 min)
Step 5 of 6: Choose Your Plan
○ Starter - $49/mo
Up to 5,000 emails/month
1 workspace
● Professional - $99/mo [RECOMMENDED]
Up to 25,000 emails/month
Unlimited workspaces
Priority support
○ Business - $249/mo
Up to 100,000 emails/month
Everything in Professional
Dedicated infrastructure
[Start 14-Day Free Trial] No credit card required
After trial started:
✓ Trial Started - 14 days remaining
You won't be charged until your trial ends.
Add payment method anytime in Settings.
[Continue to Infrastructure Setup]
Step 6: Provision Infrastructure (2-3 min)
Step 6 of 6: Launch Your Email Infrastructure
We're setting up your professional email infrastructure:
✓ VPS server provisioning
⏳ Installing SMTP server (2 min remaining)
○ Configuring DNS records
○ Installing SSL certificates
○ Creating your first email account
[Watch Setup Video] while you wait
Progress bar animates showing real-time status.
Complete:
🎉 Infrastructure Ready!
Your email infrastructure is live at:
mail.yourdomain.com
Next: Create your first email account
[Create Email Account]
Step 7: Create First Email Account (1 min)
Create Your First Sending Account
Email Address: [___]@yourdomain.com
Password: [Generate Secure Password]
[Create Account & Finish Setup]
Step 8: Success & Next Steps (30 sec)
🎉 Congratulations! You're All Set
Your email infrastructure is ready to send.
Quick Actions:
☐ Create your first campaign
☐ Import your contact list
☐ Set up email warmup (recommended)
[Go to Dashboard] [Take the Product Tour]
Level 2: Advanced Onboarding Features
Interactive Checklist
Persistent checklist in sidebar:
Getting Started ────────○○○ 70%
✓ Create workspace
✓ Add domain
✓ Verify domain
✓ Create email account
⏳ Import contacts (20/100)
○ Create first campaign
○ Send first email
[Collapse]
Features:
-
Persists across sessions
-
Click items to jump to relevant page
-
Progress percentage updates in real-time
-
Dismissible after completion
Contextual Tooltips
First-time visitor tooltips:
[i] Workspaces
Organize your campaigns by client,
brand, or project.
[Got It] [Learn More]
Smart triggering:
-
Show on first page visit only
-
Don’t show if user has interacted with feature
-
Allow dismissal (never show again)
-
Max 3 tooltips per page
Interactive Tutorial Mode
Activated by: “Take the Product Tour” button
Flow:
-
Dim entire UI
-
Highlight specific element
-
Show explanation overlay
-
Guide through workflow
-
Allow skipping or pausing
Example:
[Spotlight on "Create Campaign" button]
Step 1 of 5: Creating Your First Campaign
Click here to create a new email campaign.
[Next] [Skip Tour]
Video Tutorials
Embedded at key moments:
-
Domain setup: “How to add DNS records”
-
Email warmup: “Why warmup matters”
-
Campaign creation: “Your first campaign”
Format:
-
60-90 seconds each
-
Skippable
-
Closed captions
-
Hosted on CDN for fast loading
Progress Milestones
Achievement notifications:
🎊 Milestone Unlocked: First Email Sent!
You've sent your first email through PenguinMails.
Keep going!
[View Campaign Analytics]
Milestones:
-
✓ First workspace created
-
✓ First domain verified
-
✓ First email account created
-
✓ First 10 contacts imported
-
✓ First campaign created
-
✓ First email sent
-
✓ First email opened
-
✓ First link clicked
Personalized Recommendations
Based on user behavior:
👋 We noticed you haven't set up email warmup yet.
Warmup helps build sender reputation and improves
deliverability. It only takes 2 minutes.
[Set Up Warmup Now] [Remind Me Later]
Team Onboarding
For workspace invites:
Welcome to [Workspace Name]!
You've been invited as a Workspace Member.
Here's what you can do:
✓ View campaigns
✓ Create and edit templates
○ Can't: Modify billing or infrastructure
[View Permissions] [Explore Dashboard]
Level 3: Technical Implementation
Onboarding State Management
interface OnboardingState {
userId: string;
tenantId: string;
// Progress tracking
currentStep: number;
totalSteps: number;
completedSteps: string[];
startedAt: Date;
completedAt?: Date;
// Checklist
checklistItems: OnboardingChecklistItem[];
checklistProgress: number; // 0-100
// User preferences
skipTutorials: boolean;
dismissedTooltips: string[];
watchedVideos: string[];
// Milestones
unlockedMilestones: string[];
// Metadata
lastActiveStep: string;
lastActivityAt: Date;
}
interface OnboardingChecklistItem {
id: string;
label: string;
description: string;
completed: boolean;
required: boolean;
order: number;
actionUrl?: string;
completedAt?: Date;
}
Database Schema
CREATE TABLE user_onboarding (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
tenant_id UUID NOT NULL REFERENCES tenants(id),
-- Progress
current_step INTEGER DEFAULT 1,
completed_steps TEXT[] DEFAULT '{}',
started_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP,
-- Checklist
checklist_progress INTEGER DEFAULT 0,
checklist_items JSONB DEFAULT '[]',
-- Preferences
skip_tutorials BOOLEAN DEFAULT FALSE,
dismissed_tooltips TEXT[] DEFAULT '{}',
watched_videos TEXT[] DEFAULT '{}',
-- Milestones
unlocked_milestones TEXT[] DEFAULT '{}',
-- Metadata
last_active_step VARCHAR(100),
last_activity_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id)
);
-- Onboarding analytics
CREATE TABLE onboarding_events (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
event_type VARCHAR(100),
event_data JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_onboarding_events_user ON onboarding_events(user_id, created_at);
Onboarding Service
class OnboardingService {
async initializeOnboarding(userId: string, tenantId: string): Promise<OnboardingState> {
const checklist = this.generateChecklist(userId, tenantId);
const onboarding = await db.userOnboarding.create({
userId,
tenantId,
currentStep: 1,
checklistItems: checklist,
checklistProgress: 0,
});
await this.trackEvent(userId, 'onboarding_started');
return onboarding;
}
async completeStep(userId: string, step: string): Promise<void> {
const onboarding = await db.userOnboarding.findByUser(userId);
await db.userOnboarding.update(userId, {
completedSteps: [...onboarding.completedSteps, step],
lastActiveStep: step,
lastActivityAt: new Date(),
});
await this.trackEvent(userId, 'onboarding_step_completed', { step });
// Check for milestone unlocks
await this.checkMilestones(userId, step);
// Update checklist if applicable
await this.updateChecklist(userId, step);
}
async updateChecklist(userId: string, action: string): Promise<void> {
const onboarding = await db.userOnboarding.findByUser(userId);
const checklist = onboarding.checklistItems;
// Find matching checklist item
const item = checklist.find(i => i.id === action);
if (item && !item.completed) {
item.completed = true;
item.completedAt = new Date();
const progress = this.calculateProgress(checklist);
await db.userOnboarding.update(userId, {
checklistItems: checklist,
checklistProgress: progress,
});
// Check if onboarding complete
if (progress === 100) {
await this.completeOnboarding(userId);
}
}
}
private calculateProgress(checklist: OnboardingChecklistItem[]): number {
const total = checklist.filter(i => i.required).length;
const completed = checklist.filter(i => i.required && i.completed).length;
return Math.round((completed / total) * 100);
}
async checkMilestones(userId: string, event: string): Promise<void> {
const milestones = {
'workspace_created': 'first_workspace',
'domain_verified': 'first_domain',
'email_sent': 'first_email',
'email_opened': 'first_open',
};
const milestone = milestones[event];
if (milestone) {
await this.unlockMilestone(userId, milestone);
}
}
async unlockMilestone(userId: string, milestone: string): Promise<void> {
await db.userOnboarding.update(userId, {
unlockedMilestones: db.raw('array_append(unlocked_milestones, ?)', [milestone]),
});
await this.trackEvent(userId, 'milestone_unlocked', { milestone });
// Send notification
await notificationService.send({
userId,
type: 'milestone_unlocked',
data: { milestone },
});
}
}
Frontend Components
// Onboarding wizard
function OnboardingWizard() {
const { onboarding, completeStep } = useOnboarding();
const steps = [
{ id: 'workspace', component: WorkspaceSetup },
{ id: 'domain', component: DomainSetup },
{ id: 'payment', component: PaymentSetup },
{ id: 'infrastructure', component: InfrastructureSetup },
{ id: 'email-account', component: EmailAccountSetup },
{ id: 'complete', component: OnboardingComplete },
];
const currentStepComponent = steps[onboarding.currentStep - 1]?.component;
return (
<div className="onboarding-wizard">
<ProgressBar
current={onboarding.currentStep}
total={steps.length}
/>
{currentStepComponent && React.createElement(currentStepComponent, {
onComplete: () => completeStep(steps[onboarding.currentStep - 1].id),
})}
</div>
);
}
// Persistent checklist
function OnboardingChecklist() {
const { checklist, progress } = useOnboarding();
const [collapsed, setCollapsed] = useState(false);
if (progress === 100) return null; // Hide when complete
return (
<aside className="onboarding-checklist">
<header onClick={() => setCollapsed(!collapsed)}>
<h3>Getting Started</h3>
<ProgressBar value={progress} />
<span>{progress}%</span>
</header>
{!collapsed && (
<ul>
{checklist.map(item => (
<li key={item.id} className={item.completed ? 'completed' : ''}>
{item.completed ? '✓' : '○'} {item.label}
</li>
))}
</ul>
)}
</aside>
);
}
Related Documentation
-
User Management - Authentication and registration
-
Email Infrastructure Setup - Infrastructure provisioning
-
Domain Management - Domain configuration
-
Subscription Management - Payment and trials
Last Updated: November 25, 2025 Status: Planned - MVP Feature (Level 2) Target Release: Q1 2026 Owner: Product Team