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

# Embedding Devic in your product

> Two ways to put an assistant inside your product: a hosted widget you paste in, or React components you build with.

There are two ways to put a Devic assistant inside your product, and which one you want depends on whether you are writing React.

***

## Without code: the hosted widget

Every assistant has a **Chat Widget** section in its configuration: appearance, welcome message, suggested messages, file uploads, language and access — with a live preview beside it and a **Get Code** button that hands you the snippet to paste into your page.

<img src="https://mintcdn.com/devic/DKyKkxiOLW4okLYC/images/embed/widget-config.png?fit=max&auto=format&n=DKyKkxiOLW4okLYC&q=85&s=d6815a79cf3b4305027f7415a1ef1321" alt="Widget configuration" width="1623" height="945" data-path="images/embed/widget-config.png" />

Nothing to install and nothing to build. It is the right choice for a marketing site, a help centre, or anywhere the chat is a self-contained thing sitting on top of the page.

<img src="https://mintcdn.com/devic/DKyKkxiOLW4okLYC/images/embed/widget-live.png?fit=max&auto=format&n=DKyKkxiOLW4okLYC&q=85&s=89ffdc72a2582da44a9e262ee1813d39" alt="The chat widget in a product" width="639" height="280" data-path="images/embed/widget-live.png" />

***

## With React: `@devicai/ui`

When the assistant needs to be *part of* your interface rather than sitting on it — reading the form the user is filling in, writing into a field, or looking like the rest of your product — use the library.

`@devicai/ui` is a React library that puts a Devic assistant inside your product: a chat drawer, a command bar, a generation button — connected to the public API, styled to your application.

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

```jsx theme={null}
import { DevicProvider, ChatDrawer } from '@devicai/ui';
import '@devicai/ui/styles.css';

export default function App() {
  return (
    <DevicProvider apiKey="devic-xxx">
      <ChatDrawer
        assistantId="support-assistant"
        options={{
          position: 'right',
          welcomeMessage: 'Hello! How can I help?',
          suggestedMessages: ['Where is my order?', 'I need an invoice'],
        }}
      />
    </DevicProvider>
  );
}
```

***

## What is in the box

<Columns cols={2}>
  <Card title="ChatDrawer" icon="comments">
    A complete chat panel: history, attachments, voice input, tool timeline, feedback.
  </Card>

  <Card title="AICommandBar" icon="terminal">
    A spotlight-style bar bound to a keyboard shortcut, with slash commands and history.
  </Card>

  <Card title="AIGenerationButton" icon="wand-magic-sparkles">
    A button that generates into a field — directly, through a modal, or in a tooltip.
  </Card>

  <Card title="useDevicChat" icon="code">
    The hook underneath, for when you want your own interface entirely.
  </Card>
</Columns>

Plus `CoreMemoryModal` for [what the assistant remembers](/devic/memory/core-memory) and `IntegrationsModal` for [the apps each user connects](/devic/integrations/for-end-users).

***

## Authenticate properly

<Warning>
  An `apiKey` prop puts that key in your bundle, where anyone can read it. That is acceptable while you are building and **not** acceptable in production for a multi-customer product: with the key alone, someone can claim to be any of your tenants.

  Use [tenant sessions](/devic/multi-tenant/tenant-sessions) instead. The provider takes a function that fetches a session from *your* backend and renews it on its own — and the page then carries no key at all.
</Warning>

```jsx theme={null}
<DevicProvider
  getTenantSession={async () => {
    const r = await fetch('/api/devic-session', { credentials: 'include' });
    return r.json();
  }}
  onSessionExpired={() => location.assign('/login')}
>
  <App />
</DevicProvider>
```

If you restrict the key that ships in the browser, Devic offers a ready-made scope for exactly this case — see [API keys](/devic/administration/api-keys).

***

## Client-side tools

Some things only the browser knows: where the user is, what is selected on screen, what is in the form they are filling in. The **Model Interface Protocol** lets the assistant call a function *in your page* as if it were any other tool.

```jsx theme={null}
const locationTool = {
  toolName: 'get_user_location',
  schema: {
    type: 'function',
    function: {
      name: 'get_user_location',
      description: 'Get the user current geographic location',
      parameters: { type: 'object', properties: {} },
    },
  },
  callback: async () => {
    const pos = await new Promise((ok, err) =>
      navigator.geolocation.getCurrentPosition(ok, err),
    );
    return { latitude: pos.coords.latitude, longitude: pos.coords.longitude };
  },
};

<ChatDrawer assistantId="support-assistant" modelInterfaceTools={[locationTool]} />
```

The assistant asks, your page answers, the conversation carries on. Nothing about the user's browser has to reach your server first.

***

## Making it look like yours

Every component is themed with CSS variables, so it inherits your product rather than announcing itself:

```css theme={null}
.devic-chat-drawer {
  --devic-primary: #4764e6;
  --devic-bg: #ffffff;
  --devic-text: #1a1a1a;
  --devic-radius: 12px;
}
```

For a single accent colour, `options={{ color: '#4764e6' }}` is enough.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Configuring the chat drawer" icon="sliders" href="/devic/embed/chat-widget">
    Options, callbacks, memory and connected apps.
  </Card>

  <Card title="Tenant sessions" icon="key" href="/devic/multi-tenant/tenant-sessions">
    Proving which user is calling.
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/introduction">
    Everything the components call, callable yourself.
  </Card>

  <Card title="CLI" icon="rectangle-terminal" href="/devic/cli/index">
    The same API from a terminal.
  </Card>
</CardGroup>
