# Add an assistant to a Next.js app

> Sign up on Super Assist, create an agent and a project, and put the project's assistant beside a Next.js page it reads and acts on.

In this tutorial you sign up on Super Assist, create an agent and a project, and put the project's assistant beside an Orders page in a new Next.js app. The assistant replies from Super Assist, answers from what the page shows, and ships an order when you ask. You write no backend.

You need Node.js and npm.

An agent answers on your organization's AI spend. The Pro plan includes some every month; the Free plan runs agents only on credits bought in **Billing**. This tutorial uses Pro.

## 1. Sign up

1. Open [superassist.app/app/sign-up](https://superassist.app/app/sign-up), fill in your name, email and password, and press **Sign up**.
2. Open the verification link Super Assist emails you.
3. Name your organization and press **Create organization**.
4. In the sidebar, open **Billing** and press **Upgrade to Pro**.

## 2. Create an agent

The agent is the assistant that answers in your app: its instructions, its model, and the skills, databases and knowledge bases it may use.

1. Open **Agents** and press **New agent**.
2. Name it `shop-assistant`.
3. Above **Instructions**, press **Start from a template** and pick **General assistant**.
4. Press **Create agent**.

For a support agent with its skills ready, press **Install a template** instead and pick `saas-support`. [Templates](https://superassist.app/dashboard/templates.md) says what to replace before it goes live.

## 3. Create a project and copy its publishable key

The project is your app on Super Assist. It holds the publishable key your pages connect with, the origins it accepts, and the agent that answers.

1. Open **Projects** and press **New project**.
2. Name it `My shop`. **Default agent** already shows `shop-assistant`, your only agent. Press **Create**.
3. On the project's page, press **Copy** beside **Publishable key**. It starts with `pk_`.

The key is safe to ship in your app's bundle: it only opens threads with the project's agent. **Allowed origins** lists `http://localhost:3000`, where your app is about to run.

## 4. Create the app

Create a Next.js app with the default setup, TypeScript, Tailwind and the App Router, and install the library:

```bash
npx create-next-app@latest my-shop --yes
cd my-shop
npm install @super-assist/react
```

That one package brings the panel, its styles and the runtime.

Put the publishable key in `.env.local`:

```sh title="my-shop/.env.local"
NEXT_PUBLIC_SUPER_ASSIST_KEY=pk_...
```

## 5. Mount the panel

Create `app/assistant.tsx`. It imports the panel's styles, connects to your project with `useAssistedRuntime`, and renders the panel inside `AssistedProvider`:

```tsx title="my-shop/app/assistant.tsx"
"use client";

import type { ReactNode } from "react";
import { AssistedPanel, AssistedProvider, useAssistedRuntime } from "@super-assist/react";
import "@super-assist/react/styles.css";

export function Assistant({ children }: { children: ReactNode }) {
  const runtime = useAssistedRuntime({ key: process.env.NEXT_PUBLIC_SUPER_ASSIST_KEY! });
  return (
    <AssistedProvider runtime={runtime}>
      <main className="min-h-dvh p-6">{children}</main>
      <AssistedPanel mode="floating" threads />
    </AssistedProvider>
  );
}
```

`threads` adds a menu of your threads to the panel's header. Super Assist keeps them.

In `app/layout.tsx`, wrap the children in `Assistant`. Keep the scaffold's fonts and metadata, and change only the body:

```tsx title="my-shop/app/layout.tsx"
import { Assistant } from "./assistant";
```

```tsx title="my-shop/app/layout.tsx"
<body>
  <Assistant>{children}</Assistant>
</body>
```

## 6. See a reply

Replace `app/page.tsx` with a plain Orders page. Its orders live in state, so shipping one changes the page:

```tsx title="my-shop/app/page.tsx"
"use client";

import { useState } from "react";

type Order = { id: string; customer: string; status: "to ship" | "shipped" };

const seed: Order[] = [
  { id: "1042", customer: "Acme", status: "to ship" },
  { id: "1043", customer: "Globex", status: "to ship" },
  { id: "1045", customer: "Initech", status: "shipped" },
];

export default function Orders() {
  const [orders, setOrders] = useState(seed);
  const ship = (id: string) =>
    setOrders((all) =>
      all.map((order) => (order.id === id ? { ...order, status: "shipped" } : order)),
    );
  return (
    <ul className="flex flex-col gap-2">
      {orders.map((order) => (
        <li key={order.id} className="flex items-center gap-4">
          #{order.id} {order.customer}, {order.status}
          {order.status === "to ship" && (
            <button className="rounded border px-2 py-1 text-sm" onClick={() => ship(order.id)}>
              Ship
            </button>
          )}
        </li>
      ))}
    </ul>
  );
}
```

Start the app:

```bash
npm run dev
```

Open `http://localhost:3000`. The three orders show, and an **Assistant** button sits in the bottom-right corner. Press it and the panel opens. Ask "What can you do?".

Your agent replies from Super Assist. It can't see the orders yet, because the page hasn't introduced itself.

## 7. Let the assistant read and act

Wrap the page in `AssistedPage`, which gives it a name, instructions for working there, and its content. The content is a function, read only when the assistant asks for it. Then wrap each **Ship** button in `AssistedAction`. Every row uses the name `ship_order` with its own `id`, so the assistant sees one action that picks a row by id:

```tsx title="my-shop/app/page.tsx"
"use client";

import { AssistedAction, AssistedPage } from "@super-assist/react";
import { useState } from "react";

type Order = { id: string; customer: string; status: "to ship" | "shipped" };

const seed: Order[] = [
  { id: "1042", customer: "Acme", status: "to ship" },
  { id: "1043", customer: "Globex", status: "to ship" },
  { id: "1045", customer: "Initech", status: "shipped" },
];

export default function Orders() {
  const [orders, setOrders] = useState(seed);
  const ship = (id: string) =>
    setOrders((all) =>
      all.map((order) => (order.id === id ? { ...order, status: "shipped" } : order)),
    );
  return (
    <AssistedPage
      name="Orders"
      instructions="Every order of the shop. Ship an order that is waiting to ship by its id."
      content={() => orders}
    >
      <ul className="flex flex-col gap-2">
        {orders.map((order) => (
          <li key={order.id} className="flex items-center gap-4">
            #{order.id} {order.customer}, {order.status}
            {order.status === "to ship" && (
              <AssistedAction
                name="ship_order"
                id={order.id}
                label={`Ship ${order.customer}'s order #${order.id}`}
              >
                <button className="rounded border px-2 py-1 text-sm" onClick={() => ship(order.id)}>
                  Ship
                </button>
              </AssistedAction>
            )}
          </li>
        ))}
      </ul>
    </AssistedPage>
  );
}
```

The panel's header now reads "On Orders". Ask "Which orders are waiting to ship?".

The assistant calls `get_page_content` first, and its answer names Acme's #1042 and Globex's #1043.

Ask "Ship Globex's order."

The assistant calls `ship_order` with the id `1043`, which presses Globex's **Ship** button. The row now reads "shipped", its button is gone, and the assistant tells you the order shipped.

## What you built

A Next.js app whose assistant runs on Super Assist. The project's agent answers, the Orders page introduces itself and lends its content on demand, and each row lends an action the agent presses by id.

Next:

- [Make an action consequential](https://superassist.app/how-to/make-an-action-consequential.md), so the user presses it or approves it.
- [Lend a form's fields](https://superassist.app/how-to/lend-form-fields.md), so the assistant fills them.
- [Add `go_to_page`](https://superassist.app/how-to/add-go-to-page.md) once the app has more than one page.
- [Place the panel](https://superassist.app/how-to/place-the-panel.md) as a sheet or embedded, and [rearrange its parts](https://superassist.app/how-to/rearrange-the-panel.md).
- [Mount the devtools](https://superassist.app/how-to/mount-devtools.md) to see what the page lends.
- [Use the hosted runtime](https://superassist.app/how-to/use-the-hosted-runtime.md) to name your signed-in users, and to accept your production origin before you deploy.
- [How a turn is answered](https://superassist.app/explanation/how-a-turn-is-answered.md), from the project and its agent to what the page lends.
