Skip to main content

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:manage permission (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.

  1. In the dashboard, open Support → Channels → Add channel → Website.

  2. Fill in the form:

    FieldWhat to enter
    Site nameA name for your team, for example "Main store". It is also the title in the widget header; you can change it later.
    DomainThe host the widget runs on, for example shop.vn. The domain and all its subdomains are always allowed.
    Extra allowed originsOptional. One origin per line for other places the widget must load, for example https://app.example.com or http://localhost:3000.
  3. 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.

tip

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:

PlatformSteps
WordPressInstall 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>.
ShopifyOnline 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.
HaravanWebsite → 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.
LadiPageOpen 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.
SapoWebsite → Themes → Actions → Chỉnh sửa HTML/CSS (Edit HTML/CSS). Open Theme.bwt and paste the snippet just before </body>. Save.
Google Tag ManagerTags → 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.
WebflowProject settings → Custom code → Footer code, paste the snippet. Publish.
React / Next.jsInstall @hatang/chat-react and render <HatangChat siteId="..." /> once in your root layout. See below.
Any HTML sitePaste 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
app/layout.tsx
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, both https://shop.vn and https://www.shop.vn work.
  • Each entry in Extra allowed origins must match exactly, including scheme and port: http://localhost:3000 does not allow http://localhost:5173.
  • Requests without an Origin header (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 seeCauseFix
bootstrap returns 403 with origin_not_allowedThe 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_disabledThe site's Status is Disabled (widget hidden).Set it back to Active in the site settings.
bootstrap returns 403 with product_disabledThe Support module is turned off for the business.Turn Support on again. See Businesses and modules.
bootstrap returns 429More 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 allThe site ID is missing or the snippet is not on the page.Check the page source for HATANG_SITE_ID.
bootstrap succeeds but no launcherThe 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 consoleYour 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​

View this page as Markdown