Repository navigation
Clear cached notifications on clearIdentity before the UI mounts (#225880) - #190
Merged
Merged
Conversation
…5880) clearAllNotifications() returned early while the notification container did not exist yet, so a clearIdentity() queued in the async snippet (it runs before injectNotificationUI) left the previous contact's unread-notifications cache in place, and the reload replayed it to the next anonymous visitor. Clear state and cache regardless of the container (only the DOM work needs it), and stamp cached notifications with the receiving gleapId so a reload only shows a contact its own notifications. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LucaB01
approved these changes
Oct 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
A site calls
Gleap.clearIdentity()inline on its login page, so the call is queued inwindow.GleapActions. After logout, the previous identified contact's message preview bubble is shown to the now-anonymous visitor on that browser. This is a privacy issue: messages addressed to a named contact are shown to whoever opens the page next.Root cause
clearSession()→GleapNotificationManager.clearAllNotifications(false), whose whole body, includingsaveToGleapCache('unread-notifications', []), sat behindif (!this.notificationContainer) return;.Gleap.js, "Check for unperformed Gleap actions").injectNotificationUI()only runs after session ready → config → DOM ready. A queuedclearIdentity()therefore always found no container, and thegleap-widget-unread-notificationscache survived.injectNotificationUI()→reloadNotificationsFromCache()then replayed every cached notification younger than 1 h. That cache key is shared by every contact on the browser.Fix
clearAllNotifications()now always resets the in-memory list and the persisted cache. Only the DOM teardown and the cross-tab broadcast still need the container. The tab channel only starts ininjectNotificationUI(), so the broadcast was a no-op before mount anyway.showNotification()stampscachedForGleapIdon each notification, andreloadNotificationsFromCache()keeps only entries stamped with the current session'sgleapId. A reload can no longer show one contact another contact's notifications, even when the identity changes withoutclearIdentity().Rollout side effect: bubbles cached by older builds are unstamped. They are at most 1 h old and are dropped once on the first page load after the update. Unread state in the messenger is unaffected.
Verification
Unit tests (
src/GleapNotificationManager.test.js, new block "notification cache vs identity (#225880)"):clearAllNotifications(false) clears the persisted cache before the UI is mounted,showNotification stamps the receiving gleapId…,reloadNotificationsFromCache drops notifications cached for another (or no) gleapId(3 failed / 24 passed).npx jestpasses 33 suites / 581 tests. Two existing reload fixtures were updated to carry the stamp.Browser reproduction. A local page seeds the unread cache with a previous contact's notification (written unstamped, as a pre-fix build writes it), then loads the standard async snippet with
Gleap.initialize(<test project>)and a queuedGleap.clearIdentity():gleap-widget-unread-notificationsafter loadsdk.gleap.io/latest(19.3.5, before)PREVIOUS USER: Hi Jane, …shown to the new anonymous session[]Regression check (this branch): the same contact gets a notification via
Gleap.showNotification, which caches it stamped with its gleapId. After a reload the bubble is shown again.Gleap ticket #225880.
🤖 Generated with Claude Code