1) Create a site
- Go to /sites
- Click "Add Site"
- Set the domain (e.g. example.com) to enable automatic production installs (no siteId needed on your site)
- Open /sites/[id]/settings to copy the installation snippet
2) Choose an installation method
Both options load the same widget. Choose based on your setup:
Option A — Script tag
Best if you want the simplest setup: no bundler, no app code changes, works on plain HTML sites, Webflow, WordPress, etc.
You paste one <script> snippet and you're done.
Option B — npm SDK
Best for React/Next.js and SPAs when you want to control the widget from code (open it from a button, identify users after login, change settings, etc.).
You install @humanfirst-chat/js and call HFChat.init() in a Client Component.
Tip: on localhost, you must provide a siteId. In production, if your site has a domain set, you can omit it and let HumanFirst.chat resolve the site by website host.
3) Option A — Script tag
Add this right before </body> (works everywhere):
<script src="https://humanfirst.chat/widget.js" data-site-id="YOUR_SITE_ID"></script>That's it — the widget loads and auto-initializes.
Calling commands
The script exposes window.HFChat. Commands are queued until the widget is ready, so you can call them immediately:
<script>
// After the script tag (or after DOMContentLoaded)
window.HFChat?.open()
window.HFChat?.identify({ email: "jane@example.com", plan: "pro" })
</script>4) Option B — npm SDK
Install the SDK:
pnpm add @humanfirst-chat/jsNext.js (Client Component):
"use client";
import { useEffect } from "react";
import HFChat from "@humanfirst-chat/js";
export function SupportChat() {
useEffect(() => {
void HFChat.init({ siteId: "YOUR_SITE_ID" });
}, []);
return <button onClick={() => HFChat.open()}>Chat</button>;
}Why use the SDK?
You can call HFChat.open() (and other commands) right away. The SDK loads the widget script in the background and runs your command once the widget is ready.
Production domain install (optional)
If you set a domain for your site in the dashboard, you can omit siteId in production and let HumanFirst.chat resolve the correct site from your website host.
<script src="https://humanfirst.chat/widget.js"></script>
<script>
// Works in production if the domain is configured in the dashboard.
// On localhost you still must pass siteId.
HumanFirstChat.init({ logs: "minimal" });
</script>Widget API (commands)
Control the widget from JavaScript: open/close, hide/show, identify visitors, and update appearance.
Using the npm SDK
Import @humanfirst-chat/js and call methods directly.
import HFChat from "@humanfirst-chat/js";
void HFChat.init({ siteId: "YOUR_SITE_ID" });
HFChat.open();
HFChat.identify({ email: "jane@example.com", name: "Jane" });
HFChat.configure({ widgetPosition: "left", widgetColor: "#2563eb" });
HFChat.onReady(() => {
// Safe place to run commands that depend on the widget being ready
});Using the script tag
After the script loads, the widget exposes window.HFChat (and HumanFirstChat.init).
<script src="https://humanfirst.chat/widget.js" data-site-id="YOUR_SITE_ID"></script>
<script>
// After the script tag (or after DOMContentLoaded)
window.HFChat?.open();
window.HFChat?.identify({ email: "jane@example.com", name: "Jane" });
</script>Command reference
show() / hide() — Show or hide the widget entirely
open() / close() / toggle() — Control the chat panel
open({ focus: true }) — Open and focus the input (ideal for custom CTAs)
isOpen() — Returns whether the panel is open
identify(meta) — Attach visitor metadata (email, name, and any custom fields). Can be called at any time — before or after the widget loads. New data is merged with existing metadata.
configure(settings) — Change widget UI (color/position/size)
onReady(cb) — Runs when the widget is fully ready (useful for "run after load")
onOpen(cb) / onClose(cb) — Runs when the panel opens/closes
ready — Boolean flag indicating readiness
Custom CTA on a specific page (example: /premium)
For special pages, you can hide the default bubble and use a custom button that opens the chat with focus.
"use client";
import { useEffect } from "react";
import { usePathname } from "next/navigation";
import HFChat from "@humanfirst-chat/js";
export function PremiumChatCTA() {
const pathname = usePathname();
useEffect(() => {
if (pathname !== "/premium") return;
HFChat.hide();
return () => HFChat.show();
}, [pathname]);
return (
<button type="button" onClick={() => HFChat.open({ focus: true })}>
Any question? Chat with me
</button>
);
}Troubleshooting
- If the bubble doesn't appear, check your snippet (script URL + data-site-id) and open the browser console for errors.
- If your site has a strict CSP, allow script-src, connect-src, and frame-src for https://humanfirst.chat.
- On localhost, always provide a siteId (domain-based resolution only works in production).