Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/farrugiag/open-chat-widget/llms.txt

Use this file to discover all available pages before exploring further.

The dashboard provides an intuitive interface for viewing all chat conversations captured by your widget or headless API.

Conversation List

The main dashboard page (/) displays all conversations in chronological order, with the most recently updated conversations at the top.

What You See

Each conversation card shows:
  • Session ID: The unique identifier for the chat session
  • Last Updated: Timestamp of the most recent message
  • Last Message Preview: A snippet of the most recent message content
From dashboard/app/page.tsx:38:
conversations.map((conversation) => (
  <Link
    key={conversation._id}
    className="card"
    href={`/conversations/${conversation._id}`}
  >
    <div className="card-title">Session: {conversation.sessionId}</div>
    <div className="card-time">Updated {formatDate(conversation.updatedAt)}</div>
    <div className="card-last">
      {conversation.lastMessage?.trim() || "No messages in this conversation"}
    </div>
  </Link>
))

Empty State

If no conversations exist yet, you’ll see a helpful message:
No conversations yet Messages from the widget will appear here.

Session ID Grouping

Conversations are organized by sessionId, which is provided by:
  • The widget (automatically generated or custom)
  • Your headless API implementation
Each unique sessionId creates a separate conversation thread. This allows you to:
  • Track individual user journeys
  • Group messages from the same session
  • Identify returning users (if you persist sessionId)

Example Session IDs

// Auto-generated by widget
"session_abc123xyz"

// Custom session from your app
"user_12345_chat"

// Anonymous visitor
"anon_visitor_xyz"

Individual Conversation View

Click any conversation card to view the full message thread.

Conversation Details

The conversation detail page shows:
  • Session ID: Displayed in the page header
  • Last Updated: Timestamp of most recent activity
  • Full Message Thread: All messages in chronological order

Message Threading

Messages are displayed with:
  • Role: User or Assistant
  • Timestamp: When the message was created
  • Content: Full message text
From dashboard/app/conversations/[id]/page.tsx:44:
<section className="thread">
  {thread.messages.map((message) => (
    <article
      key={message._id}
      className={`thread-message ${message.role === "user" ? "user" : "assistant"}`}
    >
      <div className="thread-meta">
        {message.role === "user" ? "User" : "Assistant"}{formatDate(message.createdAt)}
      </div>
      <div>{message.content}</div>
    </article>
  ))}
</section>

Visual Design

Messages are styled differently based on role:
  • User messages: Styled with the user class for visual distinction
  • Assistant messages: Styled with the assistant class
This makes it easy to follow the conversation flow at a glance.

Data Source

The dashboard fetches data directly from Convex using server-side queries:

List Conversations

From dashboard/lib/convex.ts:38:
export async function listConversations(): Promise<ConversationSummary[]> {
  const client = getClient();
  const conversations = await client.query(anyApi.conversations.listConversations, {});

  return conversations as ConversationSummary[];
}

Get Conversation Thread

From dashboard/lib/convex.ts:45:
export async function getConversationThread(
  conversationId: string
): Promise<ConversationThread | null> {
  const client = getClient();
  const thread = await client.query(anyApi.conversations.getConversationThread, {
    conversationId
  });

  return thread as ConversationThread | null;
}
When viewing an individual conversation, a back link is provided:
<Link className="back-link" href="/">
  ← Back to conversations
</Link>
This allows quick navigation back to the main list.

URL Structure

/                              # Main conversation list
/conversations/:conversationId # Individual conversation view
Conversation IDs are Convex document IDs, ensuring stable URLs.

Data Types

The dashboard works with strongly-typed data:

ConversationSummary

type ConversationSummary = {
  _id: string;          // Convex document ID
  sessionId: string;    // User-provided session identifier
  createdAt: number;    // Unix timestamp (ms)
  updatedAt: number;    // Unix timestamp (ms)
  lastMessage: string;  // Preview of most recent message
};

ConversationMessage

type ConversationMessage = {
  _id: string;                    // Convex document ID
  role: "user" | "assistant";      // Message author
  content: string;                // Message text
  createdAt: number;              // Unix timestamp (ms)
};

ConversationThread

type ConversationThread = {
  conversation: ConversationSummary;
  messages: ConversationMessage[];
};

Timestamp Formatting

All timestamps are formatted using the Intl.DateTimeFormat API:
function formatDate(timestamp: number): string {
  return new Intl.DateTimeFormat("en-US", {
    dateStyle: "medium",
    timeStyle: "short"
  }).format(new Date(timestamp));
}
Example output: Mar 3, 2026, 2:30 PM

Real-Time Updates

The dashboard uses Next.js Server Components, which means:
  • Data is fetched on every page load
  • Refreshing the page shows the latest conversations
  • No client-side polling or websockets needed
To see new messages, simply refresh the page or navigate back to the conversation list.

Error Handling

Conversation Not Found

If you navigate to a conversation that doesn’t exist, Next.js shows a 404 page:
dashboard/app/conversations/[id]/page.tsx
const thread = await getConversationThread(id);

if (!thread) {
  notFound(); // Returns 404 page
}

Missing Convex Configuration

If CONVEX_URL is not configured, an error is thrown when trying to fetch data:
if (!url) {
  throw new Error("CONVEX_URL or NEXT_PUBLIC_CONVEX_URL is required for dashboard");
}
Ensure this environment variable is set in your deployment.

Build docs developers (and LLMs) love