Skip to content

feat(Support): Identify logged-in users in HubSpot chat - #8814

Draft
Holmus wants to merge 1 commit into
mainfrom
feat/hubspot-chat-identify-user
Draft

Holmus wants to merge 1 commit into
mainfrom
feat/hubspot-chat-identify-user

Conversation

@Holmus

@Holmus Holmus commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature. (Not required: internal support widget.)
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Contributes to #8813

HubSpot chat (#8710) shows every logged-in user as "Unknown Visitor", so tickets created from chat have no contact or company. Pylon chat got the user's email and a signed hash. The HubSpot path sent nothing. Now the dashboard tells HubSpot who is chatting before the widget loads.

  • Before widget.load(), the dashboard fetches a token from auth/users/me/hubspot-chat-token/ (feat(Support): Add an endpoint that issues HubSpot chat visitor tokens #8813). It then sets identificationEmail and identificationToken in hsConversationsSettings, which is where HubSpot reads them.
  • If the request fails (endpoint not deployed yet, HubSpot down, throttled), the widget still loads, anonymously as today.
  • A previous user's identity is always cleared first, so logging in as someone else in the same tab never reuses it.
  • The token is only fetched when the widget is about to load, not on every org switch. Calls made during the fetch share one request and one load(). The org is checked again after the fetch.
  • "Let us know" / "contact us" links that open the chat before it has loaded also go through this path, so they're identified too.

Safe to merge before #8813 is deployed: until then, chat just stays anonymous. Merging #8813 first avoids a console error on each page load for users with HubSpot chat.

Not in this PR: clearing HubSpot's chat cookies on logout. HubSpot's clear({ resetWidget: true }) re-creates the widget, which conflicts with loadImmediately: false, so it needs testing on its own.

Review effort: 2/5

How did you test this code?

  • Unit tests in common/__tests__/loadChat.test.ts: the identity is set before load(), anonymous fallback when the request fails, a previous identity is dropped, overlapping calls make one request and one load, no request when already loaded, no load when the org changes during the fetch. Existing tests updated for the async load.
  • Locally: CI=true lint on changed lines, the full unit test suite and the production build pass.
  • Manual check against staging after feat(Support): Add an endpoint that issues HubSpot chat visitor tokens #8813 is deployed there: with hubspot_chat on, open chat and send a message, then check that the conversation and ticket in HubSpot show the user's contact, not "Unknown Visitor".

🤖 Generated with Claude Code

HubSpot chat showed every dashboard user as "Unknown Visitor", so tickets
created from chat had no contact or company. Before loading the widget, the
dashboard now fetches a visitor identification token from the API and sets
identificationEmail and identificationToken in hsConversationsSettings.

If the token request fails, the widget still loads, anonymously as before.
A previous user's identity is always cleared first. Calls made during the
fetch share one request and one load(), and "open chat" loads the widget
identified too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
flagsmith-frontend-preview Ready Ready Preview Oct 20, 2026 4:13pm UTC
flagsmith-frontend-staging Ready Ready Preview Oct 20, 2026 4:13pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
docs Ignored Ignored Preview Oct 20, 2026 4:13pm UTC

Request Review

@Holmus Holmus added feature New feature or request front-end Issue related to the React Front End Dashboard labels Oct 20, 2026
@coderabbitai

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@talissoncosta talissoncosta left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this closes the "Unknown Visitor" gap with a sane fallback. A few questions inline, mostly about reusing the token and the logout path. None blocking for a draft.

question on the description: "logging in as someone else in the same tab never reuses it" is true for the identity, but HubSpot's messagesUtk cookie and old thread stay until clear-on-logout lands. Worth softening that line, or did you test it with two accounts?

const user = AccountStore.getUser() as AccountModel | undefined
if (!user?.email) return
try {
const { token } = await data.get(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Could this go through RTK Query? We'd get reuse for free: the cache keeps the token, overlapping calls share one request, and logout already clears it via resetApiState().

getHubspotChatToken: builder.query<Res['hubspotChatToken'], void>({
  keepUnusedDataFor: 11 * 60 * 60, // HubSpot tokens last 12h
  query: () => ({ url: 'auth/users/me/hubspot-chat-token/' }),
}),

If #8813 also returns the email the token was minted for, we wouldn't need AccountStore here at all:

const { data } = await getStore().dispatch(
  hubspotChatTokenService.endpoints.getHubspotChatToken.initiate(undefined, { subscribe: false }),
)
if (data) {
  window.hsConversationsSettings = { ...settings, identificationEmail: data.email, identificationToken: data.token }
}

identifyHubSpotVisitor()
.then(() => {
// Re-checked: the org may have changed while the token was fetched.
if (canLoadHubSpot()) {

@talissoncosta talissoncosta Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: If the user logs out while the token request is in flight, this still loads the widget with their identity. I reproduced it with a unit test (identifyChatUser(), then hideChat(), then resolve the token: load() is called with the old token).

A flag set on logout fixes it:

let loggedOut = false

// in loadHubSpotWidget, after isLoadingHubSpot = true
loggedOut = false

// after the fetch
if (!loggedOut && canLoadHubSpot()) {

// in hideChat
loggedOut = true

With it, both the logout case and a logout plus login during the fetch stop loading the old identity, and the existing tests still pass.

beforeEach(() => {
jest.resetAllMocks()
mockUtils.isOrgOnFreePlan.mockReturnValue(false)
mockAccountStore.getUser.mockReturnValue({ email: USER_EMAIL } as any)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: as any hides every other field. With the email coming from the token response, this could mock the token endpoint with a typed Res['hubspotChatToken'] instead of a cast user.

This branch was successfully deployed

2 active deployments
Preview – flagsmith-frontend-preview — c807e566 Deployed Oct 20, 2026 by vercel[bot]
Preview – flagsmith-frontend-staging — c807e566 Deployed Oct 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request front-end Issue related to the React Front End Dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants