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

# Add AI voice to a Next.js app on Vercel

> Embed the SmartAlex voice AI widget in a Next.js app with the next/script Script component (strategy afterInteractive) or a React component, then ship it on Vercel.

Next.js is the one place where the widget is a real, first-class component rather than a pasted string. You have two clean paths: the `next/script` **Script** component (the idiomatic way to load third-party scripts) or a small **React component** that mounts the script from a client effect. Both render your live agent "Alex" as a floating widget that can talk, qualify, and book. This is the fastest way to add an AI voice widget to Next.js and have it live on Vercel in one deploy.

Alex is backed by curated, high-accuracy speech, language, and voice models, kept abstracted behind the platform. You build and style the agent once inside SmartAlex; your Next.js app just loads one script.

<Info>
  The widget is a browser overlay, so it works the same whether you use the App Router or the Pages Router, and whether pages are statically generated, server-rendered, or use ISR. Rendering strategy does not matter: the script runs on the client after hydration.
</Info>

## Before you start

<Steps>
  <Step title="Have an agent ready">
    Create and deploy an agent in Studio first, so the widget has something to answer with. See [Create an agent](/studio/create-agent).
  </Step>

  <Step title="Grab your tenant id">
    Open Widget Studio in SmartAlex and copy the install code. It contains your workspace `data-tenant-id`. You can also get it from the MCP tool `smartalex_get_widget_install_code`. Full walkthrough: [Widget install](/essentials/widget-install).
  </Step>
</Steps>

## The one value you need

The widget takes a single attribute, `data-tenant-id`. There is no `data-variant`, `data-agent`, or `data-color`. The widget reads its published config (variant, colours, which agent) from the server at load time, so the snippet is identical for every variant and restyling in Widget Studio never means shipping a new deploy.

Keep the id in an environment variable so it is easy to change per environment. In Next.js, a value that must reach the browser has to be prefixed `NEXT_PUBLIC_`:

```bash .env.local theme={null}
NEXT_PUBLIC_SMARTALEX_TENANT_ID=YOUR_TENANT_ID
```

Set the same variable in the Vercel dashboard under **Project settings, Environment Variables** for Production, Preview, and Development.

## Option A: the next/script Script component

This is the recommended path. `next/script` de-duplicates the script across client-side navigations, controls when it loads, and keeps it out of your critical render path. Use `strategy="afterInteractive"` so the widget loads right after the page becomes interactive, not before first paint.

<CodeGroup>
  ```tsx app/layout.tsx (App Router) theme={null}
  import Script from "next/script";

  export default function RootLayout({
    children,
  }: {
    children: React.ReactNode;
  }) {
    return (
      <html lang="en">
        <body>
          {children}
          <Script
            src="https://api.getsmartalex.com/storage/v1/object/public/widget-assets/smartalex-widget.js"
            data-tenant-id={process.env.NEXT_PUBLIC_SMARTALEX_TENANT_ID}
            strategy="afterInteractive"
          />
        </body>
      </html>
    );
  }
  ```

  ```tsx pages/_app.tsx (Pages Router) theme={null}
  import type { AppProps } from "next/app";
  import Script from "next/script";

  export default function App({ Component, pageProps }: AppProps) {
    return (
      <>
        <Component {...pageProps} />
        <Script
          src="https://api.getsmartalex.com/storage/v1/object/public/widget-assets/smartalex-widget.js"
          data-tenant-id={process.env.NEXT_PUBLIC_SMARTALEX_TENANT_ID}
          strategy="afterInteractive"
        />
      </>
    );
  }
  ```
</CodeGroup>

<Note>
  Do not use `strategy="beforeInteractive"` for the widget. That strategy is meant for scripts the page cannot render without, and it must live in the document head. The widget is an overlay, so `afterInteractive` (or `lazyOnload` if you want it to wait until the browser is idle) is correct. `next/script` forwards the `data-tenant-id` attribute straight through to the injected `<script>` tag, which is exactly what the widget reads.
</Note>

## Option B: a reusable React component

If you would rather keep the widget in its own component (for example to mount it only on certain routes, or behind a cookie-consent gate), inject it from a client effect. Mark the file with `"use client"` in the App Router.

```tsx components/SmartAlexWidget.tsx theme={null}
"use client";

import { useEffect } from "react";

export default function SmartAlexWidget() {
  useEffect(() => {
    const script = document.createElement("script");
    script.src =
      "https://api.getsmartalex.com/storage/v1/object/public/widget-assets/smartalex-widget.js";
    script.setAttribute(
      "data-tenant-id",
      process.env.NEXT_PUBLIC_SMARTALEX_TENANT_ID ?? "",
    );
    script.async = true;
    document.body.appendChild(script);
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  return null;
}
```

Render it once, near the root, so it persists across route changes:

```tsx app/layout.tsx theme={null}
import SmartAlexWidget from "@/components/SmartAlexWidget";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <SmartAlexWidget />
      </body>
    </html>
  );
}
```

