Widget events
Subscribe with Pong('on', name, handler). Handlers run in your page, so there is no postMessage parsing and no origin checks to write.
function onMessage(m) {
if (m.type === 'agent') Pong('openChat', true);
}
Pong('on', 'message', onMessage);
Pong('off', 'message', onMessage); // one handler
Pong('off', 'message'); // all handlers of this event
Event list
| Event | Payload | When |
|---|---|---|
ready | { clientId, verified, unread, lastAgentMessageAt, banned } | The widget connected and knows the visitor. |
message | { id, type, channel, text, attachments, agentId, createdAt } | A message was sent or received. type is visitor, agent, ai, system or bot (contact form bot). |
unread | { count, lastAgentMessageAt } | The number of agent messages the visitor has not seen changed. |
open / close | { reason } | The chat window opened or closed; reason is user, api or trigger. |
trigger | { id, action } | A trigger fired on this page. action is message, open, hide or group; the server has already done its part (the message, the group). |
identity | { clientId, verified, merged } | After identify. merged is true when a signed identity joined this browser to an existing client. |
banned | { banned } | An agent blocked or unblocked the visitor. |
call | { state, video } | An agent call: state is incoming (ringing), active (answered) or ended (hung up, declined or cancelled); video is false for a voice call. |
contact | {} | The visitor filled in the contact form. The details go to the client card, not to the page. |
restart | {} | After Pong('restart'). |
localStorage bookkeeping.Count triggers in your analytics
Pong('on', 'trigger', (t) => {
window.plausible && plausible('Chat trigger', { props: { id: t.id, action: t.action } });
});
State classes on <html>
The widget keeps classes on your page's <html> element in step with its state, so your own CSS can react without any JavaScript. A class is added or removed only when that state changes; nothing else on your page is touched.
| Class | Present while |
|---|---|
pong-chat-loaded | The widget connected and knows the visitor (after ready). |
pong-chat-opened | The chat window is open. |
pong-chat-minimized | The widget is shown as its launcher button, the chat window closed. |
pong-chat-hidden | The widget is hidden (Pong('hide'), startHidden) or removed with Pong('kill'). |
pong-chat-new-message | The visitor has agent messages they have not seen. |
pong-chat-banned | An agent blocked the visitor. |
pong-chat-incoming-call | An agent is calling and the visitor has not answered yet. |
pong-chat-video-call | A video call is in progress. |
pong-chat-audio-call | A voice call is in progress. |
pong-chat-screen-sharing | The visitor is sharing their screen in a call. |
pong-chat-mobile | The widget uses its phone layout (full-screen chat). |
/* Hide your own support button for blocked visitors */
.pong-chat-banned #support { display: none; }
/* A dot on your menu while there is an unread reply */
.pong-chat-new-message #support::after { content: '●'; color: #e5484d; }
/* Hide a background video while the visitor is on a call */
.pong-chat-video-call .hero video,
.pong-chat-audio-call .hero video { visibility: hidden; }
Recipes
Badge on your own support link
Pong('on', 'unread', (u) => {
document.querySelector('#support').classList.toggle('has-unread', u.count > 0);
});
Open the chat when an agent writes
Pong('on', 'message', (m) => {
if (m.type === 'agent') { Pong('show'); Pong('expandWidget'); }
});
Events in Google Tag Manager
When the page has a dataLayer (GTM, or gtag.js), the widget pushes its events there as { event: 'pong_…' }. In GTM make a trigger of type Custom Event with that name and send it to GA4, Google Ads or any other tag. No message texts or contact details are pushed.
| Event | Extra keys | When |
|---|---|---|
pong_chat_opened / pong_chat_closed | pong_reason: user, api or trigger | The chat window opened or closed. |
pong_chat_started | The visitor sent their first message (once per browser): the usual "lead" conversion. | |
pong_message_sent | Every visitor message. | |
pong_reply_received | pong_from: agent or ai | The first answer from an agent or the AI after the visitor wrote (trigger greetings don't count). |
pong_contact_sent | The visitor filled in the contact form. | |
pong_trigger | pong_trigger: the trigger's name; pong_action | A trigger fired. |
pong_call_answered | pong_video | The visitor answered an agent's call. |
Use the extra keys in GTM as Data Layer Variables. The pushes are on by default; turn them off or set a renamed data layer in Settings → Chat widget → Analytics. A page can override that with PongSetup = { dataLayer: 'myLayer' }, or dataLayer: false for none.
Send chat events to your analytics
Without GTM, or for any other tool, pass a function:
PongSetup = {
onAnalyticEvent(name) {
// 'Chat opened', 'Chat closed', 'Message sent', 'Chat initiated by agent'
window.gtag && gtag('event', name, { event_category: 'chat' });
},
};