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

# Next.js

> Add your Invent assistant to Next.js apps

## Overview

Add your Invent AI assistant to any Next.js application (App Router or Pages Router). Perfect for React-based applications with server-side rendering and static generation.

## Installation

### App Router (Next.js 13+)

<Steps>
  <Step title="Create Assistant Component">
    Create a client component for the assistant:

    ```tsx theme={"system"}
    // components/InventAssistant.tsx
    'use client';

    interface InventAssistantProps {
      assistantId: string;
      themeAppearance?: 'auto' | 'light' | 'dark';
      themeButtonBackgroundColor?: string;
      themeButtonColor?: string;
      userId?: string;
      userName?: string;
      userHash?: string;
      userAvatar?: string;
    }

    export default function InventAssistant({
      assistantId,
      themeAppearance = 'auto',
      themeButtonBackgroundColor,
      themeButtonColor,
      userId,
      userName,
      userHash,
      userAvatar,
    }: InventAssistantProps) {
      return (
        <>
          <invent-assistant
            assistant-id={assistantId}
            theme-appearance={themeAppearance}
            {...(themeButtonBackgroundColor && {
              'theme-button-background-color': themeButtonBackgroundColor,
            })}
            {...(themeButtonColor && {
              'theme-button-color': themeButtonColor,
            })}
            {...(userId && { 'user-id': userId })}
            {...(userName && { 'user-name': userName })}
            {...(userHash && { 'user-hash': userHash })}
            {...(userAvatar && { 'user-avatar': userAvatar })}
          />
          <script
            type="text/javascript"
            src="https://www.useinvent.com/embed.js"
            async
            defer
          />
        </>
      );
    }
    ```
  </Step>

  <Step title="Add to Root Layout">
    Import and use in your root layout:

    ```tsx theme={"system"}
    // app/layout.tsx
    import InventAssistant from '@/components/InventAssistant';

    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return (
        <html lang="en">
          <body>
            {children}
            <InventAssistant assistantId={process.env.NEXT_PUBLIC_INVENT_ASSISTANT_ID!} />
          </body>
        </html>
      );
    }
    ```
  </Step>

  <Step title="Add Environment Variable">
    Add to your `.env.local`:

    ```bash theme={"system"}
    NEXT_PUBLIC_INVENT_ASSISTANT_ID=ast_YOUR_ASSISTANT_ID
    ```
  </Step>
</Steps>

### Pages Router (Next.js 12 and below)

<Steps>
  <Step title="Create Assistant Component">
    ```tsx theme={"system"}
    // components/InventAssistant.tsx
    export default function InventAssistant({ assistantId }: { assistantId: string }) {
      return (
        <>
          <invent-assistant assistant-id={assistantId} />
          <script
            type="text/javascript"
            src="https://www.useinvent.com/embed.js"
            async
            defer
          />
        </>
      );
    }
    ```
  </Step>

  <Step title="Add to _app.tsx">
    ```tsx theme={"system"}
    // pages/_app.tsx
    import type { AppProps } from 'next/app';
    import InventAssistant from '@/components/InventAssistant';

    export default function App({ Component, pageProps }: AppProps) {
      return (
        <>
          <Component {...pageProps} />
          <InventAssistant assistantId={process.env.NEXT_PUBLIC_INVENT_ASSISTANT_ID!} />
        </>
      );
    }
    ```
  </Step>
</Steps>

## User Authentication

<Warning>
  **Security Requirement:** When using any `user-*` attributes (`user-id`, `user-name`, `user-avatar`), you **must** also provide `user-hash`. Both `user-id` and `user-hash` must be provided together, or neither should be provided. The `user-hash` must be generated on your backend using HMAC-SHA256 with your assistant's secret key. Never expose the secret key to the client.
</Warning>

### Server-Side Hash Generation

Next.js is perfect for secure hash generation with Server Components or API Routes.

#### Using Server Components (App Router)

```tsx theme={"system"}
// app/layout.tsx
import { cookies } from 'next/headers';
import { generateUserHash } from '@/lib/auth';
import InventAssistant from '@/components/InventAssistant';

async function getUserData() {
  // Get user from your auth system (NextAuth, Clerk, etc.)
  const session = await getSession();

  if (!session?.user) {
    return null;
  }

  const userId = session.user.id;
  const userHash = await generateUserHash(userId);

  return {
    userId,
    userName: session.user.name,
    userAvatar: session.user.image,
    userHash,
  };
}

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const userData = await getUserData();

  return (
    <html lang="en">
      <body>
        {children}
        <InventAssistant
          assistantId={process.env.NEXT_PUBLIC_INVENT_ASSISTANT_ID!}
          {...userData}
        />
      </body>
    </html>
  );
}
```

#### Hash Generation Helper

