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

# Embed the AI Widget

> Drop a User Intuition study directly into your web app with an embeddable on-site interview widget. Install in minutes with HTML, JavaScript, or React.

The User Intuition AI widget is an embeddable on-site interview surface. Drop it into any web app and participants can start a voice or chat interview without leaving your product. The widget triggers a live Study from inside your page, captures the response, and feeds it back into your dashboard like any other interview.

Use it for in-app feedback, post-purchase surveys, churn intercepts, or always-on listening from inside your product.

***

## What you need

The easiest way to get a working embed is to request its generated HTML with your Study ID:

```http theme={null}
GET /api/public/v1/studies/{study_id}/embed-code?type=widget
```

Copy the returned `code` into your page. The study must be provisioned. For a simple link instead, use `type=button`; that response also includes `study_link`.

If you build the widget markup yourself, it needs these values:

| Prop | Description |
| - | - |
| `public-key` | The public widget key returned in the generated code. |
| `assistant-id` | The widget's provisioned interviewer ID returned in the generated code. This can differ from the Study ID used in the API path. |
| `invite-id` | The interview invitation ID returned in the generated code. |

<Note>
  Use the API Study ID to request the embed code. Use the generated widget values as returned; the widget's `assistant-id` is not necessarily the API Study ID.
</Note>

***

## Quickstart

<Steps>
  <Step title="Grab your keys">
    Copy the Study ID, then call `GET /api/public/v1/studies/{study_id}/embed-code?type=widget` to get the widget values.
  </Step>

  <Step title="Install or include the widget">
    Run `npm install @userintuition-ai/web` for React, or drop in the UMD `<script>` tag for plain HTML.
  </Step>

  <Step title="Mount it">
    Add the generated `<userintuition-widget>` element and script, or pass its values to `<UserIntuitionWidget />`.
  </Step>

  <Step title="Style and scope">
    Set `theme`, `position`, `size`, and brand colors. Use `show-based-on-url` and `delay-interval` so the widget only appears where it should.
  </Step>

  <Step title="Test the interview">
    Open the page, trigger the widget, and complete a test interview. The response will appear in your Study Dashboard alongside link and invite responses.
  </Step>
</Steps>

***

## Install

The package is published as `@userintuition-ai/web`.

<CodeGroup>
  ```bash npm theme={null}
  npm install @userintuition-ai/web
  ```

  ```html CDN theme={null}
  <script src="https://unpkg.com/@userintuition-ai/web@1.0.41/dist/embed/widget.umd.min.js" integrity="sha384-rXrrVbv7DSEZt7u+cwihOD3auuEJ5L8sTIepy8gMKtrlsYPdPlc2uXAAFfMbWHek" crossorigin="anonymous"></script>
  ```
</CodeGroup>

***

## Embedding methods

There are four ways to mount the widget. Pick the one that matches your stack.

### 1. HTML custom element

The simplest option. Drop in the script tag and a `<userintuition-widget>` element anywhere in your HTML.

```html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/@userintuition-ai/web@1.0.41/dist/embed/widget.umd.min.js" integrity="sha384-rXrrVbv7DSEZt7u+cwihOD3auuEJ5L8sTIepy8gMKtrlsYPdPlc2uXAAFfMbWHek" crossorigin="anonymous"></script>
  </head>
  <body>
    <userintuition-widget
      public-key="your-public-key"
      assistant-id="your-generated-widget-interviewer-id"
      invite-id="your-generated-invitation-id"
      mode="voice"
      theme="dark"
      position="bottom-right"
    ></userintuition-widget>
  </body>
</html>
```

### 2. JavaScript loader

If you need to mount programmatically (for example, after a route change or user action), create the same custom element after the widget script loads.

```javascript theme={null}
const container = document.getElementById('widget-container');
const widget = document.createElement('userintuition-widget');
widget.setAttribute('public-key', 'your-public-key');
widget.setAttribute('assistant-id', 'your-generated-widget-interviewer-id');
widget.setAttribute('invite-id', 'your-generated-invitation-id');
widget.setAttribute('mode', 'voice');
widget.setAttribute('theme', 'dark');
widget.setAttribute('position', 'bottom-right');
container.append(widget);
```

### 3. React component

For React apps, install the npm package and import the component.

