← Blog

How to Build a Claude-Powered Onboarding Assistant

2026-10-31 · 6 min read · SubToAPI Team

Building a Claude-powered onboarding assistant means wiring up a conversational agent that walks new users through setup steps, answers product questions in context, and knows when to hand off to a human. The core pattern is simple: give Claude a system prompt that encodes your product's onboarding flow, feed it structured context about where the user is, and let it respond conversationally while your app tracks progress server-side.

This article covers the full build: designing the onboarding flow as a system prompt, passing user state into each request, using tool calls to let Claude trigger actions (like marking a step complete), and handling streaming so responses feel instant in your UI. The goal is a production-ready assistant, not a demo.

Why Claude fits onboarding

Onboarding is a narrow, well-defined conversation domain — you know the steps, the common blockers, and the desired outcome. That makes it a good fit for an LLM with a tightly scoped system prompt, rather than a general-purpose chatbot. Claude handles long system prompts well, follows multi-step instructions reliably, and supports tool use, which matters because a real onboarding assistant needs to do things, not just talk: mark steps complete, fetch account status, or escalate to support.

Step 1: Define the onboarding flow as data, not prose

Before writing a prompt, model your onboarding steps explicitly:

{
  "steps": [
    { "id": "connect_account", "title": "Connect your account", "done": false },
    { "id": "invite_team", "title": "Invite your team", "done": false },
    { "id": "configure_workspace", "title": "Configure your workspace", "done": false },
    { "id": "first_action", "title": "Complete your first action", "done": false }
  ]
}

Storing steps as structured data lets your backend track real progress, while Claude only needs to know which step the user is currently on and what's already done. Don't bake step state into the prompt as free text — pass it as data on every request so the assistant always has fresh context.

Step 2: Write a scoped system prompt

Keep the assistant's job narrow and explicit. A vague "be helpful" prompt produces generic chat. A good onboarding prompt names the steps, the tone, and the boundaries:

You are the onboarding assistant for Acme App.
Your job is to guide new users through these steps, in order:
1. connect_account - link their external account
2. invite_team - invite at least one teammate
3. configure_workspace - set workspace name and timezone
4. first_action - complete one real task in the product

Rules:
- Only discuss onboarding and product setup. Redirect other questions to support.
- If a step is already marked done, don't ask the user to redo it.
- When the user confirms a step is complete, call the mark_step_complete tool.
- Keep responses under 3 sentences unless the user asks for detail.
- If the user seems stuck for more than two messages on the same step, offer to escalate to a human.

This is the single highest-leverage piece of the build. For more on structuring prompts like this, see our guide on structuring system prompts for Claude.

Step 3: Pass user state on every request

Each API call should include the current step state as part of the conversation context — typically as a system or user-role message injected before the actual chat turn:

const stepState = JSON.stringify(user.onboardingSteps);

const messages = [
  { role: "user", content: `Current onboarding state: ${stepState}\n\nUser message: ${userInput}` }
];

This keeps the model grounded in reality instead of hallucinating progress. It also means you don't need to re-send the full conversation history every time if you're tracking state server-side — just the relevant snapshot plus recent turns.

Step 4: Use tool calls to let Claude take action

An onboarding assistant that only talks is half-built. Give it a tool to mark steps complete, so the conversation and your database stay in sync:

{
  "name": "mark_step_complete",
  "description": "Mark an onboarding step as complete for the current user",
  "input_schema": {
    "type": "object",
    "properties": {
      "step_id": { "type": "string" }
    },
    "required": ["step_id"]
  }
}

When Claude decides the user has finished a step, it returns a tool call instead of plain text. Your backend executes the actual database update, then sends the result back so Claude can confirm it to the user. This pattern — model decides, backend executes — keeps your app in control while letting the conversation stay natural. Full details are in the tool use docs.

Step 5: Stream responses for a responsive UI

Onboarding flows are often embedded in a widget or modal, so latency matters more than in a background job. Stream tokens as they arrive rather than waiting for the full response:

const response = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "claude-sonnet-4",
    stream: true,
    max_tokens: 400,
    system: onboardingSystemPrompt,
    messages
  })
});

If you're routing requests through SubToAPI, you get an application API key (sub_live_...), streaming, and tool use out of the box, plus usage metadata per request — useful for seeing which onboarding steps generate the most assistant interactions. See the streaming docs for the full event format, and the quickstart to get a key issued in minutes.

Step 6: Track and escalate

Log every tool call and every "stuck" signal (two or more messages without progress on the same step). Route that signal to a dashboard or a Slack alert so a human can jump in. The assistant's job is to resolve the easy 80% of onboarding friction automatically and flag the rest — not to replace support entirely.

Step 7: Test with real new-user transcripts

Once live, pull actual conversation logs and check for two failure modes: the assistant answering questions outside its scope (tighten the system prompt), and the assistant failing to call mark_step_complete when it should (tighten the tool description and add a few-shot example in the prompt). Iterate weekly for the first month — onboarding copy and flow usually need a few rounds of tuning once real users interact with it.

Getting this into production

If you already have Claude access through a console account, SubToAPI turns it into a clean HTTPS API with per-key usage tracking, so you can give your onboarding assistant its own key and monitor its cost and volume separately from other features. Plans start at €9/month for solo use, with team seats from €19 — see /pricing for details, or start with the quickstart.

questions

Does the assistant need a separate model call for every user message? Yes — treat each turn as a new request with the latest step state and recent history included, rather than trying to maintain a long-running session. This keeps context accurate and avoids stale state.

Should the assistant have access to the full product documentation? Not directly. Keep the system prompt scoped to the onboarding flow itself, and use retrieval or a separate support assistant for general documentation questions. Mixing the two makes the onboarding assistant harder to control.

How do I prevent the assistant from marking steps complete incorrectly? Require explicit user confirmation before calling the tool (e.g., "yes, I've invited my team"), and have your backend double-check the action actually happened server-side before updating the database, rather than trusting the model's tool call alone.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →