Quickstart

From an empty project to a persisted, reported and titled conversation in the dashboard, and what to check when the first turn does not show up.

This guide takes the shortest path: an anonymous session, the AI SDK runtime and the assistant-ui components. The other guides swap the runtime; the cloud side stays the same.

Create a project

Sign in at cloud.assistant-ui.com and create a project. Copy its Frontend API URL from Settings › General; it looks like https://proj-<id>.assistant-api.com. A new project accepts anonymous sessions from any origin, so nothing else needs to be configured for a first run.

Configure the environment

.env.local
NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-<id>.assistant-api.com
OPENAI_API_KEY=sk-…

On Next.js, the React runtimes create an anonymous cloud client from this variable when you pass no cloud. Vite, React Router and TanStack Start expose only VITE_ variables to the browser, so name it VITE_ASSISTANT_BASE_URL there.

Install and wire the runtime

npm install @assistant-ui/react @assistant-ui/ai-sdk ai @ai-sdk/openai
app/chat/page.tsx
"use client";

import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime } from "@assistant-ui/ai-sdk";
import { ThreadList } from "@/components/assistant-ui/elements/thread-list.aui";
import { Thread } from "@/components/assistant-ui/elements/thread.aui";

export default function ChatPage() {
  const runtime = useChatRuntime();

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      <div className="grid h-dvh grid-cols-[240px_1fr]">
        <ThreadList />
        <Thread />
      </div>
    </AssistantRuntimeProvider>
  );
}

useChatRuntime() reads the base URL from the environment on Next.js and posts chat requests to /api/chat, the AI SDK route you already have. On Vite, React Router or TanStack Start, create the client once, outside the component, and pass it as useChatRuntime({ cloud }):

import { AssistantCloud } from "@assistant-ui/react";

const cloud = new AssistantCloud({
  baseUrl: import.meta.env.VITE_ASSISTANT_BASE_URL,
  anonymous: true,
});

Report model and usage

The browser cannot see which model answered or how many tokens it used. Add a messageMetadata callback to your route so the run report carries them:

app/api/chat/route.ts
import { convertToModelMessages, streamText } from "ai";
import { openai } from "@ai-sdk/openai";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const model = openai("gpt-6-luna");
  const result = streamText({
    model,
    messages: await convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse({
    messageMetadata: ({ part }) => {
      if (part.type === "finish") {
        return { usage: part.totalUsage, finishReason: part.finishReason };
      }
      if (part.type === "finish-step") {
        return { modelId: part.response.modelId, provider: model.provider };
      }
      return undefined;
    },
  });
}

Send a message and look

Send one message and open the dashboard. This is what the first turn leaves behind, and where to find it:

In the dashboardWhat you seeWritten by
ThreadsOne thread for the anonymous visitor, with the two messages rendered on its pageThe runtime, as the response settles
Threads, the thread's titleA short title in place of Untitled, as the response startsThe cloud, from the first message, streamed back to the runtime's own request
RunsOne completed run with its duration, time to first token, tokens, model and costThe runtime's report, with the model and usage from the route
EngagementOne send, and the thread's satisfaction reading once a second turn or a copy happensThe runtime's events
UsersOne anonymous user, active this monthThe user's first message

The app shows the title as soon as the model writes it; Thread titles explains how.

When the first turn does not show up

What you seeWhyWhat to do
No thread appearsNo cloud client was created, so the thread list stayed in memory: the environment variable is missing, or the app is not on Next.js and passes no cloud; or the browser's origin is refused, so every cloud request failsSet NEXT_PUBLIC_ASSISTANT_BASE_URL and restart the dev server, or on Vite, React Router and TanStack Start pass the client built from VITE_ASSISTANT_BASE_URL; check Settings › Access and the browser console for a CORS refusal
The thread exists but stays UntitledThe title attempt failed, for instance because the title provider refused the call; the hourly sweep retries it up to three timesOpen the thread in the dashboard: the Title row of its Details rail names the error. Fix the provider under Settings › Thread titles
The run reads No model reported and has no costThe route did not return modelId and usage in its metadataAdd the messageMetadata callback from the step above
A 402 in the consoleThe project's plan has reached its active user cap for the monthSee Plans and pricing

Next

  • Give users an identity of their own and lock down origins: Authentication.
  • Join your server's spans to the browser's report: Traces.
  • Read what every field of a report means: Run reports.
  • Start from a template instead: cloud with anonymous sessions, or cloud-clerk with Clerk sign in.