
How do I set up Assistant Cloud with Assistant-UI so conversations persist and users can resume threads?
For AI products built with Assistant-UI, letting users resume conversations across page refreshes, tabs, and devices is essential for a polished experience. Assistant Cloud provides this persistence layer out-of-the-box, so you don’t have to build your own thread storage or session handling.
Below is a practical guide to setting up Assistant Cloud with Assistant-UI so conversations persist and users can resume threads reliably.
What Assistant-UI + Assistant Cloud Actually Do
Assistant-UI is an open‑source React toolkit that gives you a ChatGPT-style UX with:
- Production-ready chat components
- Streaming, interruptions, retries, and multi-turn conversations
- Support for Vercel AI SDK, LangChain, LangGraph, and other LLM providers
Assistant Cloud is the hosted backend that sits behind Assistant-UI and:
- Renders and manages the chat interface state
- Stores conversation threads in Assistant UI Cloud
- Ensures sessions persist across refreshes so users can resume threads later
When you connect Assistant-UI to Assistant Cloud, you get:
- Persistent conversation history per user/thread
- Seamless resume after page reloads or navigation
- A backend designed for high-performance streaming chat experiences
Prerequisites
Before integrating Assistant Cloud with Assistant-UI, you should have:
- A React app (Next.js, Create React App, etc.)
- Basic understanding of React components and hooks
- An LLM provider configured (e.g., OpenAI via Vercel AI SDK, LangChain, LangGraph, etc.)
You’ll also need access to Assistant Cloud (e.g., via an account, project, and API key) from the Assistant-UI ecosystem.
Step 1: Install and Initialize Assistant-UI
In your project root, install Assistant-UI using the official CLI:
npx assistant-ui init
This usually:
- Installs the core Assistant-UI packages
- Sets up base components and configuration
- Prepares your app to plug into cloud-based chat state, including Assistant Cloud
If you already have Assistant-UI installed, make sure you’re using a recent version so you can take advantage of the latest Cloud features.
Step 2: Configure Assistant Cloud Credentials
Assistant Cloud needs to know which project and environment it’s working with, and your app needs a way to authenticate requests.
Typically this involves:
-
Create a project in Assistant UI Cloud
- Log into the Assistant UI Cloud dashboard.
- Create a new project (e.g.,
my-chat-app). - Note the project ID and generate an API key.
-
Add environment variables to your app (naming may differ depending on the SDK, but conceptually you’ll have something like):
ASSISTANT_UI_CLOUD_PROJECT_ID=your_project_id
ASSISTANT_UI_CLOUD_API_KEY=your_api_key
- Expose configuration to your frontend via your chosen framework’s config pattern. For example, in Next.js:
// next.config.js
module.exports = {
env: {
NEXT_PUBLIC_ASSISTANT_UI_CLOUD_PROJECT_ID: process.env.ASSISTANT_UI_CLOUD_PROJECT_ID,
},
};
The API key is usually kept server-side, while a public project ID is safe to expose to the client.
Step 3: Wrap Your App in an Assistant Cloud Provider
Assistant-UI typically uses a provider component to handle:
- State management for multi-turn conversations
- Streaming and interruptions
- Thread storage integration with Assistant Cloud
In your root layout or App component, wrap your chat experience with a Cloud-aware provider. A pattern could look like:
import React from "react";
import { AssistantCloudProvider } from "@assistant-ui/cloud"; // naming may vary
import { Chat } from "@assistant-ui/react";
export default function App() {
return (
<AssistantCloudProvider
projectId={process.env.NEXT_PUBLIC_ASSISTANT_UI_CLOUD_PROJECT_ID!}
// Optionally pass a user identifier if you have auth
userId={/* your logged-in user id or anonymous id */}
>
<Chat />
</AssistantCloudProvider>
);
}
Key ideas:
AssistantCloudProvider(or equivalent) connects the frontend chat to the cloud backend.- It automatically handles thread creation, loading, and persistence in Assistant UI Cloud.
- It ensures context builds over time as users keep chatting.
Check the Assistant-UI docs for the exact provider and props names, but the pattern will be similar.
Step 4: Create a Chat Component Backed by Cloud Threads
Once the provider is in place, configure the chat UI to use cloud-backed state. Assistant-UI gives you production-ready components with sensible defaults, so in many cases you just need to:
import React from "react";
import { Chat } from "@assistant-ui/react";
export function CloudChat() {
return (
<div className="h-full flex flex-col">
<Chat
// Optional: pass a threadId if you want to load a specific prior conversation
// threadId={someThreadId}
// Optional: customize tools, prompts, system messages, etc.
/>
</div>
);
}
When used under the Cloud provider:
- Each new visitor can get a new thread stored in Assistant Cloud.
- Existing visitors can be attached to a previous threadId to resume where they left off.
- Streaming and UI updates are handled automatically.
Step 5: Persist and Resume Conversations per User
To make conversations persist in a meaningful way, you need two things:
- A stable user identifier
- A way to either auto-load or choose a thread for that user
5.1 Identify the User
If your app has login/auth:
- Use your authenticated
user.idas theuserIdin the Cloud provider. - All threads can then be scoped to that user.
If your app is anonymous:
- Generate and store a random ID in
localStorageor cookies. - Reuse that ID each time the user returns.
Example:
function getOrCreateAnonymousUserId() {
const key = "assistant-ui-anon-user";
let id = window.localStorage.getItem(key);
if (!id) {
id = crypto.randomUUID();
window.localStorage.setItem(key, id);
}
return id;
}
Then in your provider:
<AssistantCloudProvider
projectId={process.env.NEXT_PUBLIC_ASSISTANT_UI_CLOUD_PROJECT_ID!}
userId={getOrCreateAnonymousUserId()}
>
<CloudChat />
</AssistantCloudProvider>
5.2 Resume the Last Thread Automatically
Assistant Cloud stores conversation threads so sessions persist across refreshes. To resume the most recent thread:
- On app load, fetch the latest thread for that user from Assistant Cloud (via your backend or Cloud SDK).
- Pass the
threadIdinto your chat component.
Example flow (pseudo-code):
import { useEffect, useState } from "react";
import { Chat } from "@assistant-ui/react";
import { getLastThreadForUser } from "./cloud-api"; // your wrapper around Cloud
export function CloudChatWithResume({ userId }: { userId: string }) {
const [threadId, setThreadId] = useState<string | undefined>();
useEffect(() => {
async function loadLastThread() {
const lastThread = await getLastThreadForUser(userId);
if (lastThread) setThreadId(lastThread.id);
}
loadLastThread();
}, [userId]);
return <Chat threadId={threadId} />;
}
This pattern ensures:
- On first visit, no
threadIdmeans a new conversation is created and stored. - On subsequent visits, the last
threadIdis loaded, so the chat resumes where the user left off.
Step 6: Supporting Multiple Threads per User
Many apps need users to:
- Create new conversations
- Switch between existing threads
- Delete or archive old threads
With Assistant Cloud, you can:
- List threads for a user from your backend:
- Use the Cloud API/SDK to query threads by
userId.
- Use the Cloud API/SDK to query threads by
- Display a thread list UI:
- Show conversation titles, timestamps, etc.
- Switch threads by updating the
threadIdpassed to theChatcomponent.
Example (simplified):
function ThreadSidebar({
threads,
activeThreadId,
onSelectThread,
onNewThread,
}: {
threads: { id: string; title?: string }[];
activeThreadId?: string;
onSelectThread: (id: string) => void;
onNewThread: () => void;
}) {
return (
<div className="w-64 border-r">
<button onClick={onNewThread}>New conversation</button>
<ul>
{threads.map((t) => (
<li key={t.id}>
<button
className={t.id === activeThreadId ? "font-bold" : ""}
onClick={() => onSelectThread(t.id)}
>
{t.title ?? "Untitled conversation"}
</button>
</li>
))}
</ul>
</div>
);
}
Then your main layout:
export function ChatLayout({ userId }: { userId: string }) {
const [threads, setThreads] = useState<any[]>([]);
const [activeThreadId, setActiveThreadId] = useState<string | undefined>();
// Load threads from Assistant Cloud
useEffect(() => {
async function loadThreads() {
const list = await listThreadsForUser(userId); // Cloud API
setThreads(list);
if (list[0]) setActiveThreadId(list[0].id);
}
loadThreads();
}, [userId]);
async function handleNewThread() {
const newThread = await createThreadForUser(userId); // Cloud API
setThreads((prev) => [newThread, ...prev]);
setActiveThreadId(newThread.id);
}
return (
<div className="flex h-full">
<ThreadSidebar
threads={threads}
activeThreadId={activeThreadId}
onSelectThread={setActiveThreadId}
onNewThread={handleNewThread}
/>
<div className="flex-1">
<Chat threadId={activeThreadId} />
</div>
</div>
);
}
This architecture uses Assistant Cloud as your single source of truth for conversations, while Assistant-UI renders the UX.
Step 7: Ensuring Sessions Persist Across Refreshes
With the setup above, persistence comes from two layers working together:
-
Assistant Cloud
- Stores conversations and streaming output.
- Associates threads with a user (via
userId, metadata, etc.). - Keeps context building across multi-turn conversations.
-
Your App Logic
- Maintains stable
userIdacross sessions. - Fetches and reuses
threadIdon reload. - Optionally lets users choose different threads.
- Maintains stable
To verify persistence:
- Open your app and start a conversation.
- Refresh the page:
- The same
userIdshould be used. - Your logic should refetch the last thread.
- The chat UI should render with full history intact.
- The same
- Optionally open another browser or device:
- If you share the same
userId(e.g., logged-in user), the threads should appear and be resumable there as well.
- If you share the same
Step 8: Integrating with LangChain, LangGraph, or Vercel AI SDK
Assistant-UI works with:
- LangChain / LangGraph for stateful agents
- Vercel AI SDK or other LLM providers
- Custom backends and tools
Assistant Cloud doesn’t lock you into a single model provider; it focuses on:
- Chat state and thread persistence
- Streaming UX
- Human-in-the-loop workflows (especially with LangGraph Cloud + Assistant-UI)
When wiring in your model logic, ensure that:
- Requests contain the
threadIdso the backend knows which conversation to extend. - Any metadata you want to keep per thread is saved in Cloud so it’s available when the user resumes.
Common Pitfalls and How to Avoid Them
-
Conversations don’t persist after refresh
- Check that:
userIdis stable across page loads.- You’re fetching and passing a
threadIdto theChatcomponent. - Assistant Cloud credentials (projectId/API key) are correct.
- Check that:
-
Users share conversations unexpectedly
- Don’t use a hard-coded or global
userId. - Tie
userIdto logged-in user accounts or a stable anonymous ID.
- Don’t use a hard-coded or global
-
No threads appear for a returning user
- Confirm that you are:
- Creating threads in Cloud (inspect via dashboard/API).
- Querying threads by the same
userIdyou used when creating them.
- Confirm that you are:
How This Helps Your AI Product
Using Assistant Cloud with Assistant-UI allows you to:
- Deliver a ChatGPT-quality UX in your own app with minimal boilerplate.
- Ensure conversation persistence so users can resume threads naturally.
- Focus on your core AI logic (LLM prompts, tools, agents) instead of infrastructure.
By combining production-ready components, optimized streaming, and a cloud-based thread store, you can ship robust, stateful AI chat experiences much faster—and with a better user experience for conversation continuity.