This guide assumes that you have completed the Quickstart.
An example project demonstrating implementation of this guide can be found here.
Let users share an individual response via a share modal. You provide a generateShareLink(message) function that calls your backend and returns a URL. The SDK handles the modal UI, copying, and confirmation.
1

Frontend: Add a Share button to the response footer

Create a footer component using the pre-built ResponseFooter.ShareButton.
Footer.tsx
import { useThreadListState } from "@crayonai/react-core";
import { ResponseFooter } from "@thesysai/genui-sdk";

export const Footer = () => {
  const selectedThreadId = useThreadListState().selectedThreadId;

  return (
    <ResponseFooter.Container>
      <ResponseFooter.ShareButton
        generateShareLink={async (message) => {
          const messageId = message.id;
          const baseUrl = window.location.origin;
          return `${baseUrl}/shared/${selectedThreadId}/${messageId}`;
        }}
      />
    </ResponseFooter.Container>
  );
};
Then pass it to C1Chat:
App.tsx
import { C1Chat } from "@thesysai/genui-sdk";
import Footer from "./Footer";

export default function App() {
  return (
    <C1Chat
      apiUrl="/api/chat"
      customizeC1={{ responseFooterComponent: Footer }}
    />
  );
}
The button receives the full message object and opens a modal for link generation and copying.
2

Frontend: Add a component to render the shared message

Create a route and component on the frontend to render the shared message:
/app/shared/[threadId]/[messageId]/page.tsx
"use client";

import { Loader } from "@/app/components/Loader";
import type { Message } from "@crayonai/react-core";
import { C1ChatViewer } from "@thesysai/genui-sdk";
import { use, useEffect, useState } from "react";
import "@crayonai/react-ui/styles/index.css";

export default function ViewSharedMessage({
  params,
}: {
  params: Promise<{ threadId: string; messageId: string }>;
}) {
  const { threadId, messageId } = use(params);
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    const fetchMessages = async () => {
      const response = await fetch(`/api/share/${threadId}/${messageId}`);
      const messageResponse = (await response.json()) as {
        message: Message;
      };
      setMessages([messageResponse.message]);
    };
    fetchMessages();
  }, [messageId, threadId]);

  if (!messages || !messages.length) return <Loader fullScreen />;

  return <C1ChatViewer messages={messages} />;
}
3

Backend: Implement the message share endpoint

Implement an endpoint that returns the message for a given threadId and messageId.
Implement a message store to store the message history. If you’ve followed the Quickstart, you’ll have a message store already, which you can move to a common location (such as /lib/messageStore.ts) and modify it to persist message history across API routes and requests as follows:
/lib/messageStore.ts
import OpenAI from "openai";

export type DBMessage = OpenAI.Chat.ChatCompletionMessageParam & {
  id?: string;
};

const messagesStore: {
  [threadId: string]: DBMessage[];
} = {};

export const getMessageStore = (id: string) => {
  const messageList = await fetchMessagesFromDB(id); // fetch from db here
  return {
    addMessage: (message: DBMessage) => {
      // save to db here
    },
    messageList,
  };
};
/app/api/share/[threadId]/[messageId]/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getMessageStore } from "@/lib/messageStore";

export async function GET(
  req: NextRequest,
  { params }: { params: Promise<{ threadId: string; messageId: string }> }
) {
  const { threadId, messageId } = await params;

  if (!threadId || !messageId) {
    return NextResponse.json(
      { error: "Thread ID & Message ID are required" },
      { status: 400 }
    );
  }

  const messageStore = getMessageStore(threadId);
  const message = messageStore.messageList.find((m) => m.id === messageId);
  return NextResponse.json({ message: message ?? null });
}
4

Test it out!

  • Send a message and wait for the assistant response.
  • Click the share button in the footer.
  • Generate and copy the link from the modal.