Install the web widget
The web widget is the live chat bubble that visitors see on your website. This page shows you how to create a website channel, add the snippet to your site (by hand or through WordPress, Shopify, Haravan, LadiPage, Sapo, Google Tag Manager, Webflow or React), and check that it works.
Before you start
- The Support module is turned on for your business. If it is off, the widget stays hidden.
- Your role can manage Support. Support → Channels needs the
chat:managepermission (Owner, Admin, Developer, or a member with "manage" on Support). See Team and roles. - You know the domain the widget runs on, for example
shop.vn.
1. Create a website channel
Each website is a channel with its own site_id, snippet and settings. A business can have several.
-
In the dashboard, open Support → Channels → Add channel → Website.
-
Fill in the form:
Field What to enter Site name A name for your team, for example "Main store". It is also the title in the widget header; you can change it later. Domain The host the widget runs on, for example shop.vn. The domain and all its subdomains are always allowed.Extra allowed origins Optional. One origin per line for other places the widget must load, for example https://app.example.comorhttp://localhost:3000. -
Click Create site. The site page opens with the snippet ready.
To find it later, open Support → Channels and pick the website.
2. Copy the snippet
The Install card on the site page shows the snippet with your site_id filled in. Click Copy snippet.
<script>window.$hatang=window.$hatang||[];window.HATANG_SITE_ID="site_123...";</script>
<script src="https://chat.hatang.dev/widget.js" async></script>
The first tag creates the command queue and sets your site ID. The second tag loads the widget loader. The loader is small and cached for five minutes; it fetches your site settings and then loads the versioned widget bundle. The widget renders inside a shadow DOM, so your page CSS does not leak into it and its CSS does not leak into your page.
If you prefer one tag, the loader also reads the site ID from a data-site-id attribute:
<script src="https://chat.hatang.dev/widget.js" data-site-id="site_123..." async></script>.
Use the two-tag form if you also call $hatang.push(...) before the widget loads, because the first tag creates the queue.
3. Paste it on every page
Paste the snippet just before </body> on every page where visitors should be able to chat. Platform steps:
| Platform | Steps |
|---|---|
| WordPress | Install the Ha Tang Chat plugin (Plugins → Add New, search "Ha Tang Chat") and activate it. Open Settings → Ha Tang Chat, paste the Site ID and save. Logged-in users are identified automatically. See WordPress. Without the plugin: Appearance → Theme File Editor → footer.php, paste the snippet before </body>. |
| Shopify | Online Store → Themes → Edit code. Open layout/theme.liquid and paste the snippet just before </body>. Save. The widget appears on every storefront page, including checkout pages that use the theme layout. |
| Haravan | Website → Giao diện → Chỉnh sửa mã nguồn (Haravan's labels for Website → Theme → Edit source code). Open layout/theme.liquid, paste the snippet before </body> and save. |
| LadiPage | Open the landing page, then in the toolbar choose Thiết lập → Mã JavaScript/CSS (Settings → JavaScript/CSS code). Paste the snippet into the code box, before </body>. Save, then Publish; the page shows chat only after it is published again. Install it on each landing page. |
| Sapo | Website → Themes → Actions → Chỉnh sửa HTML/CSS (Edit HTML/CSS). Open Theme.bwt and paste the snippet just before </body>. Save. |
| Google Tag Manager | Tags → New → Custom HTML, paste the snippet. Trigger: All Pages. Save and publish the container. Tick "Support document.write" only if your container requires it; the snippet does not need it. |
| Webflow | Project settings → Custom code → Footer code, paste the snippet. Publish. |
| React / Next.js | Install @hatang/chat-react and render <HatangChat siteId="..." /> once in your root layout. See below. |
| Any HTML site | Paste the snippet before </body> on every page. The second tag can use defer instead of async. |
React and Next.js
npm install @hatang/chat-react
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>
);
}
HatangChat renders nothing on the server and loads the widget once in the browser. Use useHatang() or hatang() to call the JavaScript API. Details are on the React SDK page.
4. Check the installation
Open your website in a browser. The launcher button appears in the bottom-right corner (or where you set it in Configure the widget).
Back on the site page, the Install card shows Installed on shop.vn, last seen a few minutes ago once the widget has loaded on your domain. Until then it shows Not detected yet. The status is refreshed at most once a minute.
Send a test message from the widget. It appears in Support → Inbox as a new conversation.
Which origins can load the widget
Every request the widget makes is checked against the page's Origin:
- The site's Domain and every subdomain of it are always allowed. With
shop.vn, bothhttps://shop.vnandhttps://www.shop.vnwork. - Each entry in Extra allowed origins must match exactly, including scheme and port:
http://localhost:3000does not allowhttp://localhost:5173. - Requests without an
Originheader (for example from a server) are rejected unless they come from a mobile app with an app key.
Add your local development and preview URLs to Extra allowed origins while you test.
Several websites
Create one website channel per domain or brand: Support → Channels → Add channel → Website. Each site has its own snippet, settings, identity secret and channels (Zalo, Messenger and others are attached to a website). All conversations land in the same Inbox.
Troubleshooting
When the widget cannot load, it stays silent: no launcher and no error on the page. Open your browser's developer tools, then the Network tab, and look at the bootstrap request to chat.hatang.dev.
| What you see | Cause | Fix |
|---|---|---|
bootstrap returns 403 with origin_not_allowed | The page's origin is not the site's domain, a subdomain of it, or an extra allowed origin. | Fix Domain or add the origin under Extra allowed origins. |
bootstrap returns 403 with site_disabled | The site's Status is Disabled (widget hidden). | Set it back to Active in the site settings. |
bootstrap returns 403 with product_disabled | The Support module is turned off for the business. | Turn Support on again. See Businesses and modules. |
bootstrap returns 429 | More than 30 bootstrap calls per minute from one IP address. | Wait a minute; check that the snippet is not loaded in a loop. |
No bootstrap request at all | The site ID is missing or the snippet is not on the page. | Check the page source for HATANG_SITE_ID. |
bootstrap succeeds but no launcher | The page is excluded by Where the widget shows, Hide the bubble entirely when offline is on and nobody is online, hideLauncher is set in window.HATANG_CONFIG, or the page runs in a cross-origin iframe. | See Configure the widget. |
| Script or socket blocked in the console | Your Content Security Policy does not allow the widget. | Allow https://chat.hatang.dev in script-src and connect-src, and wss://chat.hatang.dev in connect-src. |
Next steps
- Configure the widget: colors, launcher, greeting, pre-chat form, office hours.
- JavaScript API: open the chat from your own buttons and listen to events.
- Identity verification: link chats to your signed-in users.