```typescript theme={"system"}
// lib/auth.ts
import crypto from 'crypto';

export async function generateUserHash(userId: string): Promise<string> {
  const secretKey = process.env.INVENT_SECRET_KEY;

  if (!secretKey) {
    throw new Error('INVENT_SECRET_KEY is not set');
  }

  return crypto
    .createHmac('sha256', secretKey)
    .update(userId)
    .digest('hex');
}
```

#### Using API Routes (Pages Router)

```typescript theme={"system"}
// pages/api/user-hash.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import crypto from 'crypto';
import { getSession } from 'next-auth/react';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const session = await getSession({ req });

  if (!session?.user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  const userId = session.user.id;
  const secretKey = process.env.INVENT_SECRET_KEY!;

  const userHash = crypto
    .createHmac('sha256', secretKey)
    .update(userId)
    .digest('hex');

  res.status(200).json({
    userId,
    userName: session.user.name,
    userAvatar: session.user.image,
    userHash,
  });
}
```

Then fetch this data in your component:

```tsx theme={"system"}
// components/InventAssistant.tsx
'use client';

import { useEffect, useState } from 'react';

export default function InventAssistant({ assistantId }: { assistantId: string }) {
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    fetch('/api/user-hash')
      .then((res) => res.json())
      .then(setUserData)
      .catch(console.error);
  }, []);

  // ... rest of component
}
```

## Integration with Auth Libraries

### NextAuth.js

```tsx theme={"system"}
// app/layout.tsx
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { generateUserHash } from '@/lib/auth';

export default async function RootLayout({ children }) {
  const session = await getServerSession(authOptions);

  let userData = null;
  if (session?.user) {
    userData = {
      userId: session.user.id,
      userName: session.user.name,
      userAvatar: session.user.image,
      userHash: await generateUserHash(session.user.id),
    };
  }

  return (
    <html>
      <body>
        {children}
        <InventAssistant
          assistantId={process.env.NEXT_PUBLIC_INVENT_ASSISTANT_ID!}
          {...userData}
        />
      </body>
    </html>
  );
}
```

### Clerk

```tsx theme={"system"}
// app/layout.tsx
import { currentUser } from '@clerk/nextjs';
import { generateUserHash } from '@/lib/auth';

export default async function RootLayout({ children }) {
  const user = await currentUser();

  let userData = null;
  if (user) {
    userData = {
      userId: user.id,
      userName: user.fullName,
      userAvatar: user.imageUrl,
      userHash: await generateUserHash(user.id),
    };
  }

  return (
    <html>
      <body>
        {children}
        <InventAssistant
          assistantId={process.env.NEXT_PUBLIC_INVENT_ASSISTANT_ID!}
          {...userData}
        />
      </body>
    </html>
  );
}
```

## TypeScript Support

Add type declarations for the custom element:

```typescript theme={"system"}
// types/invent-assistant.d.ts
declare namespace JSX {
  interface IntrinsicElements {
    'invent-assistant': {
      'assistant-id': string;
      'theme-appearance'?: 'auto' | 'light' | 'dark';
      'theme-button-background-color'?: string;
      'theme-button-color'?: string;
      'user-id'?: string;
      'user-name'?: string;
      'user-hash'?: string;
      'user-avatar'?: string;
    };
  }
}
```

## Tips for Next.js

<CardGroup cols={2}>
  <Card title="Server Components" icon="server">
    Use Server Components for secure hash generation
  </Card>

  <Card title="Environment Variables" icon="key">
    Keep INVENT\_SECRET\_KEY server-side only
  </Card>

  <Card title="TypeScript" icon="code">
    Add type definitions for better DX
  </Card>

  <Card title="SEO Friendly" icon="magnifying-glass">
    No impact on SEO or page performance
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Bubble not appearing in development">
    **Solutions:**

    * Check that the script is loaded after the component mounts
    * Verify assistant ID is correct
    * Check browser console for errors
    * Try clearing Next.js cache: `rm -rf .next`
  </Accordion>

  <Accordion title="TypeScript errors with custom element">
    **Solutions:**

    * Add type declarations file (see TypeScript Support section)
    * Ensure file is included in tsconfig.json
    * Restart TypeScript server
  </Accordion>

  <Accordion title="User hash not working">
    **Solutions:**

    * Verify secret key is set in environment variables
    * Ensure hash is generated server-side, not client-side
    * Check that both user-id and user-hash are provided
    * Validate HMAC-SHA256 implementation
  </Accordion>
</AccordionGroup>

## Best Practices

<Note>
  * Always use Server Components or API Routes for hash generation
  * Store secret key in `.env.local` (never commit to git)
  * Use `NEXT_PUBLIC_` prefix only for non-sensitive variables
  * Test authentication in both development and production
  * Consider using middleware for auth logic
</Note>
