JavaScript API
Once the install code has loaded, window.ZebChat lets your page control the widget, identify logged-in customers and add context for your team.
| Method | What it does |
|---|---|
ZebChat.open() | Open the chat panel |
ZebChat.close() | Close the chat panel |
ZebChat.toggle() | Open or close the panel |
ZebChat.show() | Show the widget after hide() |
ZebChat.hide() | Hide the whole widget on this page |
ZebChat.startChat(message?) | Open the chat and optionally send a first message |
ZebChat.setUser(user) | Identify the visitor (verified or not) |
ZebChat.setTag(tags) | Add tags to the visitor |
ZebChat.track(name, properties?) | Record a custom event in the visitor’s journey |
ZebChat.consent(granted) | Pass on the visitor’s cookie consent |
ZebChat.setSound(on) | Turn the new-message sound on or off |
ZebChat.mute() | Turn the new-message sound off |
Every method returns nothing and never throws. Invalid input is ignored with a [ZebChat] warning in the browser console.
Calling the API before the widget loads
The install code loads async, so window.ZebChat may not exist yet when your own scripts run. Add this stub before the install code. It records calls in ZebChat.q, and the widget replays them in order as soon as it starts. Once loaded, the real API replaces the stub.
<script>
// Lets you call ZebChat.* before the widget has loaded: calls are queued and replayed in order.
window.ZebChat = window.ZebChat || (function () {
var api = { q: [] };
['open', 'close', 'toggle', 'show', 'hide', 'startChat', 'setUser', 'setTag', 'track', 'consent',
'setSound', 'mute']
.forEach(function (method) {
api[method] = function () {
api.q.push([method].concat(Array.prototype.slice.call(arguments)));
};
});
return api;
})();
</script>
<script src="https://cdn.zebchat.com/widget/v1/widget.js" data-site="SITE_KEY" async></script>Methods that need the visitor’s session (setUser, setTag, startChat, track) also wait for it, so it is fine to call them right away.
open, close and toggle
Control the chat panel from your own buttons and links. The launcher stays visible when the panel is closed.
ZebChat.open(); // open the chat panel
ZebChat.close(); // close it (the launcher stays)
ZebChat.toggle(); // open if closed, close if open
ZebChat.hide(); // remove the whole widget from this page, launcher included
ZebChat.show(); // bring it back
ZebChat.version; // "1"If the website’s launcher is set to open in a new window, open() still opens the panel on your page: browsers only allow pop-up windows from a real click on the launcher.
show and hide
hide() removes the entire widget (launcher and panel) from the current page, for example on a checkout page or while a full-screen video plays. show() brings it back. Neither is remembered across page loads.
show() can’t override the website’s visibility settings: where they hide the widget (offline, on some devices, pages or countries), it stays hidden.
startChat(message?)
Opens the chat. When you pass a message (up to 5,000 characters), it is sent as the visitor’s first message, after any pre-chat form and spam check are completed. When your team is unavailable, the message pre-fills the offline form instead.
// A "Talk to sales" button on your pricing page
document.querySelector('#talk-to-sales').addEventListener('click', () => {
ZebChat.startChat('Hi! I have a question about the Business plan.');
});setUser(user)
Tells ZebChat who the visitor is. It works in two modes.
Unverified: name, email and phone
Without an id, setUser({ name, email, phone }) adds contact details to the current, anonymous visitor. Anyone can call it from the browser, so agents see these details marked as unverified.
Verified: id and hash
For logged-in users, pass your own user id together with a hash that your server computes:
hash = hex( HMAC-SHA256( identity secret, id ) )
- In the agent app, open Websites, pick the website and create an identity secret in the Security tab. It is shown only once: store it with your server’s other secrets.
- On your server, compute the hash of the user’s id with that secret, using the exact same string you pass as
id. - Render a
setUsercall with theid, thehashand any details on every page while the user is logged in.
<script>
// Rendered by your server on every page while the user is logged in.
ZebChat.setUser({
id: '42', // your user id (string or number, up to 255 characters)
hash: 'b5c1…e9a0', // HMAC computed on your server (64 hex characters)
name: 'Maya Lopez', // optional, up to 120 characters
email: '[email protected]',// optional
phone: '+1 555 0100', // optional, up to 32 characters
});
</script>import { createHmac } from 'node:crypto';
// The website's identity secret, from the agent app (Websites → your website → Security).
const IDENTITY_SECRET = process.env.ZEBCHAT_IDENTITY_SECRET;
export function zebchatHash(userId) {
return createHmac('sha256', IDENTITY_SECRET).update(String(userId), 'utf8').digest('hex');
}
// Express example: pass the values to your template
app.get('/account', (req, res) => {
res.render('account', {
zebchatUser: { id: String(req.user.id), hash: zebchatHash(req.user.id), name: req.user.name },
});
});<?php
// The website's identity secret, from the agent app (Websites → your website → Security).
$secret = getenv('ZEBCHAT_IDENTITY_SECRET');
$id = (string) $user->id;
$hash = hash_hmac('sha256', $id, $secret);
// JSON_HEX_* flags keep the values safe inside a <script> tag.
$flags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;
?>
<script>
ZebChat.setUser({
id: <?= json_encode($id, $flags) ?>,
hash: <?= json_encode($hash, $flags) ?>,
name: <?= json_encode($user->name, $flags) ?>
});
</script>import hashlib
import hmac
import os
# The website's identity secret, from the agent app (Websites → your website → Security).
IDENTITY_SECRET = os.environ["ZEBCHAT_IDENTITY_SECRET"]
def zebchat_hash(user_id) -> str:
return hmac.new(
IDENTITY_SECRET.encode("utf-8"),
str(user_id).encode("utf-8"),
hashlib.sha256,
).hexdigest()What happens next:
- With a valid hash, the session switches to that user’s visitor on this website, created on first use. The same user on another device or browser gets the same visitor and sees their earlier conversations.
- The anonymous visitor from before the login is never merged in. When the user logs out, simply stop calling
setUser: the next page load is anonymous again, so a shared computer never shows the previous user’s chats. - A verified visitor’s name, email and phone can only be changed with a valid hash.
- Agents can see that the visitor is verified, and your user id.
Limits: id up to 255 characters, name up to 120, email up to 254, phone up to 32, and hash exactly 64 hex characters. Numbers are converted to strings and surrounding spaces are trimmed, so compute the hash over the trimmed string.
setTag(tags)
Adds one tag or a list of tags to the visitor, for example their plan or the campaign they came from. Agents see the tags on the visitor’s profile.
ZebChat.setTag('vip');
ZebChat.setTag(['trial', 'pricing']);- Tags are only ever added: your page can’t remove a tag. Agents can.
- Up to 10 tags per call, each 1–40 characters, without
<or>. Names match your existing tags without regard to case; new names are created. - A visitor can have up to 50 tags, and an organization up to 500.
track(name, properties?)
Records a custom event in the visitor’s journey, next to the pages they viewed. Use it for moments your team should know about, like a started checkout or a failed payment.
ZebChat.track('checkout_started', { plan: 'pro', items: 3 });
ZebChat.track('newsletter.signup');name: 1–64 characters from letters, digits,_,.,:and-.properties: an optional plain object, at most 2 KB as JSON.
Page views are tracked automatically, including route changes in single-page apps, so you don’t need track for those.
consent(granted)
For websites that must ask before storing anything on the visitor’s device (GDPR, ePrivacy), set the website’s consent mode to manual in the Privacy tab. Until your page calls consent(true), the widget:
- stores nothing in the browser, so it doesn’t recognise returning visitors;
- sends no page views or
trackevents (they are held in memory and sent once consent is given on the same page); - doesn’t start a visitor session or show the visitor to your team as online.
The chat itself always works: when the visitor opens it, they asked for it. Call consent on every page load with the visitor’s current choice. consent(false) deletes the stored visitor key and drops held events.
// In your cookie banner's callbacks (or your consent manager's events):
ZebChat.consent(true); // the visitor accepted
ZebChat.consent(false); // the visitor declined or withdrew consentWith consent mode off, consent calls are ignored and the widget remembers the visitor as usual.
setSound(on) and mute()
The widget plays a short, soft chime when your team replies while the chat is closed or the visitor is looking at another tab or at your page. Visitors can switch it off in the chat’s menu (⋯ → Sound). Use setSound to set it from your page, for example from your own preferences screen. The choice is remembered in the visitor’s browser, unless the website requires cookie consent and it hasn’t been given.
ZebChat.setSound(false); // no new-message sound on this page
ZebChat.setSound(true); // back on
ZebChat.mute(); // same as setSound(false)When Sound for new messages is off in the website’s Behavior settings, the widget never plays the sound and setSound is ignored.
Rate limits
The widget’s API calls are rate limited per IP address, per visitor and per organization, for example 10 setUser calls a minute per visitor and 60 events a minute per IP address. Normal use never comes close. See the REST API overview for the details.