As a developer embedding the HubSpot chat widget in a web app, I want to read the current unread conversation count when the page loads, so that I can show an unread indicator in my own UI without waiting for the count to change.
Problem
unreadConversationCountChanged only fires when the count changes. It does not deliver the current value on page load. There is no synchronous getter either — window.HubSpotConversations.widget.status() returns only { loaded }.
As a result, the two most common cases for an unread badge do not work:
- The visitor reloads the page (or navigates) while a reply is unread.
- An agent replies while the visitor has the app closed, and the visitor returns later.
In both cases our UI shows “no unread” until the agent happens to send another message.
Requested change
Either of the following would solve it:
- Add a getter, e.g.
window.HubSpotConversations.widget.unreadConversationCount(), or includeunreadCountinwidget.status(). - Or fire
unreadConversationCountChangedonce with the current value after the widget is initialized (hsConversationsOnReady).
The first is preferable because it is explicit and does not change existing event semantics.
Why this matters / what we had to do instead
We tried to reconstruct the unread state server-side and found there is no supported way:
- Conversations API v3 threads and messages expose no read/unread field, and there is no endpoint to mark a thread as read.
- Contact properties have no equivalent.
We ended up approximating it by storing “last time the visitor opened the chat” ourselves and comparing it against latestMessageSentTimestamp on threads fetched via GET /conversations/v3/conversations/threads?associatedContactId=....
That approximation is expensive and fragile:
- It requires
conversations.read+crm.objects.contacts.readscopes just to render a badge. latestMessageSentTimestampincludes chatflow bot replies, so it cannot distinguish a human agent reply from an automated one at the thread level.- The endpoint returns every channel in the inbox, so email threads have to be filtered out by
originalChannelIdor the badge fires for people who only ever emailed support. - Threads carry the pre-merge
associatedContactIdafter contacts are merged, while an email lookup returns the surviving contact ID, so merged contacts silently return nothing unlesshs_merged_object_idsis also queried. sort=latestMessageTimestampis ascending only (a-prefix silently returns zero results), so the newest threads are the ones truncated first and pagination is mandatory.
A single client-side getter would replace all of this.
Related discussions
- Create Conversations Chat API — delivered the Conversations API v3 in 2022, but it has no read/unread state, so it does not cover this use case.
- https://community.hubspot.com/t5/APIs-Integrations/Read-the-number-of-unread-chats-when-the-page-loads-from-the/td-p/344719
- https://community.hubspot.com/t5/APIs-Integrations/Unread-Conversations-in-HubSpot-Chat-Widget/m-p/756794