diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0fed8c2bda41f087ed55b6505a877b2dd7fc17f..414b948e2c41b314d74173fb2ee1c22c0f28c001 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@ This file contains the changes applied to the sources of converse<br>
 The current build version of converse is: `v7.0.3dev`<br>
 If the converse sources have to be updated, apply these changes again, or fix them using plugins
 
+### 2021-06-25
+* Fix memory leaks caused by events not properly disconnected.
+
 ### 2021-05-19
 * Avoid clearing the textarea when pressing the ESC key and not editing any messages
 
diff --git a/src/conversejs/converse.js b/src/conversejs/converse.js
index e86a471bf1938ebfae7fbd0c0e79f54dade00400..6be0ec3447865efd93a53e6ebbae8a70a2324a20 100644
--- a/src/conversejs/converse.js
+++ b/src/conversejs/converse.js
@@ -91104,13 +91104,29 @@ function dropdown_taggedTemplateLiteral(strings, raw) { if (!raw) { raw = string
 
 const dropdown_u = converse.env.utils;
 class dropdown_BaseDropdown extends element_CustomElement {
+
+  connectedCallback() {
+    super.connectedCallback();
+    this.registerEvents();
+  }
+
+  registerEvents() {
+    this.clickOutside = this._clickOutside.bind(this);
+    document.addEventListener('click', this.clickOutside);
+  }
+
   firstUpdated() {
     this.menu = this.querySelector('.dropdown-menu');
     this.dropdown = this.firstElementChild;
     this.button = this.dropdown.querySelector('button');
     this.dropdown.addEventListener('click', ev => this.toggleMenu(ev));
     this.dropdown.addEventListener('keyup', ev => this.handleKeyUp(ev));
-    document.addEventListener('click', ev => !this.contains(ev.composedPath()[0]) && this.hideMenu(ev));
+  }
+
+  _clickOutside(ev) {
+    if (!this.contains(ev.composedPath()[0])) {
+      this.hideMenu(ev);
+    }
   }
 
   hideMenu() {
@@ -91144,6 +91160,10 @@ class dropdown_BaseDropdown extends element_CustomElement {
     }
   }
 
+  disconnectedCallback() {
+    document.removeEventListener('click', this.clickOutside);
+    super.disconnectedCallback();
+  }
 }
 class dropdown_DropdownList extends dropdown_BaseDropdown {
   static get properties() {
@@ -94071,7 +94091,6 @@ class emoji_picker_EmojiPicker extends element_CustomElement {
     this.debouncedFilter = lodash_es_debounce(input => this.model.set({
       'query': input.value
     }), 250);
-    this.registerEvents();
   }
 
   get search_results() {
@@ -110777,4 +110796,4 @@ converse.initialize = function (settings, callback) {
 
 /***/ })
 /******/ ]);
-//# sourceMappingURL=converse.js.map
\ No newline at end of file
+//# sourceMappingURL=converse.js.map
diff --git a/src/plugins/sib-history-improved.js b/src/plugins/sib-history-improved.js
index a9c93c21659b36a54380ff9cf90972a366e00583..2abd12d0446578052577d2be17cfcf544d1c3460 100644
--- a/src/plugins/sib-history-improved.js
+++ b/src/plugins/sib-history-improved.js
@@ -76,17 +76,21 @@ converse.plugins.add('sib-history-improved', {
       if (oldest_message) {
         const by_jid = is_groupchat ? data.chatbox.get('jid') : _converse.bare_jid;
         const stanza_id = oldest_message && oldest_message['stanza_id '.concat(by_jid)];
+        const time = oldest_message['time'];
 
         if (stanza_id) {
           log.info(`Loading messages before stanza: ${stanza_id}`);
           await data.chatbox.fetchArchivedMessages({
             'before': stanza_id,
           });
-        } else {
-          log.info(`Loading messages before time: ${oldest_message['time']}`);
+        } else if (''.concat(time).length) {
+          log.info(`Loading messages before time: ${time}`);
           await data.chatbox.fetchArchivedMessages({
-            'end': oldest_message['time'],
+            'end': time,
           });
+        } else {
+          log.info(`Couldn't load more messages before the oldest (stanza_id: "${stanza_id}", time: "${time}")`);
+          console.warn(oldest_message);
         }
       }
     });
diff --git a/src/plugins/sib-reactions.js b/src/plugins/sib-reactions.js
index 61d54da65c249b7dc0cf1f206782e8dbfb903a23..3a18a64bf9aad98ce0891e70a7da0ddd1980eec0 100644
--- a/src/plugins/sib-reactions.js
+++ b/src/plugins/sib-reactions.js
@@ -61,6 +61,12 @@ converse.plugins.add('sib-reactions', {
 
     Strophe.addNamespace('REACTIONS', 'urn:xmpp:reactions:0');
 
+    /**
+     * Document callback (when clicking outside of the picker)
+     * TODO: This is a quick and dirty implementation, needs update
+     */
+    let documentCallback;
+
     /**
      * Send a reaction stanza for this user with the given emojis.
      * @param message
@@ -225,6 +231,11 @@ converse.plugins.add('sib-reactions', {
         const picker = new Picker();
         picker.classList.add('light', 'emoji-reaction-select');
 
+        function closePicker() {
+          picker.remove();
+          document.removeEventListener('click', documentCallback);
+        }
+
         picker.addEventListener('emoji-click', e => {
           const emoji = e.detail.unicode;
           const emojis = getUserReactionEmojis(this.model);
@@ -232,12 +243,12 @@ converse.plugins.add('sib-reactions', {
           // TODO: If it has the reaction from this user already, remove it? (config)
           if (emojis?.includes(emoji)) {
             log.warn(`The emoji "${emoji}" is already in the list of this user reactions`);
-            picker.remove();
+            closePicker();
             return;
           }
 
           emojis.push(emoji);
-          picker.remove();
+          closePicker();
 
           sendReactionStanza(this.model, emojis);
         });
@@ -245,18 +256,18 @@ converse.plugins.add('sib-reactions', {
         // Close the picker if the ESC key is pressed
         picker.addEventListener('keydown', ev => {
           if (ev.key === 'Escape') {
-            picker.remove();
+            closePicker();
           }
         });
 
         // Close the picker if clicked outside of it
-        // TODO: Remove this listener when the picker is removed from the dom
         setTimeout(() => {
-          document.addEventListener('click', ev => {
+          documentCallback = ev => {
             if (!picker.shadowRoot.contains(ev.composedPath()[0])) {
-              picker.remove();
+              closePicker();
             }
-          });
+          };
+          document.addEventListener('click', documentCallback);
         });
 
         // Append picker to the document