AI-Powered Onboarding Flows: Guiding New Users with Intelligent Agents
Build an AI onboarding agent that adapts to each user's role, experience level, and goals to guide them through your SaaS product with personalized walkthroughs and recommendations.
The Problem with Static Onboarding
Most SaaS products have a fixed onboarding flow: five steps, same for everyone. A CEO sees the same tutorial as an analyst. A power user who has used three competing products gets the same walkthrough as someone who has never seen software in this category. Static onboarding leads to two failure modes — experienced users skip everything and miss important differences, while new users feel overwhelmed by irrelevant features.
An AI-powered onboarding agent solves this by adapting the flow based on who the user is and what they need.
Capturing User Context at Signup
The onboarding agent starts by gathering context through a brief conversational intake. Instead of a static form, the AI asks follow-up questions based on previous answers.
from pydantic import BaseModel
from enum import Enum
class ExperienceLevel(str, Enum):
BEGINNER = "beginner"
INTERMEDIATE = "intermediate"
EXPERT = "expert"
class UserProfile(BaseModel):
role: str
experience_level: ExperienceLevel
goals: list[str]
team_size: int | None = None
previous_tools: list[str] = []
industry: str | None = None
INTAKE_SYSTEM_PROMPT = """You are an onboarding assistant for a project management SaaS.
Your job is to learn about the new user in 3-5 questions so you can personalize their setup.
Ask about:
1. Their role (manager, individual contributor, executive)
2. Their experience with similar tools
3. Their primary goal for using this product
4. Their team size
Be conversational and concise. After gathering enough info, respond with a JSON
block containing the UserProfile fields.
Do NOT ask all questions at once. Ask one at a time and adapt based on answers."""
class OnboardingAgent:
def __init__(self, llm_client):
self.llm_client = llm_client
self.conversations: dict[str, list[dict]] = {}
async def process_message(self, user_id: str, message: str) -> dict:
if user_id not in self.conversations:
self.conversations[user_id] = []
self.conversations[user_id].append({"role": "user", "content": message})
response = await self.llm_client.chat(
system=INTAKE_SYSTEM_PROMPT,
messages=self.conversations[user_id],
)
reply = response.content
self.conversations[user_id].append({"role": "assistant", "content": reply})
# Check if the AI has gathered enough info
profile = self.try_extract_profile(reply)
if profile:
return {"type": "profile_complete", "profile": profile, "reply": reply}
return {"type": "question", "reply": reply}
def try_extract_profile(self, reply: str) -> UserProfile | None:
import json
import re
match = re.search(r'{[^}]+}', reply, re.DOTALL)
if match:
try:
data = json.loads(match.group())
return UserProfile(**data)
except (json.JSONDecodeError, ValueError):
return None
return None
Generating Personalized Tour Steps
Once the user profile is captured, the agent generates a custom sequence of feature walkthroughs.
from dataclasses import dataclass
@dataclass
class TourStep:
feature_key: str
title: str
description: str
target_selector: str # CSS selector for the UI element to highlight
action_url: str # Page to navigate to for this step
priority: int
FEATURE_CATALOG = [
{"key": "dashboard", "name": "Dashboard", "roles": ["all"],
"complexity": "beginner"},
{"key": "kanban", "name": "Kanban Board", "roles": ["ic", "manager"],
"complexity": "beginner"},
{"key": "gantt", "name": "Gantt Charts", "roles": ["manager", "executive"],
"complexity": "intermediate"},
{"key": "time_tracking", "name": "Time Tracking", "roles": ["ic"],
"complexity": "beginner"},
{"key": "reports", "name": "Reports & Analytics", "roles": ["manager", "executive"],
"complexity": "beginner"},
{"key": "automations", "name": "Workflow Automations", "roles": ["manager"],
"complexity": "expert"},
{"key": "api_access", "name": "API & Integrations", "roles": ["ic"],
"complexity": "expert"},
]
async def generate_tour(profile: UserProfile, llm_client) -> list[TourStep]:
# Filter features relevant to this user
role_map = {"manager": "manager", "individual contributor": "ic",
"executive": "executive"}
user_role = role_map.get(profile.role.lower(), "ic")
relevant_features = [
f for f in FEATURE_CATALOG
if "all" in f["roles"] or user_role in f["roles"]
]
# Further filter by experience level
complexity_order = {"beginner": 0, "intermediate": 1, "expert": 2}
user_level = complexity_order.get(profile.experience_level.value, 0)
filtered = [
f for f in relevant_features
if complexity_order.get(f["complexity"], 0) <= user_level + 1
]
prompt = f"""Generate an onboarding tour for a {profile.role} with
{profile.experience_level.value} experience. Their goals: {', '.join(profile.goals)}.
Previous tools: {', '.join(profile.previous_tools) or 'None'}.
Available features to highlight:
{[f['name'] for f in filtered]}
Return a JSON array of tour steps ordered by relevance to the user's goals.
Each step: {{"feature_key": "...", "title": "...", "description": "...",
"priority": 1-5}}. Limit to 5-7 steps."""
response = await llm_client.chat(
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
)
return parse_tour_steps(response.content, filtered)
In-App Question Answering
During onboarding, users have questions that do not fit neatly into tour steps. The agent handles free-form questions using product documentation as context.
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
class OnboardingQAAgent:
def __init__(self, llm_client, doc_retriever):
self.llm_client = llm_client
self.doc_retriever = doc_retriever
async def answer_question(self, question: str,
user_profile: UserProfile,
current_page: str) -> str:
# Retrieve relevant documentation chunks
docs = await self.doc_retriever.search(
query=question, limit=5
)
doc_context = "\n\n".join([d.content for d in docs])
system = f"""You are an onboarding assistant. The user is a
{user_profile.experience_level.value}-level {user_profile.role}.
They are currently on the {current_page} page.
Answer their question using ONLY the documentation below.
If the answer is not in the documentation, say so and suggest
contacting support.
Documentation:
{doc_context}"""
response = await self.llm_client.chat(
system=system,
messages=[{"role": "user", "content": question}],
)
return response.content
Feature Recommendation Engine
As users complete onboarding steps, the agent suggests next features based on adoption patterns from similar users.
async def recommend_next_features(db, user_profile: UserProfile,
completed_features: list[str]) -> list[dict]:
# Find users with similar profiles who completed onboarding
similar_users = await db.fetch("""
SELECT u.id, array_agg(fa.feature_key ORDER BY fa.adopted_at) as adoption_order
FROM users u
JOIN feature_adoption fa ON fa.user_id = u.id
WHERE u.role = $1
AND u.experience_level = $2
AND fa.feature_key = ANY($3)
GROUP BY u.id
HAVING count(fa.feature_key) >= $4
LIMIT 100;
""", user_profile.role, user_profile.experience_level.value,
completed_features, len(completed_features))
# Count which features these similar users adopted next
from collections import Counter
next_features = Counter()
for user in similar_users:
order = user["adoption_order"]
for feature in order:
if feature not in completed_features:
next_features[feature] += 1
break # Only count the immediate next feature
return [
{"feature": feat, "adopted_by_similar_users": count}
for feat, count in next_features.most_common(3)
]
FAQ
How do I handle users who skip the onboarding intake?
Provide a "Skip" button that sets sensible defaults (role: individual contributor, experience: intermediate, goals: general). Track which features they use in the first session and retroactively adjust recommendations. Offer to revisit personalization after their first week.
Should the onboarding AI have access to the user's data?
During onboarding, the user typically has no data yet. The AI should have access to sample data and documentation only. If the user imported data before onboarding (e.g., via CSV), the agent can reference that to make the tour more concrete — "I see you imported 47 contacts. Let me show you how to organize them."
How do I measure onboarding AI effectiveness?
Compare three cohorts: users who completed AI onboarding, users who completed static onboarding, and users who skipped onboarding. Track activation rate (percentage reaching their first meaningful action), time-to-first-value, and 30-day retention. The AI cohort should outperform static by at least 15-20% on activation to justify the added complexity.
#AIOnboarding #SaaS #UserGuidance #FeatureRecommendation #Python #AgenticAI #LearnAI #AIEngineering
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.