<CodeGroup>
  ```tsx React theme={null}
  import { UserIntuitionWidget } from '@userintuition-ai/web';

  export default function App() {
    return (
      <UserIntuitionWidget
        publicKey="your-public-key"
        assistantId="your-generated-widget-interviewer-id"
        mode="voice"
        theme="dark"
        position="bottom-right"
      />
    );
  }
  ```

  ```tsx TypeScript theme={null}
  import { UserIntuitionWidget, type UserIntuitionWidgetProps } from '@userintuition-ai/web';

  const props: UserIntuitionWidgetProps = {
    publicKey: 'your-public-key',
    assistantId: 'your-generated-widget-interviewer-id',
    mode: 'voice',
    theme: 'dark',
  };

  export default function App() {
    return <UserIntuitionWidget {...props} />;
  }
  ```
</CodeGroup>

### 4. Web component variant

For React apps that prefer a thin wrapper around the underlying custom element, use `UserIntuitionWidgetWebComponent`. It is the package's default export and the recommended React surface.

```tsx theme={null}
import { UserIntuitionWidgetWebComponent } from '@userintuition-ai/web';
// or use the default export
import UserIntuitionWidget from '@userintuition-ai/web';

export default function App() {
  return (
    <UserIntuitionWidgetWebComponent
      publicKey="your-public-key"
      assistantId="your-generated-widget-interviewer-id"
      mode="voice"
      theme="dark"
    />
  );
}
```

***

## Modes

The widget supports three interview modes. Set the mode that fits your audience and the depth of feedback you want.

| Mode | When to use it |
| - | - |
| `voice` | Spoken interviews. Best for richer, longer-form feedback and natural conversation. Default mode. |
| `chat` | Text-only interviews. Best for quiet environments, accessibility, or users who prefer typing. |
| `hybrid` | Lets the participant choose voice or chat at the start. Best when you don't know the context the widget will load in. |

```html theme={null}
<userintuition-widget
  public-key="your-public-key"
  assistant-id="your-generated-widget-interviewer-id"
  mode="hybrid"
></userintuition-widget>
```

***

## Position and size

Control where the widget anchors and how much room it takes up on screen.

### Position

| Value | Description |
| - | - |
| `bottom-right` | Default. Anchored bottom-right, ideal for chat-style launchers. |
| `bottom-left` | Bottom-left corner. |
| `top-right` | Top-right corner. |
| `top-left` | Top-left corner. |
| `center` | Centered on screen. Use for full-screen takeovers or modal-style interviews. |

### Size

| Value | Description |
| - | - |
| `compact` | Default. Small launcher that expands when opened. |
| `full` | Full launcher panel — more visible, larger surface for the interview. |
| `minimal` | Smallest footprint. Good for unobtrusive, always-on placement. |

```html theme={null}
<userintuition-widget
  public-key="your-public-key"
  assistant-id="your-generated-widget-interviewer-id"
  position="bottom-right"
  size="full"
></userintuition-widget>
```

***

## Theme and branding

The widget ships with `light` and `dark` presets. You can override individual colors to match your brand.

| React prop | HTML attribute | Description |
| - | - | - |
| `theme` | `theme` | Preset — `light` or `dark`. Default: `light`. |
| `baseBgColor` | `base-bg-color` | Base background color (hex). |
| `baseColor` | `base-color` | Base color (hex). |
| `accentColor` | `accent-color` | Accent color used across the interview UI (hex). |
| `ctaButtonColor` | `cta-button-color` | Background color of the call-to-action button (hex). |
| `ctaButtonTextColor` | `cta-button-text-color` | Text color of the call-to-action button (hex). |
| `buttonBaseColor` | `button-base-color` | Base color for buttons (hex). |
| `buttonAccentColor` | `button-accent-color` | Accent color for buttons (hex). |
| `borderRadius` | `border-radius` | One of `none`, `small`, `medium`, `large`. Default: `medium`. |

```html theme={null}
<userintuition-widget
  public-key="your-public-key"
  assistant-id="your-generated-widget-interviewer-id"
  theme="dark"
  base-bg-color="#000000"
  accent-color="#14B8A6"
  cta-button-color="#000000"
  cta-button-text-color="#ffffff"
  border-radius="large"
></userintuition-widget>
```

You can also customize widget copy with `title`, `cta-title`, `cta-subtitle`, `start-button-text`, `end-button-text`, and mode-specific empty-state messages (`voice-empty-message`, `chat-empty-message`, `chat-placeholder`, `hybrid-empty-message`, and others).

***

## Consent flow

When `consent-required` is enabled, the widget shows a consent dialog before the interview can start. The participant's choice is stored in `localStorage` so they only see the dialog once per device.

