> ## 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.

# Nuxt

> Add your Invent assistant to Nuxt 3 apps

## Overview

Add your Invent AI assistant to any Nuxt 3 application. Perfect for Vue.js applications with server-side rendering and static generation.

## Installation

<Steps>
  <Step title="Create Assistant Component">
    ```vue theme={"system"}
    <!-- components/InventAssistant.vue -->
    <template>
      <div>
        <invent-assistant
          :assistant-id="assistantId"
          :theme-appearance="themeAppearance"
          :theme-button-background-color="themeButtonBackgroundColor"
          :theme-button-color="themeButtonColor"
          :user-id="userId"
          :user-name="userName"
          :user-hash="userHash"
          :user-avatar="userAvatar"
        />
        <script
          type="text/javascript"
          src="https://www.useinvent.com/embed.js"
          async
          defer
        ></script>
      </div>
    </template>

    <script setup lang="ts">
    interface Props {
      assistantId: string;
      themeAppearance?: 'auto' | 'light' | 'dark';
      themeButtonBackgroundColor?: string;
      themeButtonColor?: string;
      userId?: string;
      userName?: string;
      userHash?: string;
      userAvatar?: string;
    }

    withDefaults(defineProps<Props>(), {
      themeAppearance: 'auto',
    });
    </script>
    ```
  </Step>

  <Step title="Add to App Layout">
    ```vue theme={"system"}
    <!-- app.vue or layouts/default.vue -->
    <template>
      <div>
        <NuxtPage />
        <InventAssistant :assistant-id="config.public.inventAssistantId" />
      </div>
    </template>

    <script setup lang="ts">
    const config = useRuntimeConfig();
    </script>
    ```
  </Step>

  <Step title="Configure Environment">
    Add to `nuxt.config.ts`:

    ```typescript theme={"system"}
    export default defineNuxtConfig({
      runtimeConfig: {
        inventSecretKey: process.env.INVENT_SECRET_KEY, // Private
        public: {
          inventAssistantId: process.env.NUXT_PUBLIC_INVENT_ASSISTANT_ID,
        },
      },
    });
    ```

    Add to `.env`:

    ```bash theme={"system"}
    NUXT_PUBLIC_INVENT_ASSISTANT_ID=ast_YOUR_ASSISTANT_ID
    INVENT_SECRET_KEY=your_secret_key_here
    ```
  </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

Use Nuxt server routes to generate the hash securely:

```typescript theme={"system"}
// server/api/user-hash.get.ts
import crypto from 'crypto';

export default defineEventHandler(async (event) => {
  // Get user from your auth system
  const session = await getUserSession(event);

  if (!session?.user) {
    throw createError({
      statusCode: 401,
      message: 'Unauthorized',
    });
  }

  const config = useRuntimeConfig();
  const userId = session.user.id;

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

  return {
    userId,
    userName: session.user.name,
    userAvatar: session.user.avatar,
    userHash,
  };
});
```

### Using in Component

```vue theme={"system"}
<!-- components/InventAssistant.vue -->
<template>
  <invent-assistant
    :assistant-id="config.public.inventAssistantId"
    :user-id="userData?.userId"
    :user-name="userData?.userName"
    :user-hash="userData?.userHash"
    :user-avatar="userData?.userAvatar"
  />
</template>

<script setup lang="ts">
const config = useRuntimeConfig();

const { data: userData } = await useFetch('/api/user-hash', {
  lazy: true,
  server: false,
});
</script>
```

## Integration with Nuxt Auth

### Using @sidebase/nuxt-auth

```vue theme={"system"}
<!-- app.vue -->
<template>
  <div>
    <NuxtPage />
    <InventAssistant
      :assistant-id="config.public.inventAssistantId"
      v-bind="userAuthData"
    />
  </div>
</template>

<script setup lang="ts">
const config = useRuntimeConfig();
const { data: session } = useAuth();

const userAuthData = computed(() => {
  if (!session.value?.user) return {};

  return {
    userId: session.value.user.id,
    userName: session.value.user.name,
    userAvatar: session.value.user.image,
    // Note: userHash should be fetched from API route
  };
});
</script>
```

## TypeScript Support

Add type declarations:

```typescript theme={"system"}
// types/invent-assistant.d.ts
declare module 'vue' {
  export interface GlobalComponents {
    '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;
    };
  }
}

export {};
```

## Composable for Authentication

Create a reusable composable:

```typescript theme={"system"}
// composables/useInventAuth.ts
export const useInventAuth = () => {
  const userData = useState<{
    userId: string;
    userName: string;
    userAvatar?: string;
    userHash: string;
  } | null>('inventUserData', () => null);

  const fetchUserAuth = async () => {
    try {
      const data = await $fetch('/api/user-hash');
      userData.value = data;
    } catch (error) {
      userData.value = null;
    }
  };

  return {
    userData: readonly(userData),
    fetchUserAuth,
  };
};
```

Usage:

```vue theme={"system"}
<template>
  <InventAssistant
    :assistant-id="config.public.inventAssistantId"
    v-bind="userData"
  />
</template>

<script setup lang="ts">
const config = useRuntimeConfig();
const { userData, fetchUserAuth } = useInventAuth();

onMounted(() => {
  fetchUserAuth();
});
</script>
```

## Tips for Nuxt

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

  <Card title="Composables" icon="puzzle-piece">
    Create reusable composables for auth logic
  </Card>

  <Card title="SSR Compatible" icon="bolt">
    Works with SSR, SSG, and SPA modes
  </Card>

  <Card title="Type Safe" icon="shield-check">
    Full TypeScript support
  </Card>
</CardGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Script not loading">
    **Solutions:**

    * Ensure plugin is client-side only (`.client.ts`)
    * Check that script loads after component mounts
    * Verify URL is correct
    * Check browser console for errors
  </Accordion>

  <Accordion title="SSR hydration mismatch">
    **Solutions:**

    * Use `ClientOnly` component if needed
    * Ensure script loads client-side only
    * Check that user data is fetched client-side
  </Accordion>

  <Accordion title="Environment variables not working">
    **Solutions:**

    * Restart dev server after adding env variables
    * Check `nuxt.config.ts` runtimeConfig
    * Use `NUXT_PUBLIC_` prefix for public variables
    * Keep secret key private (no prefix)
  </Accordion>
</AccordionGroup>

## Best Practices

<Note>
  * Use server routes for hash generation
  * Keep secret key in `.env` (never commit)
  * Use composables for reusable logic
  * Test in both SSR and SPA modes
  * Leverage Nuxt's built-in security features
</Note>
