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

# Install Widget

> Launch the AI Chat Widget on your website with HTML, the default React package, or a headless build.

Use this page when your goal is simple: get the **AI Chat Widget** live on a website and confirm visitors can start a conversation.

<Tip>
  Need the widget to recognize signed-in customers? Open **[Authentication](/widget/authentication)** after installation.
</Tip>

<Info>
  Want to tweak colors, launcher size, and initial messages before you copy the code? Use the **[Playground](/widget/playground)** — it generates the exact snippet for your setup.
</Info>

## Before You Start

You need a <Tooltip tip="A unique identifier from your OpenCX dashboard that connects the widget to your organization. Not to be confused with the authenticated contact token used for visitor identity.">**widget token**</Tooltip> from your [OpenCX dashboard](https://platform.open.cx/channels/configure/widget). This token tells the widget which organization it belongs to.

Choose the install path that matches your site:

<CardGroup cols={4}>
  <Card title="HTML" icon="code">
    Best when you want the fastest website embed.
  </Card>

  <Card title="React" icon="react">
    Best when your site already uses React.
  </Card>

  <Card title="Headless" icon="cube">
    Best when you want your own UI or storage model.
  </Card>

  <Card title="Mobile" icon="phone" href="/widget/native-mobile">
    Best when you need chat inside iOS, Android, or React Native.
  </Card>
</CardGroup>

## Implementation Steps

<Tabs>
  <Tab title="HTML">
    <Steps>
      <Step title="Confirm this is the right path">
        Choose HTML when you want the default widget on a standard website and do not need to build custom UI from scratch.
      </Step>

      <Step title="Add the widget script">
        Put the widget script in your page `head`.

        ```html index.html theme={"dark"}
        <script defer src="https://unpkg.com/@opencx/widget@latest/dist-embed/script.js"></script>
        ```
      </Step>

      <Step title="Initialize the widget after the page loads">
        Call <Tooltip tip="The initialization function for the HTML widget embed — call it after DOMContentLoaded with your widget token.">`initOpenScript()`</Tooltip> after `DOMContentLoaded` and pass your widget token.

        ```html index.html theme={"dark"}
        <script>
          window.addEventListener('DOMContentLoaded', () => {
            initOpenScript({
              token: '<WIDGET_TOKEN>',
            });
          });
        </script>
        ```
      </Step>

      <Step title="Reload the page and verify the widget">
        By default, the widget appears as a floating launcher. Open it and send a test message.
      </Step>
    </Steps>

    <Warning>
      **Widget does not appear after page load:** keep the `DOMContentLoaded` wrapper unless your site guarantees the widget initializes only after the DOM is ready.
    </Warning>
  </Tab>

  <Tab title="React">
    <Steps>
      <Step title="Confirm this is the right path">
        Choose React when your website already uses React and you want the default widget experience inside your app.
      </Step>

      <Step title="Install the package">
        Add the default widget package to your project.

        ```bash theme={"dark"}
        npm install @opencx/widget-react
        ```
      </Step>

      <Step title="Create a wrapper component">
        Render <Tooltip tip="The default React widget component — renders the full chat UI including launcher, message thread, and input.">`<Widget />`</Tooltip> and pass your widget token through `options`.

        ```tsx WidgetWrapper.tsx theme={"dark"}
        import { Widget } from '@opencx/widget-react';

        export function WidgetWrapper() {
          return (
            <Widget
              options={{
                token: '<WIDGET_TOKEN>',
              }}
            />
          );
        }
        ```
      </Step>

      <Step title="Mount it in your app">
        Place the wrapper where the widget should be available, usually your app shell or main layout.
      </Step>
    </Steps>

    <Warning>
      **Widget renders but never loads your organization:** make sure the widget token is passed inside the `options` object you give to `<Widget />`.
    </Warning>
  </Tab>

  <Tab title="Headless">
    <Steps>
      <Step title="Confirm this is the right path">
        Choose <Tooltip tip="A widget build where you control the entire UI, rendering, and storage layer — only the chat engine and hooks are provided.">headless</Tooltip> only when the default widget UI is not enough and your team wants to own the layout, rendering, and persistence model.
      </Step>

      <Step title="Install the headless packages">
        Add the provider and core engine packages.

        ```bash theme={"dark"}
        npm install @opencx/widget-react-headless @opencx/widget-core
        ```
      </Step>

      <Step title="Wrap your custom UI with WidgetProvider">
        <Tooltip tip="The React context provider that initializes the headless widget engine and gives child components access to chat hooks and state.">`WidgetProvider`</Tooltip> initializes the widget engine and gives your app access to the hooks and state you need.

        ```tsx App.tsx theme={"dark"}
        import { WidgetProvider } from '@opencx/widget-react-headless';

        export function App() {
          return (
            <WidgetProvider options={{ token: '<WIDGET_TOKEN>' }}>
              <YourCustomWidget />
            </WidgetProvider>
          );
        }
        ```
      </Step>

      <Step title="Build and test the full conversation flow">
        Confirm your custom UI can load history, send a message, and handle a returning visitor before you ship it.
      </Step>
    </Steps>

    <Warning>
      **Headless UI works for new chats but breaks on real usage:** remember that you own fallback states, history rendering, and resolved-session behavior in a headless build.
    </Warning>
  </Tab>
</Tabs>

## Choose How The Widget Appears

These options control what visitors see on the page before they even start chatting.

<AccordionGroup>
  <Accordion title="Floating launcher (default)" icon="message" id="floating-launcher">
    This is the standard widget behavior. Visitors see a launcher button, click it to open the widget, and close it when they are done.

    Use this when the widget should be available site-wide without taking up permanent page space.

    ```tsx theme={"dark"}
    const options = {
      token: '<WIDGET_TOKEN>',
    };
    ```
  </Accordion>

  <Accordion title="Inline embed" icon="rectangle-list" id="inline-embed">
    Use this when the widget should live inside a page section, such as a help page, pricing page, portal, or account screen.

    When <Tooltip tip="Embeds the widget directly in the page layout instead of floating over it. The launcher button is hidden.">`inline`</Tooltip> is `true`, the widget stays open inside its parent container and the floating launcher is hidden. In practice, this means the widget becomes part of the page layout instead of hovering over it.

    ```tsx theme={"dark"}
    const options = {
      token: '<WIDGET_TOKEN>',
      inline: true,
    };
    ```
  </Accordion>

  <Accordion title="Open by default" icon="arrow-up-right-from-square" id="open-by-default">
    Use this when the widget should already be open on first render, such as inside a webview or a dedicated support page.

    This changes the initial state only. The visitor can still continue using the widget normally after it opens.

    ```tsx theme={"dark"}
    const options = {
      token: '<WIDGET_TOKEN>',
      isOpen: true,
    };
    ```
  </Accordion>

  <Accordion title="Open after a delay" icon="clock" id="open-after-a-delay">
    Use this when you want the widget to open after the visitor has already spent time on the page.

    This is best for proactive support moments. It is usually a poor fit for every page on your site because it can feel intrusive if the visitor was not trying to chat.

    ```tsx theme={"dark"}
    const options = {
      token: '<WIDGET_TOKEN>',
      openAfterNSeconds: 10,
    };
    ```
  </Accordion>
</AccordionGroup>

## Test Your First Conversation

<CardGroup cols={2}>
  <Card title="1. Confirm the widget appears" icon="list-ol">
    Load the page and verify the launcher or inline widget shows where you expect.
  </Card>

  <Card title="2. Confirm the opening behavior" icon="list-ol">
    Check that the widget opens the way you configured it: floating, inline, already open, or delayed.
  </Card>

  <Card title="3. Send a real message" icon="list-ol">
    Start a conversation and verify the message reaches your [inbox](https://platform.open.cx/inbox).
  </Card>

  <Card title="4. Reload and return" icon="list-ol">
    Refresh the page and confirm the same visitor can continue the conversation on the same device.
  </Card>
</CardGroup>

## Good To Know

<AccordionGroup>
  <Accordion title="Links can open in the same tab or a new one" icon="link">
    Use <Tooltip tip="Controls whether links in AI replies open in the same tab (_top) or a new tab (_blank).">`anchorTarget`</Tooltip> when replies include links and you need to control what happens after the visitor clicks them.

    Choose `_top` if you want the current page to change. Choose `_blank` if you want the visitor to keep the chat open and open the link in a new tab.
  </Accordion>

  <Accordion title="Headless builds can use custom storage" icon="database">
    If browser storage is not the right fit, use <Tooltip tip="A storage adapter from @opencx/widget-core that lets you replace browser localStorage with your own persistence layer.">`ExternalStorage`</Tooltip> from `@opencx/widget-core`.

    This matters most in mobile apps, embedded environments, or custom shells where your app already controls how tokens and session data are stored.
  </Accordion>
</AccordionGroup>

## Where To Go Next

<CardGroup cols={2}>
  <Card title="Authentication" icon="shield-check" href="/widget/authentication">
    Identify signed-in visitors and protect conversation history.
  </Card>

  <Card title="Configuration" icon="gear" href="/widget/configuration">
    Control branding, prompts, behavior, and advanced options.
  </Card>

  <Card title="Conversation Sessions" icon="route" href="/widget/conversation-sessions">
    Understand history, handoff, and returning-visitor behavior.
  </Card>

  <Card title="Mobile Support" icon="phone" href="/widget/native-mobile">
    Add the widget to iOS, Android, and React Native apps.
  </Card>
</CardGroup>