<Tip>
  Prefer Option A for a site-wide widget. Reach for Option B when you need conditional mounting: render `<SmartAlexWidget />` only after a consent flag is set, or only inside a marketing layout, and the effect cleanup removes the script when the component unmounts.
</Tip>

## Ship it on Vercel

<Steps>
  <Step title="Set the environment variable">
    In the Vercel dashboard, add `NEXT_PUBLIC_SMARTALEX_TENANT_ID` under **Project settings, Environment Variables** for all environments you deploy.
  </Step>

  <Step title="Push and let Vercel build">
    Push to your connected Git branch (or run `vercel --prod`). Because the widget is a runtime browser overlay, nothing special is needed in `next.config.js`, and no serverless function or edge middleware is involved.
  </Step>

  <Step title="Verify on the deployed URL">
    Open the deployment. You should see the widget anchored to the corner. In DevTools, confirm a request to `api.getsmartalex.com` for `smartalex-widget.js`.
  </Step>
</Steps>

<Note>
  No Content Security Policy is set by default in Next.js. If you have added a strict CSP (via headers in `next.config.js` or middleware), allow `https://api.getsmartalex.com` in `script-src` and `connect-src` so the widget can load and connect.
</Note>

## How the pieces fit together

```mermaid theme={null}
flowchart LR
  A[Widget Studio: pick variant, style, agent] --> B[Publish config to SmartAlex]
  C[next/script or React component with tenant id] --> D[Deploy on Vercel]
  D --> E[Visitor loads a page, hydration completes]
  E --> F[Script loads afterInteractive, fetches config by tenant id]
  B --> F
  F --> G[Widget renders and connects to Alex]
```

Because the config lives on the server, you can restyle the widget or swap the agent in Widget Studio and the change is live with no rebuild and no redeploy on Vercel.

## Choosing a widget variant

You pick the look and interaction inside Widget Studio, not in code. Five variants are available:

| Variant        | Interaction    | What visitors see                                  |
| -------------- | -------------- | -------------------------------------------------- |
| Pill (default) | Voice and chat | Compact floating button that expands into chat     |
| Chat bar       | Text           | Always-visible input bar at the bottom of the page |
| Side panel     | Text           | Full-height panel that slides in from the right    |
| Voice pill     | Voice only     | Voice-only pill with avatar and a call button      |
| Ask Alex       | Voice and text | Premium voice and chat messenger, live on the page |

<Note>
  **Voice pill** and **Ask Alex** only appear in the picker when your agent runs on the SmartAlex voice engine. **Ask Alex** also enables a persistent pop-up call that survives page navigation, which pairs well with a single-page-app router. Only one widget is active per workspace at a time, so the newest saved config wins. See [Widget variants](/essentials/widgets) for the full breakdown.
</Note>

## Operate the account from your editor

Since you are already in a Next.js codebase, you can drive SmartAlex from the same AI editor you build in. The MCP server exposes 28 tools (contacts, agents, campaigns, deals, and widget install code) to Claude Code, Cursor, VS Code, and other MCP clients. Add the hosted server with one command:

```bash theme={null}
claude mcp add --transport http smartalex https://api.getsmartalex.com/functions/v1/mcp-server
```

Then ask it to "give me the widget install code for my workspace" or "list my deployed agents" without leaving your editor. API keys for the MCP server require the Power Tools add-on (\$29/month) and a super-admin role. See [MCP overview](/mcp/overview).

## Troubleshooting

* **Widget not showing?** Confirm `NEXT_PUBLIC_SMARTALEX_TENANT_ID` is set (client variables must carry the `NEXT_PUBLIC_` prefix), then check the console for the request to `api.getsmartalex.com`.
* **Works in dev, missing on Vercel?** The variable exists in `.env.local` but not in Vercel. Add it in **Project settings, Environment Variables** and redeploy.
* **Blocked by CSP?** Allow `https://api.getsmartalex.com` in `script-src` and `connect-src`.
* **Wrong style or agent?** That is controlled in Widget Studio, not the code. Save the correct config there; the page picks it up on next load.

## Related

<CardGroup cols={2}>
  <Card title="Widget install guide" icon="code" href="/essentials/widget-install">
    The canonical install reference: snippet, React usage, and verification.
  </Card>

  <Card title="Widget variants" icon="layout-panel-left" href="/essentials/widgets">
    Compare the five variants and pick the right interaction model.
  </Card>

  <Card title="Build with v0, Cursor and Bolt" icon="wand-magic-sparkles" href="/build-with/cursor-v0-bolt">
    Generated the Next.js app with an AI builder? Drop the widget in the same way.
  </Card>

  <Card title="Operate SmartAlex over MCP" icon="plug" href="/mcp/overview">
    Drive contacts, agents, and campaigns from Claude Code, Cursor, or VS Code.
  </Card>
</CardGroup>
