diff --git a/frontend/src/api/onboarding.ts b/frontend/src/api/onboarding.ts
new file mode 100644
index 00000000..4f54e687
--- /dev/null
+++ b/frontend/src/api/onboarding.ts
@@ -0,0 +1,21 @@
+import { apiClient } from './client'
+
+export interface OnboardingStatus {
+ created_flow: boolean
+ ran_session: boolean
+ exported_session: boolean
+ tried_ai_assistant: boolean
+ invited_teammate: boolean
+ connected_psa: boolean
+ is_team_user: boolean
+ dismissed: boolean
+}
+
+export async function getOnboardingStatus(): Promise {
+ const response = await apiClient.get('/users/onboarding-status')
+ return response.data
+}
+
+export async function dismissOnboarding(): Promise {
+ await apiClient.post('/users/onboarding-status/dismiss')
+}
diff --git a/frontend/src/components/dashboard/OnboardingChecklist.tsx b/frontend/src/components/dashboard/OnboardingChecklist.tsx
new file mode 100644
index 00000000..f4552204
--- /dev/null
+++ b/frontend/src/components/dashboard/OnboardingChecklist.tsx
@@ -0,0 +1,160 @@
+import { useState, useEffect } from 'react'
+import { useNavigate } from 'react-router-dom'
+import { Check, X, ChevronRight } from 'lucide-react'
+import { cn } from '@/lib/utils'
+import { getOnboardingStatus, dismissOnboarding } from '@/api/onboarding'
+import type { OnboardingStatus } from '@/api/onboarding'
+
+interface ChecklistItem {
+ key: keyof OnboardingStatus
+ label: string
+ path: string
+}
+
+const SOLO_ITEMS: ChecklistItem[] = [
+ { key: 'created_flow', label: 'Create your first flow', path: '/trees' },
+ { key: 'ran_session', label: 'Run your first session', path: '/trees' },
+ { key: 'exported_session', label: 'Export a session', path: '/sessions' },
+ { key: 'tried_ai_assistant', label: 'Try the AI assistant', path: '/assistant' },
+]
+
+const TEAM_ITEMS: ChecklistItem[] = [
+ { key: 'created_flow', label: 'Create your first flow', path: '/trees' },
+ { key: 'invited_teammate', label: 'Invite a team member', path: '/account' },
+ { key: 'ran_session', label: 'Run your first session', path: '/trees' },
+ { key: 'connected_psa', label: 'Connect a PSA integration', path: '/account/integrations' },
+ { key: 'exported_session', label: 'Export a session', path: '/sessions' },
+]
+
+export function OnboardingChecklist() {
+ const navigate = useNavigate()
+ const [status, setStatus] = useState(null)
+ const [dismissed, setDismissed] = useState(false)
+ const [allComplete, setAllComplete] = useState(false)
+
+ useEffect(() => {
+ getOnboardingStatus()
+ .then(setStatus)
+ .catch(() => {
+ // Silently fail — don't show checklist if endpoint unavailable
+ })
+ }, [])
+
+ const items = status?.is_team_user ? TEAM_ITEMS : SOLO_ITEMS
+ const completedCount = status
+ ? items.filter((item) => status[item.key]).length
+ : 0
+ const totalCount = items.length
+ const isAllDone = completedCount === totalCount && status !== null
+
+ useEffect(() => {
+ if (isAllDone) {
+ const timer = setTimeout(() => setAllComplete(true), 2000)
+ return () => clearTimeout(timer)
+ }
+ }, [isAllDone])
+
+ // Don't render if dismissed, fully complete, or not loaded yet
+ if (!status || status.dismissed || dismissed || allComplete) return null
+
+ const progressPercent = totalCount > 0 ? (completedCount / totalCount) * 100 : 0
+
+ const handleDismiss = async () => {
+ setDismissed(true)
+ try {
+ await dismissOnboarding()
+ } catch {
+ // Already hidden locally
+ }
+ }
+
+ return (
+
+ {/* Progress bar */}
+
+
+
+ {/* Header */}
+
+
+
+ Getting Started
+
+
+ {isAllDone ? (
+ You're all set!
+ ) : (
+
+ {completedCount}
+ {' '}of {totalCount} complete
+
+ )}
+
+
+
+
+
+ {/* Checklist items */}
+
+ {items.map((item) => {
+ const done = status[item.key]
+ return (
+ -
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/frontend/src/pages/QuickStartPage.tsx b/frontend/src/pages/QuickStartPage.tsx
index ecb71bc8..26278446 100644
--- a/frontend/src/pages/QuickStartPage.tsx
+++ b/frontend/src/pages/QuickStartPage.tsx
@@ -26,6 +26,7 @@ import { QuickActions } from '@/components/dashboard/QuickActions'
import { OpenSessions } from '@/components/dashboard/OpenSessions'
import { RecentActivity } from '@/components/dashboard/RecentActivity'
import { PreparedSessions } from '@/components/dashboard/PreparedSessions'
+import { OnboardingChecklist } from '@/components/dashboard/OnboardingChecklist'
function timeAgo(dateStr: string): string {
const now = Date.now()
@@ -278,6 +279,9 @@ export function QuickStartPage() {
+ {/* Onboarding Checklist */}
+
+
{/* Row 1: Calendar + Quick Actions */}