# Inbox+ Widget — Integration Guide

Live URL of this doc: `https://ai.inboxplus.app/docs/integrate.md`

---

## Overview

Inbox+ is a live chat widget. You embed one `<script>` tag on any website and a chat box appears. Visitors can start a conversation; the workspace owner receives messages and replies from the Inbox+ dashboard.

The widget has **two trigger modes**:

| Mode | Description |
|---|---|
| **FAB** (default) | Floating action button, fixed bottom-right corner — created automatically |
| **Inline** | You provide any HTML element with `data-ns-trigger`; clicking it opens the chat panel |

Both modes show a red dot badge when new supporter messages arrive while the chat panel is closed.

---

## Getting a Workspace Key

1. Log in at `https://dash.inboxplus.app`
2. Go to **Settings → Widget**
3. Copy the **Workspace Key** (format: `ws_xxxxxxxxxxxxxxxx`)

---

## Mode 1 — FAB (Floating Action Button)

Add before `</body>`. The widget creates a circular button fixed at the bottom-right corner.

```html
<script
  src="https://ai.inboxplus.app/widget/ns.js"
  data-key="ws_YOUR_WORKSPACE_KEY"
  defer
></script>
```

That's all. No other markup needed.

**Optional config** — add a `<script>` block before the widget script:

```html
<script>
  window.nsvars = {
    customerEmail: 'user@example.com',  // pre-fill customer email (if known)
    customerName:  'Jane Doe',          // pre-fill customer name
    apiUrl:        'https://api.inboxplus.app',  // default, no need to set
  };
</script>
<script src="https://ai.inboxplus.app/widget/ns.js" data-key="ws_YOUR_WORKSPACE_KEY" defer></script>
```

---

## Mode 2 — Inline Trigger

Add `data-ns-trigger` to **any** HTML element. The widget will use that element as the trigger instead of creating a floating button.

```html
<!-- Your trigger element — can be a button, div, span, anchor, anything -->
<button data-ns-trigger>
  <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
    <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
  </svg>
  Chat with us
</button>

<!-- Widget script — place anywhere, before </body> -->
<script
  src="https://ai.inboxplus.app/widget/ns.js"
  data-key="ws_YOUR_WORKSPACE_KEY"
  defer
></script>
```

### What the widget does to your element

- Sets `position: relative` (if it was `static`) so the badge can position correctly
- Sets `cursor: pointer`
- Appends a `<span>` (the red dot badge) inside your element
- Adds class `ns-trigger--open` when the chat panel is open

### Styling the badge

The badge is an inline-styled `<span>` (18×18px, red `#ef4444`, white border) appended as the **last child** of your trigger element. It shows/hides via `display` — you do not need to write any CSS for it.

### Full inline example with custom styling

```html
<button
  data-ns-trigger
  style="
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background: #2563eb;
    color: #fff;
    border: none;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
  "
>
  <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
    <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
  </svg>
  Chat with us
</button>

<script src="https://ai.inboxplus.app/widget/ns.js" data-key="ws_YOUR_WORKSPACE_KEY" defer></script>
```

---

## Behaviour Reference

| Scenario | Result |
|---|---|
| Visitor opens chat panel | Red dot badge hides |
| Supporter sends message while panel is closed | Red dot badge shows; browser tab title flashes; notification sound plays |
| Visitor reopens panel | Badge hides automatically |
| `data-ns-trigger` element exists | Inline mode — no floating FAB created |
| No `data-ns-trigger` on page | FAB mode — floating button created at bottom-right |

---

## Chat Panel Position

The chat panel always appears **fixed at the bottom-right corner** of the viewport, regardless of trigger mode. Inline trigger mode only changes *what opens it*, not where the panel appears.

---

## Framework Examples

### React

```jsx
import { useEffect } from 'react';

export function InboxWidget({ workspaceKey }) {
  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://ai.inboxplus.app/widget/ns.js';
    script.dataset.key = workspaceKey;
    script.defer = true;
    document.body.appendChild(script);
    return () => script.remove();
  }, [workspaceKey]);

  return null; // FAB mode — no JSX needed
}
```

For inline trigger in React:

```jsx
export function ChatButton({ workspaceKey }) {
  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://ai.inboxplus.app/widget/ns.js';
    script.dataset.key = workspaceKey;
    script.defer = true;
    document.body.appendChild(script);
    return () => script.remove();
  }, [workspaceKey]);

  return (
    <button data-ns-trigger style={{ position: 'relative', display: 'inline-flex', alignItems: 'center', gap: 8 }}>
      <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
        <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
      </svg>
      Chat with us
    </button>
  );
}
```

### Next.js (App Router)

```tsx
// app/layout.tsx
import Script from 'next/script';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script
          src="https://ai.inboxplus.app/widget/ns.js"
          data-key="ws_YOUR_WORKSPACE_KEY"
          strategy="lazyOnload"
        />
      </body>
    </html>
  );
}
```

### Shopify (theme.liquid)

```liquid
{% comment %} Before </body> in theme.liquid {% endcomment %}
<script
  src="https://ai.inboxplus.app/widget/ns.js"
  data-key="ws_YOUR_WORKSPACE_KEY"
  defer
></script>
```

---

## Troubleshooting

**Widget does not appear**
- Check that `data-key` is set and the workspace key is correct
- Open browser console — look for errors from `ns.js`
- Make sure the script is not blocked by CSP

**Red dot does not show**
- The badge only appears when the supporter sends a message while the chat panel is closed
- If you're on an old cached version, hard-refresh (`Cmd+Shift+R` / `Ctrl+Shift+R`)

**Inline trigger: badge positioned incorrectly**
- Your trigger element must have `position` other than `static`, OR let the widget set it automatically
- If your element uses `overflow: hidden`, the badge (which extends slightly outside) will be clipped — use `overflow: visible` or add padding

**Chat panel overlaps my content**
- The panel is `position: fixed` — it does not affect document layout
- If z-index conflicts occur, the panel has `z-index: 9999`

---

## API

Widget calls `https://api.inboxplus.app`. No CORS setup needed on your end — the API allows all origins.

Endpoints used by the widget (read-only reference):

| Method | Path | Purpose |
|---|---|---|
| GET | `/widget/config?key=ws_...` | Load workspace config (colors, icon, etc.) |
| POST | `/chat` | Start a new chat |
| GET | `/chat/:id` | Load chat history |
| POST | `/chat/:id/message` | Send a message |
| GET | `/chat/:id/poll?after=:msgId` | Long-poll for new messages |
| POST | `/chat/:id/image` | Upload an image |
