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

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 });
}
3

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.