| React prop | HTML attribute | Description |
| - | - | - |
| `consentRequired` | `consent-required` | Show a consent dialog before the interview begins. Default: `false`. |
| `consentTitle` | `consent-title` | Title of the consent dialog. |
| `consentContent` | `consent-content` | Body text of the consent dialog. |
| `consentStorageKey` | `consent-storage-key` | LocalStorage key used to persist consent. |
| `termsContent` | `terms-content` | Optional terms-and-conditions text. |

```html theme={null}
<userintuition-widget
  public-key="your-public-key"
  assistant-id="your-generated-widget-interviewer-id"
  consent-required="true"
  consent-title="Terms and conditions"
  consent-content='By clicking "Agree," and each time I interact with this AI agent, I consent to the recording, storage, and sharing of my communications with third-party service providers, and as otherwise described in our Terms of Service.'
  consent-storage-key="userintuition_widget_consent"
></userintuition-widget>
```

<Note>
  Consent state is keyed by `consent-storage-key`. If you change the key, the widget will treat returning participants as new and prompt them again.
</Note>

***

## Smart display

You usually don't want the widget to appear on every page or fire instantly. Use these props to scope when and where it shows.

| React prop | HTML attribute | Description |
| - | - | - |
| `showWidget` | `show-widget` | Hard on/off switch. Default: `true`. |
| `showBasedOnUrl` | `show-based-on-url` | Array of URL paths where the widget should appear. Pass a JSON array string in HTML. |
| `delayInterval` | `delay-interval` | Milliseconds to wait before showing the widget. Default: `0`. Useful when you want to give the page a moment to settle before interrupting the user. |

<CodeGroup>
  ```html HTML theme={null}
  <userintuition-widget
    public-key="your-public-key"
    assistant-id="your-generated-widget-interviewer-id"
    show-based-on-url='["/feedback", "/contact"]'
    delay-interval="3000"
  ></userintuition-widget>
  ```

  ```tsx React theme={null}
  <UserIntuitionWidget
    publicKey="your-public-key"
    assistantId="your-generated-widget-interviewer-id"
    showBasedOnUrl={['/feedback', '/contact']}
    delayInterval={3000}
  />
  ```
</CodeGroup>

***

## Voice and reconnect options

Voice mode has a few extra knobs for transcript display and reconnection.

| React prop | HTML attribute | Description |
| - | - | - |
| `voiceShowTranscript` | `voice-show-transcript` | Display a live transcript during voice interviews. Default: `false`. |
| `voiceAutoReconnect` | `voice-auto-reconnect` | Reconnect automatically if the audio connection drops. Default: `false`. |
| `reconnectStorageKey` | `reconnect-storage-key` | LocalStorage key used to persist reconnect state. |
| `showTranscript` | `show-transcript` | Show the transcript surface generally. Default: `false`. |

***

## Where to find your keys

Use your Study ID to request the generated embed code. Copy `public-key`, `assistant-id`, and `invite-id` from that response when configuring the widget yourself.

<CardGroup cols={2}>
  <Card title="Public key" icon="key" href="/resources/account-settings">
    Find this in your account settings under API keys. Safe to ship in client-side code.
  </Card>

  <Card title="Widget values" icon="flask" href="/api-reference/study-lifecycle">
    Request `GET /api/public/v1/studies/{study_id}/embed-code?type=widget` with your Study ID and copy the generated widget values.
  </Card>
</CardGroup>

***

## Browser support

The widget runs in any modern browser that supports:

* ES6+
* The Custom Elements API
* Microphone access (for voice and hybrid modes)

For React installs, React 16.8+ is required as a peer dependency.

***

## Next.js and React Server Components

The widget is a client-only component — it touches `window`, `localStorage`, and the microphone. In Next.js 13+ with the App Router, mark the file as a client component.

```tsx theme={null}
'use client';

import UserIntuitionWidget from '@userintuition-ai/web';

export default function FeedbackWidget() {
  return (
    <UserIntuitionWidget
      publicKey="your-public-key"
      assistantId="your-generated-widget-interviewer-id"
      mode="voice"
    />
  );
}
```

<Warning>
  Don't import the widget into a server component or render it during SSR. The bundle assumes a browser environment and will throw if it loads on the server.
</Warning>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Share a study link" icon="link" href="/recruiting/share-link">
    The simpler alternative — a hosted URL anyone can open in a browser.
  </Card>

  <Card title="Account settings" icon="gear" href="/resources/account-settings">
    Request generated embed code for your Study ID.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.