Dark mode
Widget SDK developer guide

Widget SDK developer guide

This guide is for developers who control the Helpin chat widget from their own code. It covers the client lifecycle, signed-in users, logout, widget events, and the script-tag command API. To install the widget and see the basic options, start with Embed the widget.

Prerequisites

  • A widget key from Settings → Chat widget.

  • Your site's origin added to the widget's allowed origins. See Embedding reference.

  • The SDK loaded with a script tag (lib.js) or installed with npm install @helpin-ai/sdk-js.

Two ways to call the SDK

The npm package returns a typed client object. The script tag exposes the same methods as commands on a global function, named helpin by default (change it with namespace).

import { helpinClient } from '@helpin-ai/sdk-js';

const client = helpinClient({
  widgetKey: 'your-widget-key',
  host: 'https://client.helpin.ai',
  autoBoot: false,
});
client?.open();
<script>
  helpin('onLoad', function () {
    helpin('open');
  });
</script>

helpinClient(...) returns null if it can't initialize, so check the result before you use it. With the script tag, helpin(...) calls made before the SDK finishes loading are queued and run in order. Use helpin('onLoad', callback) when your code must wait for the SDK.

Framework packages

For Vue, React, and Next.js apps, Helpin publishes thin wrappers around @helpin-ai/sdk-js. Each package exports createClient(options), which accepts the same options as helpinClient(...) and returns the same client. The package then shares that client with your components and gives you a useHelpin() composable or hook. Everything else in this guide, such as boot(), id(), show() / hide(), and the event listeners, works the same way.

Package

Share the client

Use it in components

@helpin-ai/vue (Vue 3.3+)

app.use(HelpinPlugin, { client })

useHelpin(), or $helpin in templates

@helpin-ai/react

<HelpinProvider client={client}>

useHelpin()

@helpin-ai/nextjs

<HelpinProvider client={client}> in a Client Component

useHelpin()

Vue

npm install @helpin-ai/vue @helpin-ai/sdk-js
// main.ts
import { createApp } from 'vue';
import { createClient, HelpinPlugin } from '@helpin-ai/vue';
import App from './App.vue';

const client = createClient({
  widgetKey: 'your-widget-key',
  host: 'https://client.helpin.ai',
});

createApp(App).use(HelpinPlugin, { client }).mount('#app');
<script setup lang="ts">
import { useHelpin } from '@helpin-ai/vue';

const helpin = useHelpin();
</script>

<template>
  <button @click="helpin.open()">Chat with us</button>
</template>

createClient() returns null during server rendering. In Nuxt 3, create the client and install HelpinPlugin in a client-only plugin, such as plugins/helpin.client.ts.

React

npm install @helpin-ai/react @helpin-ai/sdk-js
import { createClient, HelpinProvider, useHelpin } from '@helpin-ai/react';

const client = createClient({
  widgetKey: 'your-widget-key',
  host: 'https://client.helpin.ai',
});

function HelpButton() {
  const { open } = useHelpin();
  return <button onClick={open}>Chat with us</button>;
}

export function Root() {
  return (
    <HelpinProvider client={client}>
      <HelpButton />
    </HelpinProvider>
  );
}

Next.js

npm install @helpin-ai/nextjs @helpin-ai/sdk-js
'use client';

import { useMemo } from 'react';
import { createClient, HelpinProvider } from '@helpin-ai/nextjs';

export function Providers({ children }: { children: React.ReactNode }) {
  const client = useMemo(
    () =>
      createClient({
        widgetKey: process.env.NEXT_PUBLIC_HELPIN_WIDGET_KEY!,
        host: process.env.NEXT_PUBLIC_HELPIN_HOST!,
      }),
    [],
  );

  return <HelpinProvider client={client}>{children}</HelpinProvider>;
}

Wrap your root layout in Providers, then call useHelpin() from any Client Component. createClient() returns null on the server, so always call it from a Client Component.

What useHelpin() returns

In all three packages, useHelpin() returns id, track, lead, trackPageView, set, unset, rawTrack, show, hide, open, close, toggle, openMessages, openNewMessage, openConversation, openArticle, and shutdown. trackPageView() is the same as pageview(). If no client is available, for example during server rendering, the methods do nothing.

For boot(), reset(), group(), the event listeners, and the getters, call the client that createClient(...) returned:

client?.onUnreadCountChange((count) => {
  // update your own badge
});

Each package also exports usePageView() for tracking route changes yourself. If you use it, set autoPageview: false on the client so each navigation isn't counted twice. In Vue, pass your router: usePageView({ router: useRouter() }). In Next.js, pass the client: usePageView(client).

Control when the widget starts

By default, the widget boots as soon as widgetKey and host are set. To show it only after your own logic runs, for example behind a custom Help button, set autoBoot: false (or data-auto-boot="false"). The widget then stays dormant until you call boot(), show(), open(), openMessages(), or openNewMessage().

