# FAQ

> Short answers to common questions.

Questions we hear a lot. One answer each.

---

## General

### What is this widget?

A conversational AI assistant you embed on your website with one line
of code. Your visitors chat with an AI; you control the configuration
(colors, copy, model, tools) from your Help AI dashboard.

### How much does it cost?

The widget runtime is free to embed. API usage is billed under your
Help AI plan — see [help.ai/pricing](https://help.ai/pricing).

### How big is the bundle?

~107 KB gzipped for the IIFE / standalone ESM (CDN asset) — chat, messenger
tabs, forms/HITL, themes, and i18n included. No external runtime dependencies.
Live budgets are enforced in CI (`.size-limit.json`).

### Does it need a build step?

No. Path A (`<script data-*>`) works on any HTML page with zero
tooling. For framework integrations there's a proper NPM package.

### Is the source open?

Yes — source-available. You can read it, audit it, fork it for your
own builds. Your public key gates the backend, not the frontend.

### What browsers are supported?

Chrome/Edge 100+, Safari 15+, Firefox 100+, iOS Safari 15+. No IE11.
See [Browser support](/sdk/browser-support).

---

## Installation

### Do I need to install NPM packages?

Only if you want to — the `<script>` tag install works without
anything. NPM is there for framework integrations (React, Next.js,
Vue, etc.) where you want typed imports + tree-shaking.

### Can I self-host the bundle?

Yes — download `dist/help-ai/elements.js` from the NPM package (or build it
yourself) and serve it from your CDN. Point your `<script src>` at your hosted
URL. Self-hosting is also what unlocks **chunked delivery** (only changed code
re-downloads across releases) behind a single stable URL the customer never has
to change — see
[Caching, versioning & self-hosting](/sdk/installation#caching-versioning--self-hosting).

### Can I use this with a tag manager (GTM)?

Yes. Use the async loader snippet ([Path B](/sdk/installation#path-b--async-loader-snippet))
inside a Custom HTML tag. All `HelpAI(...)` calls queue until the
bundle lands.

### Does it work in an iframe?

Yes — and there's an optional `presentation.iframe: true` flag that wraps the
widget in its OWN iframe for extra isolation. See
[Configuration § presentation.iframe](/sdk/configuration#presentationiframe).

### Does it work in shadow DOM?

Yes. The widget **creates** a shadow DOM for its own internals, but
you can also mount the widget inside another shadow root (e.g., a
custom element on your page). Everything just works.

### Does it work with React / Next.js?

Yes. Full walkthrough: [Framework integrations § Next.js](/sdk/frameworks#nextjs).

### Does it work with Vue / Svelte / SolidJS / Angular?

Yes. See [Framework integrations](/sdk/frameworks).

### Does it work with WordPress / Shopify / Webflow / Squarespace?

Yes. [Framework integrations § CMS](/sdk/frameworks#wordpress).

---

## Customization

### Can I change the launcher icon?

Yes. Pick from presets (`chat`, `spark`, `message`, `help`, `wand`)
or pass raw SVG. See [Theming § Icons](/sdk/theming#icons).

### Can I match my brand colors?

Yes. Set `theme.accent`, `theme.accentText`, `theme.radius`,
`theme.fontFamily`. See [Theming § Colors](/sdk/theming#color-overrides).

### Can I change the font?

Yes, via `theme.fontFamily`. The widget uses Inter by default but
respects any CSS font stack you provide.

### Can I hide the launcher and open the widget from my own button?

Yes. Set `launcher: { hidden: true }`, then call `chat.open()` from
your button's click handler. [Recipes § Custom launcher](/sdk/recipes#custom-launcher-button).

### Can I change the welcome message?

Yes — from your Help AI dashboard (**Deployment → Welcome**). The
widget just renders what the backend sends.

### Can I override UI strings?

Yes, per-locale or flat. See [Theming § Strings](/sdk/theming#strings-overrides).

### Can I have multiple widgets on one page?

Yes — with distinct `widgetId` values. Each gets its own chat
thread, storage, and events. [Recipes § Multi-widget](/sdk/recipes#multiple-widgets-on-one-page).

### Can I show the widget only on certain pages?

Yes — just skip the `init()` call on pages where you don't want it.
Or conditionally mount/unmount based on the URL.
[Recipes § Conditional show](/sdk/recipes#conditionally-show-based-on-url).

### Can I use it in a specific language?

Yes. Force via `i18n.locale: 'fr-CA'`. Let users switch via
`i18n.availableLocales: ['en', 'fr', 'es']`. Full details: [Theming §
Internationalization](/sdk/theming#internationalization).

### Can I change the widget's position on mobile?

Not per-breakpoint via options, but you can use `update()` to change
it based on `window.innerWidth`:

```ts
function presentationForViewport() {
  return {
    mode: 'floating' as const,
    position: window.innerWidth < 640 ? ('bottom-right' as const) : ('bottom-left' as const),
  };
}

const chat = init({ publicKey: '...', aiAgentDeploymentId: '01900000-0000-7000-8000-000000000000', presentation: presentationForViewport() });

function updatePosition() {
  chat.update({ presentation: presentationForViewport() });
}
updatePosition();
window.addEventListener('resize', updatePosition);
```

---

## Data & privacy

### What data does the widget send to Help AI?

Every turn: the visitor's message, any attachments, the widget
settings snapshot (locale, theme preference, panel size), and an
anonymous `visitorId`. The default anonymous usage tracker also sends
allowlisted event metadata through 1×1 pixel requests; it never sends message
text or form values and can be disabled with `tracking.enabled: false`. GPC and
DNT disable it automatically. No cookies or fingerprinting.

Full breakdown: [Security & privacy § data collected](/sdk/security-privacy#what-data-the-widget-collects).

### Does the widget use cookies?

No cookies. The default persistence adapter uses `localStorage`, and anonymous
usage tracking is enabled by default. Cookie absence alone does not determine
your consent obligations; if your policy requires consent before analytics,
mount with `tracking.enabled: false` and enable it only after consent. Users in
Private / Incognito mode still get the widget, but persistence behavior depends
on the browser.

### Where is the data stored?

Help AI API + your deployment's configured model provider.

### Is the widget GDPR-compliant?

It stores data about identified users (when you pass `user.id`) or
anonymous visitors. Your DPA (Data Processing Agreement) with Help
AI covers the processing terms. For consent management, see
[Recipes § Gate behind consent](/sdk/recipes#gate-the-widget-behind-consent).

### Can visitors delete their chat history?

Yes — clicking the trash icon in the panel starts a new conversation
(the old one becomes inaccessible from the client). For full
deletion from the backend, they contact support@help.ai (or your
equivalent data controller).

### Can I disable conversation and UI persistence?

Yes — pass a custom in-memory storage adapter. Adapter-managed identity,
conversation, draft, preference, and UI state then evaporates on reload. The
optional logger debug level is separate: calling `setDebug` persists
`helpai.debug` directly in `localStorage` until the host clears it.
[Recipes § Custom storage adapter](/sdk/recipes#custom-storage-adapter).

### Does the widget track visitors across sites?

No. The `visitorId` is per browser origin and brand, shared by all Help AI
widgets and deployments on that origin. A visitor using the widget on `foo.com`
is a different visitor on `bar.com` even if both sites share the same Help AI
deployment.

---

## Integration

### How do I pass the current user's identity?

```ts
init({
  userContext: { id: user.id, email: user.email, name: user.name },
});
```

`userContext` (and `pageContext`) is host-asserted context for the AI,
not an auth credential. Browser public access uses the matching
`publicKey` + `aiAgentDeploymentId` pair, or the deployment ID alone for
intentional guest mode.
See [Recipes § Logged-in user personalization](/sdk/recipes#logged-in-user-personalization).

### How do I integrate with my analytics (GA / Segment / Mixpanel)?

One-line pre-boot hook forwards every event:

```html
<script>
  window.HelpAIHooks = window.HelpAIHooks || [];
  window.HelpAIHooks.push([
    '*',
    '*',
    (inst, event, data) => {
      analytics.track(`chat_${event}`, { widget: inst.widgetId, data });
    },
  ]);
</script>
```

Full examples: [Recipes § Analytics forwarding](/sdk/recipes#analytics-forwarding).

### How do I capture errors in Sentry / Datadog?

```ts
import { hook } from '@helpai/elements';

hook('*', 'error', (inst, _event, err) => {
  Sentry.captureException(err, { tags: { widget: inst.widgetId } });
});
```

### Can I read the chat transcript server-side?

Yes — our REST API exposes per-visitor / per-chat endpoints. Contact
support for the API spec. Client-side, build your own log:

```ts
const transcript = [];
chat.on('message', (m) => transcript.push({ ...m, at: Date.now() }));
```

### How do I send the user a pre-filled first message?

Configure **welcome suggestion chips** in your Help AI dashboard.
Clicking a chip fills the composer with its text to edit before sending
(or set `behavior.autoSendSuggestions: true` to send on tap). This is the
intended pattern for "conversation starter" UX.

### How do I trigger chat from a specific user action (e.g., after clicking a CTA)?

```ts
const chat = init({ publicKey: '...', aiAgentDeploymentId: '01900000-0000-7000-8000-000000000000' });

document.querySelector('#pricing-cta').addEventListener('click', () => {
  chat.open();
});
```

---

## Behavior

### Why does the widget open automatically sometimes?

When you set `behavior.startMinimized: false` explicitly. Otherwise it defaults
to closed, and remembers the user's last open/close state across
reloads.

### Why does the panel restore from fullscreen when I reload?

User's last size tier is remembered. If they closed while in
fullscreen, it reopens in fullscreen. If they want to reset,
clicking "New conversation" resets the layout too (or they can click
the ⛶ button to exit fullscreen).

### Why doesn't the widget show on Safari private mode?

It does — but `localStorage` might be ephemeral, meaning chat history
disappears when the tab closes. Everything else works.

### Why do I see the "What can you do?" suggestion only sometimes?

Suggestion chips are server-configured per deployment. The backend
decides what to show based on:

- **New conversation** — typically "What can you do?", "Show me pricing",
  etc.
- **Resumed chat** — typically "Continue where we left off" or
  nothing.

If you're seeing unexpected ones, check your deployment's
"Welcome → Suggestions" config in the dashboard.

### Why does expanding the panel not work on mobile?

The automatic tier uses fullscreen below 640 px, normal from 640–899 px,
and expanded from 900 px by default. To change the desktop breakpoint:

```ts
init({ presentation: { size: { autoSizeBreakpoint: 1200 } } }); // desktop expands at 1200px+
```

### Why does my custom SVG icon render blank?

Probably malformed SVG. The widget parses icons via `DOMParser` —
verify yours is valid SVG 2.x. Use `<path fill="currentColor">` for
theming to work.

### Why does Enter send when I'm composing CJK (Japanese/Chinese/Korean)?

It shouldn't — the widget checks `isComposing`. If it's still
happening, report a bug. Workaround: use `Shift+Enter` for a
newline.

---

## Billing & plans

### Does the widget consume API credits?

Yes — every message sent to the AI uses your Help AI API credits.
See [help.ai/pricing](https://help.ai/pricing).

### How do I cap spend per visitor?

In your Help AI dashboard: **Deployment → Limits → Per-visitor cap**.
When a visitor hits the cap, the widget shows "This conversation is
closed. Start a new conversation?" (via `canContinue: false`).

### What happens if my account runs out of credits?

The widget still renders; users see an error when they try to send.
The `error` event fires with the details. Configure a fallback UX:

```ts
init({
  onError: (err) => {
    // Show a message or fall back to email form
    showFallbackContactForm();
  },
});
```

---

## Versioning

### How do I know what version I'm running?

```js
console.log(window.HelpAI?.version);
// Or:
import { version } from '@helpai/elements';
console.log(version);
```

### How do I pin to a specific version?

```html
<script src="https://cdn.help.ai/v1.2.0/elements.js" defer></script>
```

Or `v1` for the latest v1.x.x (auto-patches but no major breaks).

### When are breaking changes released?

Only in major version bumps. Minor versions are additive. Patch
versions are bug fixes. Semver throughout.

### How do I upgrade?

If you use the floating CDN URL, automatically. If pinned, update
the version in your `<script>` tag. NPM users: `npm update
@helpai/elements`.

### Where's the changelog?

[github.com/help-ai/elements/releases](https://github.com/help-ai/elements/releases).

---

## Support

### How do I contact support?

- **Email**: [support@help.ai](mailto:support@help.ai)
- **Docs**: you're reading them
- **Status**: [help.ai/status](https://help.ai/status)
- **Bugs**: [GitHub Issues](https://github.com/help-ai/elements/issues)

### How fast is support?

- Email: within 24 hours on weekdays.
- Critical outages: tracked on status page in real-time.
- Enterprise customers: SLA per contract.

### Can I get a custom build?

Yes — contact [sales@help.ai](mailto:sales@help.ai) for enterprise
options. Custom brands, custom CDN, custom features are all on the
table.
