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

# Embed Widget

> Add the Argide widget to your website

## Installation

Choose your preferred installation method:

<Tabs>
  <Tab title="Script Tag">
    Add the script before `</body>`:

    <CodeGroup>
      ```html HTML theme={null}
      <script
        src="https://dashboard.argide.ai/argide-b2b-widget.iife.js"
        data-api-url="https://dashboard.argide.ai"
        data-product-id="YOUR_PRODUCT_ID"
        data-agent-name="Your Agent Name"
      ></script>
      ```

      ```jsx Next.js theme={null}
      import Script from 'next/script'

      export default function Layout({ children }) {
        return (
          <>
            {children}
            <Script
              src="https://dashboard.argide.ai/argide-b2b-widget.iife.js"
              data-api-url="https://dashboard.argide.ai"
              data-product-id="YOUR_PRODUCT_ID"
              data-agent-name="Your Agent Name"
              strategy="afterInteractive"
            />
          </>
        )
      }
      ```
    </CodeGroup>

    | Attribute         | Required | Description                            |   |
    | ----------------- | -------- | -------------------------------------- | - |
    | `data-api-url`    | Yes      | `https://dashboard.argide.ai`          |   |
    | `data-product-id` | Yes      | Your product ID from dashboard         |   |
    | `data-agent-name` | No       | Display name (defaults to "Assistant") |   |

    After the script loads, use `window.argide()` to pass functions and objects:

    | Command                   | Description                                                          |
    | ------------------------- | -------------------------------------------------------------------- |
    | `setIdentityTokenFetcher` | Auto-refreshing JWT function. See [Identity](#user-identity)         |
    | `setContext`              | Page context object. See [Context](#page-context)                    |
    | `onToolResult`            | Callback on tool completion. See [Callbacks](#tool-result-callbacks) |
    | `registerToolRenderers`   | Custom inline visuals. See [Renderers](#tool-renderers)              |
    | `identify`                | Manual JWT token (alternative to fetcher)                            |
    | `registerTools`           | Client-side tool handlers                                            |
    |                           |                                                                      |
  </Tab>

  <Tab title="React SDK">
    Install the SDK:

    ```bash theme={null}
    npm install @argide/client @argide/ui
    ```

    Add to your app:

    ```tsx theme={null}

    import { ArgideWidget } from '@argide/ui';
    import '@argide/ui/styles.css';

    export function ArgideWidgetClient() {
      return (
        <ArgideWidget
          productId="YOUR_PRODUCT_ID"
          apiUrl="https://dashboard.argide.ai"
          agentName="Your Agent Name"
        />
      );
    }
    ```

    | Prop               | Required | Description                                                                                                         |
    | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------- |
    | `productId`        | Yes      | Your product ID from dashboard                                                                                      |
    | `apiUrl`           | Yes      | `https://dashboard.argide.ai`                                                                                       |
    | `agentName`        | No       | Display name (defaults to "Assistant")                                                                              |
    | `getIdentityToken` | No       | Async function returning a JWT. Auto-refreshes on expiry. See [Identity Verification](/setup/identity-verification) |
    | `context`          | No       | Page context object sent with every message. Reactive — updates when the object changes                             |
    | `toolRenderers`    | No       | Map of tool name → React component for inline rendering. See [Tool Renderers](/integration/tool-renderers)          |
    | `onToolResult`     | No       | Callback `(toolName, result) => void` fired when a server-side tool completes                                       |
    | `navigate`         | No       | SPA navigation function (e.g. `router.push`) for internal links                                                     |

    <Accordion title="Copilot Sidebar">
      A full-height sidebar that automatically pushes your page content aside. Wrap your app with `ArgideProvider` and place `ArgideCopilot` alongside your app:

      ```bash theme={null}
      npm install @argide/client @argide/ui
      ```

      ```tsx theme={null}
      import { ArgideProvider, ArgideCopilot } from '@argide/ui';
      import '@argide-ai/ui/styles.css';

      function App() {
        return (
          <ArgideProvider
            productId="YOUR_PRODUCT_ID"
            apiUrl="https://dashboard.argide.in"
          >
            <YourApp />
            <ArgideCopilot position="right" width={400} />
          </ArgideProvider>
        );
      }
      ```
    </Accordion>
  </Tab>
</Tabs>

## Find Your Product ID

1. Go to [dashboard.argide.ai/dashboard/deploy/widget](https://dashboard.argide.ai/dashboard/deploy/widget)
2. Copy your Product ID

***

## User Identity

Authenticate users for persistent conversations and user-specific actions.

<Tabs>
  <Tab title="Script Tag">
    **Option A — Auto-refresh (recommended).** Pass a function that fetches a JWT. The SDK calls it on mount and re-calls it automatically when the token expires (401):

    ```javascript theme={null}
    window.argide('setIdentityTokenFetcher', async () => {
      const res = await fetch('/api/argide-token');
      const { token } = await res.json();
      return token;
    });
    ```

    **Option B — Manual.** Pass a static token (you handle refresh yourself):

    ```javascript theme={null}
    window.argide('identify', {
      token: 'jwt-from-your-backend',  // Required
      name: 'John Doe'                  // Optional
    })

    // On logout
    window.argide('resetUser')
    ```
  </Tab>

  <Tab title="React SDK">
    Pass `getIdentityToken` — the SDK handles calling it on mount and auto-refreshing on expiry:

    ```tsx theme={null}
    import { ArgideWidget } from '@argide-ai/ui';

    function App() {
      return (
        <ArgideWidget
          productId="YOUR_PRODUCT_ID"
          apiUrl="https://api.argide.ai"
          getIdentityToken={async () => {
            const res = await fetch('/api/argide-token');
            const { token } = await res.json();
            return token;
          }}
        />
      );
    }
    ```
  </Tab>
</Tabs>

See [Identity Verification](/setup/identity-verification) for backend JWT setup.

***

## Client-Side Tools

Register tools the agent can call. The return value from your handler is sent back to the agent, so it can confirm success or handle errors intelligently.

See [Client-Side Tools](/integration/client-side-tools) for full setup.

<Tabs>
  <Tab title="Script Tag">
    ```javascript theme={null}
    window.argide('registerTools', {
      navigateToPage: async ({ path }) => {
        router.push(path)
        return { success: true }  // Agent sees this result
      },

      showUpgradeModal: async () => {
        document.getElementById('upgrade-modal').showModal()
        return { shown: true }
      }
    })
    ```
  </Tab>

  <Tab title="React SDK">
    ```tsx theme={null}
    import { ArgideWidget } from '@argide-ai/ui';

    function App() {
      const tools = {
        navigateToPage: async ({ path }) => {
          router.push(path);
          return { success: true };  // Agent sees this result
        },

        showUpgradeModal: async () => {
          document.getElementById('upgrade-modal').showModal();
          return { shown: true };
        }
      };

      return (
        <ArgideWidget
          productId="YOUR_PRODUCT_ID"
          apiUrl="https://api.argide.ai"
          tools={tools}
        />
      );
    }
    ```
  </Tab>
</Tabs>

<Tip>
  Return meaningful results from your tools. The agent uses these to provide accurate feedback like "Done! I've navigated you to Settings" or handle errors gracefully.
</Tip>

***

## Tool Result Callbacks

React to server-side tool completions — refresh data, show a diff UI, dispatch events, etc.

<Tabs>
  <Tab title="Script Tag">
    ```javascript theme={null}
    window.argide('onToolResult', (toolName, result) => {
      if (toolName === 'propose_revision') {
        showDiffUI(result);
      }
    });
    ```
  </Tab>

  <Tab title="React SDK">
    ```tsx theme={null}
    <ArgideWidget
      onToolResult={(toolName, result) => {
        if (toolName === 'propose_revision') showDiffUI(result);
      }}
      ...
    />
    ```
  </Tab>
</Tabs>

***

## Tool Renderers

Render custom visuals inline in the chat when a tool completes — data cards, tables, charts, and more.

Your renderer receives `{ result, status }` and returns one of:

| Return type     | Use case                                 |
| --------------- | ---------------------------------------- |
| **HTML string** | Data cards, tables, simple visuals       |
| **HTMLElement** | Charts via Chart.js, D3, ECharts, Plotly |
| **ReactNode**   | Full React components (React SDK only)   |

<Tabs>
  <Tab title="Script Tag">
    ### Data Card

    Show key metrics with change indicators:

    ```javascript theme={null}
    window.argide('registerToolRenderers', {
      query_analytics_chart: ({ result }) => {
        const r = result || {};
        const color = r.changePercent > 0 ? '#059669' : '#ef4444';
        const arrow = r.changePercent > 0 ? '↑' : '↓';
        return `<div style="padding:12px; border:1px solid #e2e8f0; border-radius:8px; background:#fff; font-family:system-ui,sans-serif;">
          <div style="font-size:13px; font-weight:600; color:#0f172a;">${r.title || 'Metric'}</div>
          <div style="font-size:24px; font-weight:700; color:#2563eb; margin-top:4px;">${r.currentValue || 'N/A'}</div>
          ${r.changePercent != null
            ? `<div style="font-size:12px; color:${color};">${arrow} ${Math.abs(r.changePercent).toFixed(1)}%</div>`
            : ''}
          ${r.dashboard_url
            ? `<a href="${r.dashboard_url}" target="_blank" style="font-size:11px; color:#2563eb; text-decoration:none; margin-top:8px; display:inline-block;">View full chart ↗</a>`
            : ''}
        </div>`;
      }
    });
    ```

    ### Table

    Display structured data in rows and columns:

    ```javascript theme={null}
    window.argide('registerToolRenderers', {
      query_data_table: ({ result }) => {
        const r = result || {};
        const headers = r.columns || [];
        const rows = r.rows || [];
        return `<div style="border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; font-family:system-ui,sans-serif;">
          <table style="width:100%; border-collapse:collapse; font-size:12px;">
            <thead>
              <tr style="background:#f8fafc;">
                ${headers.map(h =>
                  '<th style="padding:8px 12px; text-align:left; font-weight:600; border-bottom:1px solid #e2e8f0;">' + h + '</th>'
                ).join('')}
              </tr>
            </thead>
            <tbody>
              ${rows.map(row =>
                '<tr style="border-bottom:1px solid #f1f5f9;">' +
                  row.map(cell =>
                    '<td style="padding:6px 12px; color:#334155;">' + cell + '</td>'
                  ).join('') +
                '</tr>'
              ).join('')}
            </tbody>
          </table>
        </div>`;
      }
    });
    ```

    ### Chart (Chart.js, D3, ECharts)

    For interactive charts, return an **HTMLElement** instead of a string. The widget mounts it directly:

    ```html theme={null}
    <!-- Load Chart.js (or any charting library) -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

    <script>
    window.argide('registerToolRenderers', {
      query_analytics_chart: ({ result }) => {
        const canvas = document.createElement('canvas');
        canvas.style.width = '100%';
        canvas.style.maxHeight = '200px';
        new Chart(canvas, {
          type: 'line',
          data: {
            labels: result.data.map(d => d.date),
            datasets: [{
              label: result.title,
              data: result.data.map(d => d.value),
              borderColor: '#2563eb',
              tension: 0.3,
            }]
          },
          options: { responsive: true, plugins: { legend: { display: false } } }
        });
        return canvas;  // Return the DOM element
      }
    });
    </script>
    ```

    <Warning>
      **Timing:** `window.argide()` must be called **after** `argide-widget.js` has loaded. In plain HTML this happens naturally (scripts execute in order). In Next.js, use `onLoad`:

      ```jsx theme={null}
      <Script
        src="https://api.argide.ai/static/argide-widget.js"
        data-product-id="YOUR_PRODUCT_ID"
        data-api-url="https://api.argide.ai"
        strategy="afterInteractive"
        onLoad={() => {
          window.argide('registerToolRenderers', { ... });
        }}
      />
      ```
    </Warning>

    <Tip>
      The widget uses Shadow DOM for CSS isolation. Use inline `style` attributes — Tailwind classes and external CSS won't apply inside the widget.
    </Tip>
  </Tab>

  <Tab title="React SDK">
    React SDK renderers return **JSX** — full React components with hooks, state, and libraries like Recharts:

    ```tsx theme={null}
    <ArgideWidget
      toolRenderers={{
        query_analytics_chart: ({ result }) => <MyChart data={result.data} />,
      }}
      ...
    />
    ```
  </Tab>
</Tabs>

***

## Quick Q\&A

Some users find it more intuitive to read setup instructions in Q\&A format. Here's everything above as quick answers:

<AccordionGroup>
  <Accordion title="How do I add the chat to my app?">
    Install the SDK and drop in one component:

    ```bash theme={null}
    npm install @argide-ai/client @argide-ai/ui
    ```

    ```tsx theme={null}
    <ArgideWidget
      productId="YOUR_PRODUCT_ID"
      apiUrl="https://dashboard.argide.ai"
    />
    ```

    That's it. Chat works anonymously out of the box. No provider wrapping needed.
  </Accordion>

  <Accordion title="How do I authenticate users?">
    Two steps:

    1. **Create a backend endpoint** (\~15 lines) that reads your existing session and mints a JWT signed with your Argide verification secret. Argide never sees your auth system — the JWT is the bridge.

    2. **Pass it as a prop:**

    ```tsx theme={null}
    <ArgideWidget
      productId="YOUR_PRODUCT_ID"
      apiUrl="https://dashboard.argide.ai"
      getIdentityToken={async () => {
        const res = await fetch('/api/argide-token');
        const { token } = await res.json();
        return token;
      }}
    />
    ```

    The SDK calls this on mount and auto-refreshes when the token expires. No `useEffect`, no `setInterval`, no manual calls.

    This enables: conversation history, personalized responses, and user-specific tool actions.

    See [Identity Verification](/setup/identity-verification) for the backend JWT setup.
  </Accordion>

  <Accordion title="How do I give the AI context about the current page?">
    Pass a `context` object. It's reactive — when it changes (e.g., user navigates), the AI automatically knows.

    ```tsx theme={null}
    const context = useMemo(() => {
      const match = pathname.match(/\/items\/([^/]+)/);
      return match ? { itemId: match[1] } : {};
    }, [pathname]);

    <ArgideWidget
      ...
      context={context}
    />
    ```

    This gets injected into the AI's system prompt so it can perform page-aware actions like "edit this item" without asking which one.
  </Accordion>

  <Accordion title="How do I handle SPA navigation for links?">
    Pass your router's push function:

    ```tsx theme={null}
    <ArgideWidget
      ...
      navigate={(path) => router.push(path)}
    />
    ```

    Internal links the AI returns will use your SPA router instead of a full page reload.
  </Accordion>

  <Accordion title="How do I react when the AI calls a tool?">
    **React SDK** — use `onToolResult` and `toolRenderers` as props:

    ```tsx theme={null}
    <ArgideWidget
      onToolResult={(toolName, result) => {
        if (toolName === 'propose_revision') showDiffUI(result);
      }}
      toolRenderers={{
        query_chart: ({ result }) => <MyChart data={result.data} />,
      }}
    />
    ```

    **Script Tag** — use `window.argide()`:

    ```javascript theme={null}
    window.argide('onToolResult', (toolName, result) => {
      if (toolName === 'propose_revision') showDiffUI(result);
    });

    window.argide('registerToolRenderers', {
      query_chart: ({ result }) => `<div>${result.title}: ${result.value}</div>`,
    });
    ```
  </Accordion>

  <Accordion title="What does the full setup look like?">
    Everything is a prop on one component:

    ```tsx theme={null}
    <ArgideWidget
      productId="..."
      apiUrl="https://dashboard.argide.ai"
      getIdentityToken={fetchToken}
      navigate={(path) => router.push(path)}
      onToolResult={(name, result) => ...}
      toolRenderers={{ ... }}

    />
    ```

    No providers, no initializers, no polling.
  </Accordion>
</AccordionGroup>

***

## Troubleshooting

| Issue                | Solution                                              |
| -------------------- | ----------------------------------------------------- |
| Widget not appearing | Check Product ID, verify script/component is rendered |
| Console errors       | Check `apiUrl` is correct                             |
| CORS errors          | Contact support to whitelist your domain              |
