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.

JM
James Morton
Written By James MortonLast updated 1 day ago

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

view

string, optional

The view that opened, for example "new-post" or "help"

postId, articleId, entryId

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

id

string

Post ID

title

string

Post title

board

{ id, name, slug }

Board the post was created in

statusId

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

postId

string

Post ID

voted

boolean

true if voted, false if the vote was removed

voteCount

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

postId

string

Post the comment belongs to

commentId

string

New comment ID

parentId

string or null

Parent comment ID for replies, null for top-level comments

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

success

boolean

Whether identification succeeded

user

{ id, name, email } or null

User details, or null for anonymous

anonymous

boolean

true for an anonymous session

error

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

count

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.

Was this helpful?

Your feedback shapes what we write next.