Method

What it does

boot(settings?)

Boots or re-boots the widget. settings can include widgetKey, host, and user.

show() / hide()

Shows the launcher without opening the panel; hides the launcher and closes the panel.

open() / close() / toggle()

Opens, closes, or toggles the chat panel.

openMessages()

Opens the conversation list.

openNewMessage(content?)

Starts a new conversation, optionally pre-filled with content.

openConversation(conversationId)

Opens a specific conversation.

openArticle(articleKey, options?)

Opens a Help Center article inside the widget. options accepts collectionId and spaceId.

shutdown()

Ends the widget session and removes the widget from the page.

For openArticle, pass the last segment of the article's URL, not the full URL.

Identify signed-in users

Call id(...) after a user signs in. The SDK accepts id, email, first_name / firstName, last_name / lastName, phone, job_title / jobTitle, and a company object with id, name, and created_at.

const identity = await fetch('/api/helpin/identity', { cache: 'no-store' })
  .then((response) => response.json());
await client.id(identity);

In this example, /api/helpin/identity is an endpoint in your application. It reads the signed-in user from your own session and returns their identity with an identity_verification proof. The proof has this shape:

{
  "version": "v1",
  "issued_at": 1767225600,
  "expires_at": 1767225900,
  "signature": "hex-encoded HMAC-SHA256"
}

Your backend builds the proof by joining these values with newline characters, in this order:

  1. helpin-widget-identity:v1

  2. Your widget key

  3. The email, trimmed and lowercased

  4. The user ID you send as id

  5. The company ID, trimmed, or an empty string

  6. issued_at, in Unix seconds

  7. expires_at, in Unix seconds

Sign that text with HMAC-SHA256, using your installation's signing secret as the key (the secret string itself, not hex-decoded), and hex-encode the result. The proof can be valid for at most 15 minutes, and issued_at can't be more than one minute ahead of Helpin's clock. Send exactly the values you signed.

import hashlib, hmac, time

def sign_identity(secret, widget_key, email, user_id="", company_id=""):
    issued_at = int(time.time())
    expires_at = issued_at + 300
    message = "\n".join([
        "helpin-widget-identity:v1", widget_key, email.strip().lower(),
        user_id, company_id.strip(), str(issued_at), str(expires_at),
    ])
    signature = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return {"version": "v1", "issued_at": issued_at,
            "expires_at": expires_at, "signature": signature}

Keep the signing secret on your server. It's a different value from the public widget key. Only sign identities taken from your own authenticated session, never values sent by the browser.

Visitor identity verification in Settings → Chat widget controls how Helpin treats identities:

  • Accept unverified identities treats unsigned identities as unverified visitor claims. A valid proof still marks the identity as verified.

  • Require server-signed identities rejects identity requests with a missing, expired, or mismatched proof. Anonymous chat still works.

Get the signing secret

You need a workspace admin or owner role.

  1. In Helpin, open Settings → Chat widget and find Identity signing secret.

  2. Use the Reveal (eye) or Copy icon next to the masked secret, and store the secret in your server's secret configuration. Never put it in browser code.

  3. To replace it, select Regenerate secret and confirm. The old secret stops working immediately, so update your server right away. Regenerating the widget key also replaces the signing secret.

Until your server uses the new secret, identities signed with the old one are rejected when Require server-signed identities is on, and treated as unverified otherwise.

Log out

When a user signs out of your app, end their widget session and clear the stored identity:

client.shutdown();
await client.reset(true); // true also replaces the anonymous visitor ID

Listen to widget events

Method

Called when

Callback argument

onOpen(callback)

The visitor opens the panel from the widget

none

onClose(callback)

The visitor closes the panel from the widget

none

onUnreadCountChange(callback)

The total unread count changes

the new count

onUserEmailSupplied(callback)

The visitor enters their email

the email

onConversationStarted(callback)

A new conversation is created

the conversation ID

onMessageReceived(callback)

A message arrives

the message object

onOpen and onClose fire only for the visitor's own clicks, not when your code calls open() or close().

client.onUnreadCountChange((count) => {
  document.querySelector('#help-badge').textContent = count ? String(count) : '';
});

Track events

Method

Use it to

track(eventName, payload?)

Record a custom event.

lead(payload)

Record a lead. email is required.

group(company)

Link the current user to a company.

pageview()

Record a pageview manually.

articleView(articleId, properties?)

Record a help article view.

set(properties, opts?) / unset(name, opts?)

Add or remove properties sent with events.

Helpin records pageviews automatically, including navigation in single-page apps, unless you set autoPageview: false.

Read state

getVisitorId() returns the anonymous visitor ID, isWidgetReady() reports whether the widget has loaded, and getConfig() returns the merged configuration.

Was this article helpful?