@helpai/elements 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -12
- package/configurator.mjs +1 -1
- package/docs/README.md +183 -0
- package/docs/analytics.md +551 -0
- package/docs/api-reference.md +637 -0
- package/docs/browser-support.md +302 -0
- package/docs/configuration.md +1014 -0
- package/docs/events-and-hooks.md +483 -0
- package/docs/faq.md +435 -0
- package/docs/frameworks.md +643 -0
- package/docs/installation.md +626 -0
- package/docs/options.md +323 -0
- package/docs/quickstart.md +229 -0
- package/docs/recipes.md +725 -0
- package/docs/security-privacy.md +636 -0
- package/docs/theming.md +570 -0
- package/docs/troubleshooting.md +523 -0
- package/elements-web-component.esm.js +39 -39
- package/elements-web-component.esm.js.map +4 -4
- package/elements.cjs.js +39 -39
- package/elements.cjs.js.map +4 -4
- package/elements.esm.js +39 -39
- package/elements.esm.js.map +4 -4
- package/elements.js +39 -39
- package/elements.js.map +4 -4
- package/index.d.ts +107 -3
- package/index.mjs +13 -13
- package/jsx-react.d.ts +15 -0
- package/jsx-svelte.d.ts +14 -0
- package/jsx-vue.d.ts +14 -0
- package/llms-full.txt +7954 -0
- package/llms.txt +37 -0
- package/loader.js +3 -3
- package/loader.min.js +1 -1
- package/package.json +36 -1
- package/react.d.ts +3575 -0
- package/react.mjs +62 -0
- package/schema.d.ts +56 -0
- package/schema.json +24 -2
- package/schema.mjs +1 -1
- package/web-component.d.ts +1583 -17
- package/web-component.mjs +14 -14
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
# Framework integrations
|
|
2
|
+
|
|
3
|
+
Copy-paste recipes for every major frontend framework + CMS.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- [Next.js](#nextjs)
|
|
10
|
+
- [React (Vite / CRA)](#react)
|
|
11
|
+
- [Vue 3](#vue-3)
|
|
12
|
+
- [Nuxt 3](#nuxt-3)
|
|
13
|
+
- [Svelte / SvelteKit](#svelte--sveltekit)
|
|
14
|
+
- [Astro](#astro)
|
|
15
|
+
- [Remix](#remix)
|
|
16
|
+
- [SolidJS](#solidjs)
|
|
17
|
+
- [Angular](#angular)
|
|
18
|
+
- [WordPress](#wordpress)
|
|
19
|
+
- [Shopify](#shopify)
|
|
20
|
+
- [Webflow](#webflow)
|
|
21
|
+
- [Squarespace / Wix](#squarespace--wix)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Next.js
|
|
26
|
+
|
|
27
|
+
The React kit, `@helpai/elements/react`, is server-render safe and already marked `'use client'`, so it drops straight
|
|
28
|
+
into a layout. Nothing touches the page until it runs in the browser.
|
|
29
|
+
|
|
30
|
+
**App Router** (13+):
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// app/layout.tsx
|
|
34
|
+
import { HelpAI } from '@helpai/elements/react';
|
|
35
|
+
|
|
36
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
37
|
+
return (
|
|
38
|
+
<html lang='en'>
|
|
39
|
+
<body>
|
|
40
|
+
{children}
|
|
41
|
+
<HelpAI publicKey={process.env.NEXT_PUBLIC_HELPAI_KEY!} aiAgentDeploymentId={process.env.NEXT_PUBLIC_HELPAI_DEPLOYMENT_ID!} theme='host' />
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# .env.local
|
|
50
|
+
NEXT_PUBLIC_HELPAI_KEY=agent_pk_abc123...
|
|
51
|
+
NEXT_PUBLIC_HELPAI_DEPLOYMENT_ID=01900000-0000-7000-8000-000000000000
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A server component can only pass serializable props, so callbacks (`onOpen`, `onMessage`, …) go on a `<HelpAI />`
|
|
55
|
+
rendered from a `'use client'` component of your own. `useHelpAI()` (below) works in any client component.
|
|
56
|
+
|
|
57
|
+
**Pages Router**: render `<HelpAI />` in `pages/_app.tsx` the same way; no `dynamic(..., { ssr: false })` needed.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## React
|
|
62
|
+
|
|
63
|
+
The React kit (React 18+) mounts the widget with `<HelpAI />` and drives it from any component with `useHelpAI()`:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { HelpAI, useHelpAI } from '@helpai/elements/react';
|
|
67
|
+
|
|
68
|
+
export function Root() {
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<main>{/* your app */}</main>
|
|
72
|
+
<HelpAI publicKey={import.meta.env.VITE_HELPAI_KEY} aiAgentDeploymentId={import.meta.env.VITE_HELPAI_DEPLOYMENT_ID} theme='host' />
|
|
73
|
+
</>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function PricingHelp() {
|
|
78
|
+
const { ask, open, state } = useHelpAI();
|
|
79
|
+
return (
|
|
80
|
+
<>
|
|
81
|
+
<button onClick={() => ask('Which plan fits a team of 10?')}>Ask about plans</button>
|
|
82
|
+
<button onClick={() => open({ to: 'help' })}>Help center {state.unread > 0 && `(${state.unread})`}</button>
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- **`<HelpAI {...options} />`** takes every [widget option](./configuration.md) as a prop; `aiAgentDeploymentId` is
|
|
89
|
+
required. It renders nothing itself: the widget mounts once the page is in the browser, a prop change re-configures
|
|
90
|
+
the live widget without a remount, and unmounting removes it. Callback props (`onOpen`, `onMessage`, …) can be new
|
|
91
|
+
functions on every render; the widget always calls the latest one.
|
|
92
|
+
- **`useHelpAI(widgetId?)`** returns `{ state, ask, open, close, reset }`. `state` is
|
|
93
|
+
[`{ open, ready, unread, conversationId? }`](./api-reference.md#state-and-ready) and re-renders the component when it changes;
|
|
94
|
+
the server render sees the initial state. The commands are stable across renders and do nothing until the widget
|
|
95
|
+
has mounted (`state.ready`). `ask(text)` fills the composer; `ask(text, { send: true })` sends it. Call `reset()`
|
|
96
|
+
when your user logs out.
|
|
97
|
+
- **One import path.** The kit carries the whole widget API (`getInstance`, `hook`, the types), so import everything
|
|
98
|
+
from `@helpai/elements/react`; the package's other entries are separate copies with their own widgets.
|
|
99
|
+
- **Two widgets** on one page: give each `<HelpAI widgetId='support' … />` and read it with `useHelpAI('support')`.
|
|
100
|
+
- **Signed-in users:** pass `userToken`, a function that fetches the token your server signs
|
|
101
|
+
([Verified users](./security-privacy.md#verified-users-usertoken)). Keep it stable for one user (a module function, or
|
|
102
|
+
`useCallback` keyed on your user id): a different function signs in afresh, and dropping it signs out.
|
|
103
|
+
|
|
104
|
+
The kit bundles the widget and imports only React from your app, so you don't need Preact installed.
|
|
105
|
+
|
|
106
|
+
### React 19 — use the web component directly
|
|
107
|
+
|
|
108
|
+
React 19+ supports custom elements natively:
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
// No JS bundle import needed — add a <script> tag or use the web-component sub-entry
|
|
112
|
+
import '@helpai/elements/web-component';
|
|
113
|
+
|
|
114
|
+
function Chat() {
|
|
115
|
+
return <web-ai-chat public-key={import.meta.env.VITE_HELPAI_KEY} ai-agent-deployment-id={import.meta.env.VITE_HELPAI_DEPLOYMENT_ID} theme='auto' />;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### TypeScript typings
|
|
120
|
+
|
|
121
|
+
`import type {} from '@helpai/elements/jsx/react';` once (in your entry file or a `.d.ts`) registers `<web-ai-chat>`
|
|
122
|
+
in React 19's JSX: every attribute the element reads autocompletes, `ai-agent-deployment-id` is required, and a `ref`
|
|
123
|
+
is the typed element with `ask`, `open`, `state`, `ready` and `reset`. Vue and Svelte have `@helpai/elements/jsx/vue`
|
|
124
|
+
and `@helpai/elements/jsx/svelte` ([JSX typings](./api-reference.md#jsx-typings)).
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { useRef } from 'react';
|
|
128
|
+
|
|
129
|
+
import type {} from '@helpai/elements/jsx/react';
|
|
130
|
+
|
|
131
|
+
function Chat() {
|
|
132
|
+
const chat = useRef<HTMLElementTagNameMap['web-ai-chat']>(null);
|
|
133
|
+
return (
|
|
134
|
+
<>
|
|
135
|
+
<button onClick={() => chat.current?.ask('Which plan fits a team of 10?')}>Ask about plans</button>
|
|
136
|
+
<web-ai-chat ref={chat} public-key='agent_pk_...' ai-agent-deployment-id='...' theme='host' />
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Vue 3
|
|
145
|
+
|
|
146
|
+
Composition API:
|
|
147
|
+
|
|
148
|
+
```vue
|
|
149
|
+
<!-- components/Chat.vue -->
|
|
150
|
+
<script setup lang="ts">
|
|
151
|
+
import { onMounted, onBeforeUnmount } from 'vue';
|
|
152
|
+
import { init, type ChatWidgetInstance } from '@helpai/elements';
|
|
153
|
+
|
|
154
|
+
let instance: ChatWidgetInstance | null = null;
|
|
155
|
+
|
|
156
|
+
onMounted(() => {
|
|
157
|
+
instance = init({
|
|
158
|
+
publicKey: import.meta.env.VITE_HELPAI_KEY,
|
|
159
|
+
aiAgentDeploymentId: import.meta.env.VITE_HELPAI_DEPLOYMENT_ID,
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
onBeforeUnmount(() => {
|
|
164
|
+
instance?.destroy();
|
|
165
|
+
});
|
|
166
|
+
</script>
|
|
167
|
+
|
|
168
|
+
<template>
|
|
169
|
+
<!-- Nothing to render — the widget mounts its own DOM -->
|
|
170
|
+
</template>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```vue
|
|
174
|
+
<!-- App.vue -->
|
|
175
|
+
<script setup lang="ts">
|
|
176
|
+
import Chat from './components/Chat.vue';
|
|
177
|
+
</script>
|
|
178
|
+
|
|
179
|
+
<template>
|
|
180
|
+
<main>
|
|
181
|
+
<!-- your app -->
|
|
182
|
+
</main>
|
|
183
|
+
<Chat />
|
|
184
|
+
</template>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Web component approach
|
|
188
|
+
|
|
189
|
+
Vue 3 supports custom elements natively. Register the web-component
|
|
190
|
+
sub-entry, then use the tag:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
// main.ts
|
|
194
|
+
import { createApp } from 'vue';
|
|
195
|
+
import '@helpai/elements/web-component';
|
|
196
|
+
|
|
197
|
+
import App from './App.vue';
|
|
198
|
+
|
|
199
|
+
const app = createApp(App);
|
|
200
|
+
// Tell Vue to treat `web-ai-chat` as a custom element (not a Vue component)
|
|
201
|
+
app.config.compilerOptions.isCustomElement = (tag) => tag === 'web-ai-chat';
|
|
202
|
+
app.mount('#app');
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```vue
|
|
206
|
+
<template>
|
|
207
|
+
<web-ai-chat public-key="agent_pk_..." ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" theme="auto" />
|
|
208
|
+
</template>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Nuxt 3
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
// plugins/web-ai-chat.client.ts
|
|
217
|
+
import { init } from '@helpai/elements';
|
|
218
|
+
|
|
219
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
220
|
+
const chat = init({
|
|
221
|
+
publicKey: useRuntimeConfig().public.helpaiKey,
|
|
222
|
+
aiAgentDeploymentId: useRuntimeConfig().public.helpaiDeploymentId,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
nuxtApp.hook('app:beforeMount', () => {
|
|
226
|
+
// Widget already mounted by init(). This hook is just a reference.
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Clean up on app tear-down (rarely triggered in SPA navigation)
|
|
230
|
+
nuxtApp.hook('app:suspense:resolve', () => {
|
|
231
|
+
// No-op — widget stays across navigations
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
provide: {
|
|
236
|
+
chat,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
// nuxt.config.ts
|
|
244
|
+
export default defineNuxtConfig({
|
|
245
|
+
runtimeConfig: {
|
|
246
|
+
public: {
|
|
247
|
+
helpaiKey: process.env.NUXT_PUBLIC_HELPAI_KEY,
|
|
248
|
+
helpaiDeploymentId: process.env.NUXT_PUBLIC_HELPAI_DEPLOYMENT_ID,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Note the `.client.ts` suffix — ensures the plugin only runs in the
|
|
255
|
+
browser.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Svelte / SvelteKit
|
|
260
|
+
|
|
261
|
+
**SvelteKit**:
|
|
262
|
+
|
|
263
|
+
```svelte
|
|
264
|
+
<!-- src/routes/+layout.svelte -->
|
|
265
|
+
<script lang="ts">
|
|
266
|
+
import { onMount, onDestroy } from 'svelte';
|
|
267
|
+
import { browser } from '$app/environment';
|
|
268
|
+
import { init, type ChatWidgetInstance } from '@helpai/elements';
|
|
269
|
+
import { PUBLIC_HELPAI_DEPLOYMENT_ID, PUBLIC_HELPAI_KEY } from '$env/static/public';
|
|
270
|
+
|
|
271
|
+
let instance: ChatWidgetInstance | null = null;
|
|
272
|
+
|
|
273
|
+
onMount(() => {
|
|
274
|
+
if (!browser) return;
|
|
275
|
+
instance = init({ publicKey: PUBLIC_HELPAI_KEY, aiAgentDeploymentId: PUBLIC_HELPAI_DEPLOYMENT_ID });
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
onDestroy(() => {
|
|
279
|
+
instance?.destroy();
|
|
280
|
+
});
|
|
281
|
+
</script>
|
|
282
|
+
|
|
283
|
+
<slot />
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Plain Svelte** (no SvelteKit):
|
|
287
|
+
|
|
288
|
+
```svelte
|
|
289
|
+
<!-- App.svelte -->
|
|
290
|
+
<script lang="ts">
|
|
291
|
+
import { onMount, onDestroy } from 'svelte';
|
|
292
|
+
import { init, type ChatWidgetInstance } from '@helpai/elements';
|
|
293
|
+
|
|
294
|
+
let instance: ChatWidgetInstance | null = null;
|
|
295
|
+
|
|
296
|
+
onMount(() => {
|
|
297
|
+
instance = init({ publicKey: import.meta.env.VITE_HELPAI_KEY, aiAgentDeploymentId: import.meta.env.VITE_HELPAI_DEPLOYMENT_ID });
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
onDestroy(() => {
|
|
301
|
+
instance?.destroy();
|
|
302
|
+
});
|
|
303
|
+
</script>
|
|
304
|
+
|
|
305
|
+
<main>
|
|
306
|
+
<!-- your app -->
|
|
307
|
+
</main>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Web component in Svelte
|
|
311
|
+
|
|
312
|
+
Svelte handles custom elements natively:
|
|
313
|
+
|
|
314
|
+
```svelte
|
|
315
|
+
<script lang="ts">
|
|
316
|
+
import '@helpai/elements/web-component';
|
|
317
|
+
</script>
|
|
318
|
+
|
|
319
|
+
<web-ai-chat public-key="agent_pk_..." ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" theme="auto" />
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Astro
|
|
325
|
+
|
|
326
|
+
Astro is SSR-first; wrap the widget in a client directive:
|
|
327
|
+
|
|
328
|
+
```astro
|
|
329
|
+
---
|
|
330
|
+
// src/components/Chat.astro
|
|
331
|
+
const publicKey = import.meta.env.PUBLIC_HELPAI_KEY;
|
|
332
|
+
const aiAgentDeploymentId = import.meta.env.PUBLIC_HELPAI_DEPLOYMENT_ID;
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
<script define:vars={{ publicKey, aiAgentDeploymentId }}>
|
|
336
|
+
import('@helpai/elements').then(({ init }) => {
|
|
337
|
+
init({ publicKey, aiAgentDeploymentId });
|
|
338
|
+
});
|
|
339
|
+
</script>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
```astro
|
|
343
|
+
---
|
|
344
|
+
// src/layouts/Layout.astro
|
|
345
|
+
import Chat from '../components/Chat.astro';
|
|
346
|
+
---
|
|
347
|
+
<html>
|
|
348
|
+
<body>
|
|
349
|
+
<slot />
|
|
350
|
+
<Chat />
|
|
351
|
+
</body>
|
|
352
|
+
</html>
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Or use the web component (even simpler — no JS needed):
|
|
356
|
+
|
|
357
|
+
```astro
|
|
358
|
+
---
|
|
359
|
+
import '@helpai/elements/web-component';
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
<web-ai-chat public-key={Astro.env.PUBLIC_HELPAI_KEY} ai-agent-deployment-id={Astro.env.PUBLIC_HELPAI_DEPLOYMENT_ID} />
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Remix
|
|
368
|
+
|
|
369
|
+
Remix (and React Router 7) render on the server, which the [React kit](#react) handles: pass the keys from the loader.
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
// app/root.tsx
|
|
373
|
+
import { HelpAI } from '@helpai/elements/react';
|
|
374
|
+
import { Outlet, useLoaderData } from '@remix-run/react';
|
|
375
|
+
|
|
376
|
+
export async function loader() {
|
|
377
|
+
return {
|
|
378
|
+
helpaiKey: process.env.HELPAI_PUBLIC_KEY ?? '',
|
|
379
|
+
helpaiDeploymentId: process.env.HELPAI_DEPLOYMENT_ID ?? '',
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export default function App() {
|
|
384
|
+
const { helpaiKey, helpaiDeploymentId } = useLoaderData<typeof loader>();
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<html>
|
|
388
|
+
<body>
|
|
389
|
+
<Outlet />
|
|
390
|
+
{helpaiKey && helpaiDeploymentId && <HelpAI publicKey={helpaiKey} aiAgentDeploymentId={helpaiDeploymentId} />}
|
|
391
|
+
</body>
|
|
392
|
+
</html>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## SolidJS
|
|
400
|
+
|
|
401
|
+
```tsx
|
|
402
|
+
import { init, type ChatWidgetInstance } from '@helpai/elements';
|
|
403
|
+
import { onMount, onCleanup } from 'solid-js';
|
|
404
|
+
|
|
405
|
+
export function Chat() {
|
|
406
|
+
let instance: ChatWidgetInstance | null = null;
|
|
407
|
+
|
|
408
|
+
onMount(() => {
|
|
409
|
+
instance = init({ publicKey: import.meta.env.VITE_HELPAI_KEY, aiAgentDeploymentId: import.meta.env.VITE_HELPAI_DEPLOYMENT_ID });
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
onCleanup(() => {
|
|
413
|
+
instance?.destroy();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Solid also supports custom elements natively:
|
|
421
|
+
|
|
422
|
+
```tsx
|
|
423
|
+
import '@helpai/elements/web-component';
|
|
424
|
+
|
|
425
|
+
export default function App() {
|
|
426
|
+
return <web-ai-chat public-key='agent_pk_...' ai-agent-deployment-id='01900000-0000-7000-8000-000000000000' />;
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Angular
|
|
433
|
+
|
|
434
|
+
Angular needs `CUSTOM_ELEMENTS_SCHEMA` to accept the custom tag:
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
// src/app/app.module.ts
|
|
438
|
+
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
439
|
+
import '@helpai/elements/web-component';
|
|
440
|
+
|
|
441
|
+
@NgModule({
|
|
442
|
+
// ...
|
|
443
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
444
|
+
})
|
|
445
|
+
export class AppModule {}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
```html
|
|
449
|
+
<!-- app.component.html -->
|
|
450
|
+
<web-ai-chat public-key="agent_pk_..." ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" theme="auto"></web-ai-chat>
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
For programmatic control:
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
// chat.service.ts
|
|
457
|
+
import { Injectable } from '@angular/core';
|
|
458
|
+
import { init, type ChatWidgetInstance } from '@helpai/elements';
|
|
459
|
+
|
|
460
|
+
import { environment } from '../environments/environment';
|
|
461
|
+
|
|
462
|
+
@Injectable({ providedIn: 'root' })
|
|
463
|
+
export class ChatService {
|
|
464
|
+
private instance: ChatWidgetInstance | null = null;
|
|
465
|
+
|
|
466
|
+
mount() {
|
|
467
|
+
if (!this.instance) {
|
|
468
|
+
this.instance = init({ publicKey: environment.helpaiKey, aiAgentDeploymentId: environment.helpaiDeploymentId });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
destroy() {
|
|
473
|
+
this.instance?.destroy();
|
|
474
|
+
this.instance = null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
open() {
|
|
478
|
+
this.instance?.open();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## WordPress
|
|
486
|
+
|
|
487
|
+
Add the snippet via the Theme Header/Footer plugin OR directly in
|
|
488
|
+
your theme's `header.php`:
|
|
489
|
+
|
|
490
|
+
```html
|
|
491
|
+
<!-- Before </head> -->
|
|
492
|
+
<script src="https://cdn.help.ai/sdk/js/elements/latest/elements.js" data-public-key="agent_pk_abc123..." data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" defer></script>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Via a plugin
|
|
496
|
+
|
|
497
|
+
Any "Insert Headers and Footers" plugin works:
|
|
498
|
+
|
|
499
|
+
1. Install the plugin (e.g., "Insert Headers and Footers" by WPBeginner).
|
|
500
|
+
2. Settings → Insert Headers and Footers.
|
|
501
|
+
3. Paste the script tag into the "Scripts in Header" box.
|
|
502
|
+
4. Save.
|
|
503
|
+
|
|
504
|
+
### Via functions.php
|
|
505
|
+
|
|
506
|
+
```php
|
|
507
|
+
<?php
|
|
508
|
+
// Add to your theme's functions.php
|
|
509
|
+
function helpai_enqueue_chat() {
|
|
510
|
+
?>
|
|
511
|
+
<script
|
|
512
|
+
src="https://cdn.help.ai/sdk/js/elements/latest/elements.js"
|
|
513
|
+
data-public-key="agent_pk_abc123..."
|
|
514
|
+
data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000"
|
|
515
|
+
defer
|
|
516
|
+
></script>
|
|
517
|
+
<?php
|
|
518
|
+
}
|
|
519
|
+
add_action('wp_head', 'helpai_enqueue_chat');
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Personalization for logged-in users
|
|
523
|
+
|
|
524
|
+
```php
|
|
525
|
+
<?php
|
|
526
|
+
function helpai_enqueue_chat_personalized() {
|
|
527
|
+
$user = wp_get_current_user();
|
|
528
|
+
$attrs = 'data-public-key="agent_pk_..." data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000"';
|
|
529
|
+
if ($user->ID) {
|
|
530
|
+
$attrs .= ' data-user-id="' . esc_attr($user->ID) . '"';
|
|
531
|
+
$attrs .= ' data-user-email="' . esc_attr($user->user_email) . '"';
|
|
532
|
+
$attrs .= ' data-user-name="' . esc_attr($user->display_name) . '"';
|
|
533
|
+
$attrs .= ' data-user-context=\'' . esc_attr(json_encode(array("plan" => "pro"))) . '\'';
|
|
534
|
+
}
|
|
535
|
+
?>
|
|
536
|
+
<script src="https://cdn.help.ai/sdk/js/elements/latest/elements.js" <?php echo $attrs; ?> defer></script>
|
|
537
|
+
<?php
|
|
538
|
+
}
|
|
539
|
+
add_action('wp_head', 'helpai_enqueue_chat_personalized');
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
> Note: `data-user-*` / `data-page-*` are host-asserted context for the
|
|
543
|
+
> AI, never an auth credential — the browser deployment is selected by
|
|
544
|
+
> `data-public-key` + `data-ai-agent-deployment-id`. Explicit
|
|
545
|
+
> scalar attributes win over keys in the `data-user-context` /
|
|
546
|
+
> `data-page-context` JSON.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Shopify
|
|
551
|
+
|
|
552
|
+
Shopify has a "custom pixels" and "additional scripts" workflow.
|
|
553
|
+
Easiest path:
|
|
554
|
+
|
|
555
|
+
1. In your admin: **Online Store → Themes → Edit code**.
|
|
556
|
+
2. Open `theme.liquid`.
|
|
557
|
+
3. Paste before `</head>`:
|
|
558
|
+
|
|
559
|
+
```html
|
|
560
|
+
<script src="https://cdn.help.ai/sdk/js/elements/latest/elements.js" data-public-key="agent_pk_..." data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" defer></script>
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### With Shopify customer data
|
|
564
|
+
|
|
565
|
+
```html
|
|
566
|
+
{% if customer %}
|
|
567
|
+
<script
|
|
568
|
+
src="https://cdn.help.ai/sdk/js/elements/latest/elements.js"
|
|
569
|
+
data-public-key="agent_pk_..."
|
|
570
|
+
data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000"
|
|
571
|
+
data-user-id="{{ customer.id }}"
|
|
572
|
+
data-user-email="{{ customer.email }}"
|
|
573
|
+
data-user-name="{{ customer.first_name }} {{ customer.last_name }}"
|
|
574
|
+
data-page-area="orders"
|
|
575
|
+
defer
|
|
576
|
+
></script>
|
|
577
|
+
{% else %}
|
|
578
|
+
<script src="https://cdn.help.ai/sdk/js/elements/latest/elements.js" data-public-key="agent_pk_..." data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" defer></script>
|
|
579
|
+
{% endif %}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## Webflow
|
|
585
|
+
|
|
586
|
+
Webflow lets you add site-wide custom code:
|
|
587
|
+
|
|
588
|
+
1. Site settings → **Custom code → Head code**.
|
|
589
|
+
2. Paste:
|
|
590
|
+
|
|
591
|
+
```html
|
|
592
|
+
<script src="https://cdn.help.ai/sdk/js/elements/latest/elements.js" data-public-key="agent_pk_..." data-ai-agent-deployment-id="01900000-0000-7000-8000-000000000000" defer></script>
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
3. Save + publish.
|
|
596
|
+
|
|
597
|
+
Page-specific customization: open the page → **Page settings →
|
|
598
|
+
Inside `<head>` tag** and paste a page-specific snippet.
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## Squarespace / Wix
|
|
603
|
+
|
|
604
|
+
**Squarespace:**
|
|
605
|
+
|
|
606
|
+
1. Settings → **Advanced → Code Injection**.
|
|
607
|
+
2. Paste the script tag into the **Header** section.
|
|
608
|
+
|
|
609
|
+
**Wix:**
|
|
610
|
+
|
|
611
|
+
1. Settings → **Custom Code**.
|
|
612
|
+
2. Add new snippet.
|
|
613
|
+
3. Paste + choose "All pages" + "Head" placement.
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
## Framework-agnostic troubleshooting
|
|
618
|
+
|
|
619
|
+
**The widget doesn't appear in SSR previews** — that's expected. The
|
|
620
|
+
widget is client-only. It appears after hydration / mount.
|
|
621
|
+
|
|
622
|
+
**The widget flashes open then closes on SPA navigation** — you're
|
|
623
|
+
probably calling `destroy()` then `init()` on every route change. Use
|
|
624
|
+
`init()` alone — it's idempotent. If there's an existing instance at
|
|
625
|
+
the same `widgetId`, it merges the new options in.
|
|
626
|
+
|
|
627
|
+
**Hot module replacement breaks the widget** — Next.js / Vite HMR
|
|
628
|
+
sometimes mounts duplicate instances. Always pair your `useEffect` /
|
|
629
|
+
`onMounted` with a cleanup that calls `destroy()`.
|
|
630
|
+
|
|
631
|
+
**CSP blocks the widget** — the widget inlines styles inside a shadow
|
|
632
|
+
root (requires `style-src 'unsafe-inline'` or a nonce pattern). See
|
|
633
|
+
[Security & privacy § CSP](./security-privacy.md#content-security-policy).
|
|
634
|
+
|
|
635
|
+
More: [Troubleshooting](./troubleshooting.md).
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Next
|
|
640
|
+
|
|
641
|
+
- [Recipes](./recipes.md) — programmatic control patterns.
|
|
642
|
+
- [Events & hooks](./events-and-hooks.md) — analytics integration.
|
|
643
|
+
- [Configuration](./configuration.md) — every option in detail.
|