Listen to widget events
Subscribe to widget events (ready, open, close, post:created, vote, comment:created, identify, unread) to track analytics, show confirmations, or update your own UI.
The widget SDK fires events when users submit feedback, vote, comment, or receive chat messages, so your app can track analytics, show confirmations, or update its own UI. This article lists every event and its payload.
Subscribe to events
Use on to listen for an event. It returns an unsubscribe function:
const unsubscribe = Quackback("on", "post:created", (payload) => {
console.log("New post:", payload.title);
analytics.track("feedback_submitted", { postId: payload.id });
});
// Later, stop listening:
unsubscribe();You can also remove listeners with off:
function handleVote(payload) {
console.log(payload.voted ? "Upvoted" : "Removed vote", payload.postId);
}
Quackback("on", "vote", handleVote);
// Remove one handler
Quackback("off", "vote", handleVote);
// Remove every handler for an event
Quackback("off", "vote");With the npm package, use Quackback.on(...) and Quackback.off(...). In React, use the useQuackbackEvent hook.
Available events
ready
Fires when the widget has loaded and can receive commands. Payload: {}
Quackback("on", "ready", () => {
console.log("Widget is ready");
});open
Fires when the panel opens, from the launcher or from open.
Quackback("on", "open", () => {
document.body.classList.add("widget-open");
});Field | Type | Description |
|---|---|---|
| string, optional | The view that opened, for example |
| string, optional | Set when the panel opened to a specific item |
close
Fires when the panel closes. Payload: {}
Quackback("on", "close", () => {
document.body.classList.remove("widget-open");
});post:created
Fires after a user submits a new post through the widget.
Quackback("on", "post:created", (payload) => {
showToast(`Thanks for your feedback: "${payload.title}"`);
});Field | Type | Description |
|---|---|---|
| string | Post ID |
| string | Post title |
|
| Board the post was created in |
| string or null | Initial status ID |
vote
Fires when a user adds or removes a vote.
Quackback("on", "vote", (payload) => {
analytics.track("vote_toggled", { postId: payload.postId, voted: payload.voted });
});Field | Type | Description |
|---|---|---|
| string | Post ID |
| boolean |
|
| number | Updated vote count |
comment:created
Fires when a user posts a comment or reply.
Quackback("on", "comment:created", (payload) => {
console.log("Comment added to post", payload.postId);
});Field | Type | Description |
|---|---|---|
| string | Post the comment belongs to |
| string | New comment ID |
| string or null | Parent comment ID for replies, |
identify
Fires after an identify call completes, whether it succeeded or failed.
Quackback("on", "identify", (payload) => {
if (payload.success) {
console.log("Identified:", payload.user?.name ?? "anonymous");
} else {
console.error("Identify failed:", payload.error);
}
});Field | Type | Description |
|---|---|---|
| boolean | Whether identification succeeded |
|
| User details, or |
| boolean |
|
| string, optional | Error code on failure. See Troubleshoot widget identify. |
unread
Fires when the number of unread Messenger messages changes. It carries the same count that drives the launcher badge.
Quackback("on", "unread", (payload) => {
updateHeaderBadge(payload.count);
});Field | Type | Description |
|---|---|---|
| number | Total unread messages across the visitor's conversations |
Single-page apps
In React or another framework, subscribe in an effect and clean up on unmount:
import { useEffect } from "react";
export function WidgetEvents() {
useEffect(() => {
const unsubs = [
Quackback("on", "post:created", (p) => {
analytics.track("feedback_submitted", { postId: p.id });
}),
Quackback("on", "vote", (p) => {
analytics.track("vote", { postId: p.postId, voted: p.voted });
}),
];
return () => unsubs.forEach((fn) => fn());
}, []);
return null;
}Tip: Handlers run synchronously. For async work such as API calls, start a promise inside the handler. Errors thrown inside handlers are caught so they never break the widget.
Related articles
Was this helpful?
Your feedback shapes what we write next.
