Skip to main content

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+)

1

Create Assistant Component

Create a client component for the assistant:
// 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/button.js"
        async
        defer
      />
    </>
  );
}
2

Add to Root Layout

Import and use in your root layout:
// 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>
  );
}
3

Add Environment Variable

Add to your .env.local:
NEXT_PUBLIC_INVENT_ASSISTANT_ID=ast_YOUR_ASSISTANT_ID

Pages Router (Next.js 12 and below)

1

Create Assistant Component

// 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/button.js"
        async
        defer
      />
    </>
  );
}
2

Add to _app.tsx

// 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!} />
    </>
  );
}

User Authentication

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.

Server-Side Hash Generation

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

Using Server Components (App Router)

// 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

// 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)

// 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:
// 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

// 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

// 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:
// 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

Server Components

Use Server Components for secure hash generation

Environment Variables

Keep INVENT_SECRET_KEY server-side only

TypeScript

Add type definitions for better DX

SEO Friendly

No impact on SEO or page performance

Troubleshooting

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
Solutions:
  • Add type declarations file (see TypeScript Support section)
  • Ensure file is included in tsconfig.json
  • Restart TypeScript server
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

Best Practices

  • 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