React and Next.js (@hatang/chat-react)
@hatang/chat-react loads the Ha Tang chat widget in a React or Next.js app. It gives you a component that renders nothing and injects the widget script once, and a hook that returns the typed $hatang JavaScript API. The widget is still the web widget, with the same look and the same dashboard settings; this package only handles loading it and the TypeScript types.
@hatang/chat-react 0.1.2 · React 18+ · Next.js 14+ (App Router and Pages Router) · npm · changelog: CHANGELOG.md in the package
Before you start
- A website channel in Ha Tang. Copy its Site ID (
site_...) from Support → Channels → your website. - The domain your app runs on must be the website's domain (or one of its subdomains), or be listed under Extra allowed origins in the website's settings. Add
http://localhost:3000there for local development.
Install
npm install @hatang/chat-react
Load the widget
Render <HatangChat /> once, in your root layout. The module starts with "use client", so you can use it directly in the App Router.
import { HatangChat } from "@hatang/chat-react";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<HatangChat siteId="site_123..." />
</body>
</html>
);
}
On first render the component sets window.HATANG_SITE_ID, sets window.HATANG_CONFIG when you pass config, and appends https://chat.hatang.dev/widget.js with async. It never adds the script twice, even when it renders again or more than once. Once the first page loads, the website in the dashboard shows that the widget is installed.
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
siteId | string | required | The website's Site ID |
host | string | https://chat.hatang.dev | Where widget.js is served from. Change it only for a local gateway |
config | HatangConfig | — | { position?: "left" | "right"; locale?: "vi" | "en"; hideLauncher?: boolean }, written to window.HATANG_CONFIG before the script loads |
user | HatangIdentity | — | { userId?, email?, name?, phone?, hash?, data? }. Calls identify when the widget is ready, and again whenever userId, email, name or hash changes |
config is read once, when the script is first added; later changes to it do not reach the widget. To switch language at runtime, call setLocale. The HATANG_CONFIG options offset and mobileOffset are not in the HatangConfig type yet; if you need them, set window.HATANG_CONFIG yourself before the component renders (see Web widget and JS API).
Call the widget from your code
useHatang() (a hook) and hatang() (a plain function, for code outside components) return the same object. Calls made before the widget has loaded are queued, so you can call them at any time in the browser. On the server they do nothing.
"use client";
import { useHatang } from "@hatang/chat-react";
export function SupportButton() {
const chat = useHatang();
return <button onClick={() => chat.open()}>Chat with us</button>;
}
| Method | What it does |
|---|---|
open(), close(), toggle() | Open, close or toggle the chat window |
hide(), show() | Hide or show the launcher button (for example on a checkout page) |
identify(identity) | Attach the signed-in user; hash is computed on your server (Identity verification) |
setData(data) | Custom attributes shown to agents |
setLocale("vi" | "en") | Change the widget's language |
pushEvent(name, data?) | Record an event on the visitor's timeline |
on(event, cb), off(event, cb) | Listen to ready, open, close, message:received, message:sent, conversation:status |
reset() | Forget the current visitor (on sign-out). The widget reloads the page to start a fresh session |
"use client";
import { useEffect } from "react";
import { hatang } from "@hatang/chat-react";
export function ChatAnalytics() {
useEffect(() => {
const chat = hatang();
const onReply = (m?: unknown) => track("chat_reply", m);
chat.on("message:received", onReply);
return () => chat.off("message:received", onReply);
}, []);
return null;
}
The widget also takes commands this typed API does not list, such as lead. Push them on the queue yourself: window.$hatang.push(["lead", { email, name }]). The full command and event list is in Web widget and JS API.
Identify signed-in users
Compute hash, the HMAC-SHA256 of the user id with the site's identity secret, on the server and pass it down with the user. Never put the secret in the client bundle.
import { createHmac } from "node:crypto";
import { HatangChat } from "@hatang/chat-react";
import { currentUser } from "@/lib/auth";
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const user = await currentUser();
const identity = user
? {
userId: user.id,
email: user.email,
name: user.name,
hash: createHmac("sha256", process.env.HATANG_IDENTITY_SECRET!).update(user.id).digest("hex"),
}
: undefined;
return (
<html lang="en">
<body>
{children}
<HatangChat siteId="site_123..." user={identity} />
</body>
</html>
);
}
With a valid hash, the inbox marks the visitor as verified and merges the conversation with that user's earlier sessions, including those from your mobile app. Call hatang().reset() when the user signs out so the next person on the same browser does not inherit the identity.
Without useEffect
For the Pages Router, other frameworks or a plain HTML template, hatangSnippet(siteId, host?, config?) returns the same inline script the dashboard shows, as one string. Put it in a <script> tag or in next/script:
import Script from "next/script";
import { hatangSnippet } from "@hatang/chat-react";
<Script id="hatang" strategy="afterInteractive">
{hatangSnippet("site_123...", undefined, { locale: "en" })}
</Script>
Exports
HatangChat, HatangChatProps, hatang, useHatang, HatangApi, HatangIdentity, HatangEvent, HatangConfig, hatangSnippet, inlineSnippet and widgetUrl.
Changelog
0.1.1: the npm page describes the widget and Ha Tang and links this guide; the README ends with an About Ha Tang section. No code changes.
0.1.0: first release. <HatangChat siteId host config user /> loads the widget once; useHatang() / hatang() with open, close, toggle, hide, show, identify, setData, setLocale, pushEvent, on, off and reset, queued until the widget loads.
Next steps
- Web widget and JS API: every
HATANG_CONFIGoption, theleadcommand and conversion tracking. - Identity verification: signed identities and how sessions merge.
- Install the widget: Shopify, Google Tag Manager, Webflow and plain HTML.