You can register a callback with Stack Exchange Chat, which gets called prior to the change happening in the DOM (i.e. if you want to find a new message in the DOM, you need to use a `setTimeout()` to act after the DOM change). Callbacks can be registered with `CHAT.addEventHandlerHook(callback)`, which takes a [non-`async`][1] function as its single argument. The callback function is passed arguments that look like: <!-- language: lang-json --> arguments: { 0: { event_type: 1, time_stamp: 1552493100, content: 'Test message with a tag <a href="//stackoverflow.com/questions/tagged/some-tag"><span class="ob-post-tag" style="background-color: #E0EAF1; color: #3E6D8E; border-color: #3E6D8E; border-style: solid;">some-tag</span></a>.', id: 92913194, user_id: 3773011, user_name: "Makyen", room_id: 68414, room_name: "SOCVR Testing Facility", message_id: 45625173 }, 1: false, 2: 92913190 } The first argument is a chat "event" Object. The type of event is indicated by the numeric value of `event_type`. There are 34 types which are possible for `event_type`. <!-- language: lang-js --> const chatEventTypes = { 1: 'MessagePosted', 2: 'MessageEdited', 3: 'UserEntered', 4: 'UserLeft', 5: 'RoomNameChanged', 6: 'MessageStarred', 7: 'DebugMessage', 8: 'UserMentioned', 9: 'MessageFlagged', 10: 'MessageDeleted', 11: 'FileAdded', 12: 'ModeratorFlag', 13: 'UserSettingsChanged', 14: 'GlobalNotification', 15: 'AccessLevelChanged', 16: 'UserNotification', 17: 'Invitation', 18: 'MessageReply', 19: 'MessageMovedOut', 20: 'MessageMovedIn', 21: 'TimeBreak', 22: 'FeedTicker', 29: 'UserSuspended', 30: 'UserMerged', 34: 'UserNameOrAvatarChanged', }; The callback will receive events for all the rooms the user is in, so you will want to filter them by matching the `room_id` to the current room. The list of event types was copied from the SE's minimized chat JavaScript. [1]: https://chat.stackoverflow.com/transcript/message/54614070