> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thesys.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Sharing a Single Message

> Enable users to generate a shareable link for an individual message.

<Note>
  This guide assumes that you have completed the [Quickstart](/guides/conversational/getting-started).
</Note>

<Tip>
  An example project demonstrating implementation of this guide can be found
  [here](https://github.com/thesysdev/examples/tree/main/sharing-generated-ui).
</Tip>

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.

<Steps>
  <Step title="Frontend: Add a Share button to the response footer">
    Create a footer component using the pre-built `ResponseFooter.ShareButton`.

    ```tsx Footer.tsx theme={null}
    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`:

    ```tsx App.tsx theme={null}
    import { C1Chat } from "@thesysai/genui-sdk";
    import Footer from "./Footer";

    export default function App() {
      return (
        <C1Chat
          apiUrl="/api/chat"
          customizeC1={{ responseFooterComponent: Footer }}
        />
      );
    }
    ```

    <Tip>
      The button receives the full `message` object and opens a modal for link generation and copying.
    </Tip>
  </Step>

  <Step title="Frontend: Add a component to render the shared message">
    Create a route and component on the frontend to render the shared message:

    ```tsx /app/shared/[threadId]/[messageId]/page.tsx [expandable] theme={null}
    "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} />;
    }
    ```
  </Step>

  <Step title="Backend: Implement the message share endpoint">
    Implement an endpoint that returns the message for a given `threadId` and `messageId`.

    <Note>
      Implement a message store to store the message history. If you've followed the [Quickstart](/guides/conversational/persistence), 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:

      ```ts /lib/messageStore.ts focus={12, 15} [expandable] theme={null}
      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,
        };
      };
      ```
    </Note>

    ```ts /app/api/share/[threadId]/[messageId]/route.ts theme={null}
    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 });
    }
    ```
  </Step>

  <Step title="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.
  </Step>
</Steps>
