Skip to main content
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.