diff --git a/lib/selectors/thread-selectors.js b/lib/selectors/thread-selectors.js
--- a/lib/selectors/thread-selectors.js
+++ b/lib/selectors/thread-selectors.js
@@ -18,7 +18,7 @@
 } from './calendar-filter-selectors.js';
 import { relativeMemberInfoSelectorForMembersOfThread } from './user-selectors.js';
 import genesis from '../facts/genesis.js';
-import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
 import {
   getAvatarForThread,
   getRandomDefaultEmojiAvatar,
@@ -258,15 +258,19 @@
     ).length,
 );
 
-const allUnreadCounts: (state: BaseAppState<>) => {
+const thinThreadsUnreadCountSelector: (state: BaseAppState<>) => {
   +[keyserverID: string]: number,
 } = createSelector(
   (state: BaseAppState<>) => state.threadStore.threadInfos,
   (threadInfos: RawThreadInfos): { +[keyserverID: string]: number } => {
+    const thinThreadInfosList = values(threadInfos).filter(
+      threadInfo => !threadInfo.thick,
+    );
+
     const keyserverToThreads = _groupBy(threadInfo =>
-      extractKeyserverIDFromIDOptional(threadInfo.id),
+      extractKeyserverIDFromID(threadInfo.id),
     )(
-      values(threadInfos).filter(threadInfo =>
+      thinThreadInfosList.filter(threadInfo =>
         threadInHomeChatList(threadInfo),
       ),
     );
@@ -540,7 +544,7 @@
   childThreadInfos,
   containedThreadInfos,
   unreadCount,
-  allUnreadCounts,
+  thinThreadsUnreadCountSelector,
   unreadBackgroundCount,
   unreadCountSelectorForCommunity,
   otherUsersButNoOtherAdmins,
diff --git a/native/push/push-handler.react.js b/native/push/push-handler.react.js
--- a/native/push/push-handler.react.js
+++ b/native/push/push-handler.react.js
@@ -27,7 +27,7 @@
 } from 'lib/selectors/keyserver-selectors.js';
 import {
   threadInfoSelector,
-  allUnreadCounts,
+  thinThreadsUnreadCountSelector,
   unreadThickThreadIDsSelector,
 } from 'lib/selectors/thread-selectors.js';
 import { isLoggedIn } from 'lib/selectors/user-selectors.js';
@@ -108,7 +108,7 @@
   // Navigation state
   +activeThread: ?string,
   // Redux state
-  +unreadCount: { +[keyserverID: string]: number },
+  +thinThreadsUnreadCount: { +[keyserverID: string]: number },
   +unreadThickThreadIDs: $ReadOnlyArray<string>,
   +connection: { +[keyserverID: string]: ?ConnectionInfo },
   +deviceTokens: {
@@ -326,7 +326,7 @@
   }
 
   async updateBadgeCount() {
-    const curUnreadCounts = this.props.unreadCount;
+    const curThinUnreadCounts = this.props.thinThreadsUnreadCount;
     const curConnections = this.props.connection;
 
     const currentUnreadThickThreads = this.props.unreadThickThreadIDs;
@@ -339,7 +339,7 @@
     }> = [];
     const notifsStorageQueries: Array<string> = [];
 
-    for (const keyserverID in curUnreadCounts) {
+    for (const keyserverID in curThinUnreadCounts) {
       if (curConnections[keyserverID]?.status !== 'connected') {
         notifsStorageQueries.push(keyserverID);
         continue;
@@ -347,7 +347,7 @@
 
       notifStorageUpdates.push({
         id: keyserverID,
-        unreadCount: curUnreadCounts[keyserverID],
+        unreadCount: curThinUnreadCounts[keyserverID],
       });
     }
 
@@ -401,7 +401,9 @@
   }
 
   async resetBadgeCount() {
-    const keyserversDataToRemove = Object.keys(this.props.unreadCount);
+    const keyserversDataToRemove = Object.keys(
+      this.props.thinThreadsUnreadCount,
+    );
     try {
       await commCoreModule.removeKeyserverDataFromNotifStorage(
         keyserversDataToRemove,
@@ -827,7 +829,7 @@
   React.memo<BaseProps>(function ConnectedPushHandler(props: BaseProps) {
     const navContext = React.useContext(NavContext);
     const activeThread = activeMessageListSelector(navContext);
-    const unreadCount = useSelector(allUnreadCounts);
+    const thinThreadsUnreadCount = useSelector(thinThreadsUnreadCountSelector);
     const unreadThickThreadIDs = useSelector(unreadThickThreadIDsSelector);
     const connection = useSelector(allConnectionInfosSelector);
     const deviceTokens = useSelector(deviceTokensSelector);
@@ -852,7 +854,7 @@
       <PushHandler
         {...props}
         activeThread={activeThread}
-        unreadCount={unreadCount}
+        thinThreadsUnreadCount={thinThreadsUnreadCount}
         unreadThickThreadIDs={unreadThickThreadIDs}
         connection={connection}
         deviceTokens={deviceTokens}
diff --git a/web/app.react.js b/web/app.react.js
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -69,7 +69,7 @@
 import UpdateModalHandler from './modals/update-modal.react.js';
 import SettingsSwitcher from './navigation-panels/settings-switcher.react.js';
 import Topbar from './navigation-panels/topbar.react.js';
-import useBadgeHandler from './push-notif/badge-handler.react.js';
+import BadgeHandler from './push-notif/badge-handler.react.js';
 import encryptedNotifUtilsAPI from './push-notif/encrypted-notif-utils-api.js';
 import { PushNotificationsHandler } from './push-notif/push-notifs-handler.js';
 import { updateNavInfoActionType } from './redux/action-types.js';
@@ -532,8 +532,6 @@
         !!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread,
     );
 
-    useBadgeHandler();
-
     const dispatch = useDispatch();
     const modalContext = useModalContext();
     const modals = React.useMemo(
@@ -561,6 +559,7 @@
           onClose={releaseLockOrAbortRequest}
           secondaryTunnelbrokerConnection={secondaryTunnelbrokerConnection}
         >
+          <BadgeHandler />
           <IdentitySearchProvider>
             <QRAuthProvider
               parseTunnelbrokerQRAuthMessage={parseTunnelbrokerQRAuthMessage}
diff --git a/web/push-notif/badge-handler.react.js b/web/push-notif/badge-handler.react.js
--- a/web/push-notif/badge-handler.react.js
+++ b/web/push-notif/badge-handler.react.js
@@ -3,11 +3,17 @@
 import * as React from 'react';
 
 import { allConnectionInfosSelector } from 'lib/selectors/keyserver-selectors.js';
-import { allUnreadCounts } from 'lib/selectors/thread-selectors.js';
+import {
+  thinThreadsUnreadCountSelector,
+  unreadThickThreadIDsSelector,
+} from 'lib/selectors/thread-selectors.js';
+import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
 
 import {
   updateNotifsUnreadCountStorage,
   queryNotifsUnreadCountStorage,
+  getNotifsUnreadThickThreadIDs,
+  updateNotifsUnreadThickThreadIDsStorage,
 } from './notif-crypto-utils.js';
 import electron from '../electron.js';
 import { useSelector } from '../redux/redux-utils.js';
@@ -15,7 +21,10 @@
 
 function useBadgeHandler() {
   const connection = useSelector(allConnectionInfosSelector);
-  const unreadCount = useSelector(allUnreadCounts);
+  const thinThreadsUnreadCount = useSelector(thinThreadsUnreadCountSelector);
+
+  const { socketState: tunnelbrokerSocketState } = useTunnelbroker();
+  const currentUnreadThickThreadIDs = useSelector(unreadThickThreadIDsSelector);
 
   React.useEffect(() => {
     void (async () => {
@@ -24,17 +33,32 @@
       } = {};
       const unreadCountQueries: Array<string> = [];
 
-      for (const keyserverID in unreadCount) {
+      for (const keyserverID in thinThreadsUnreadCount) {
         if (connection[keyserverID]?.status !== 'connected') {
           unreadCountQueries.push(keyserverID);
           continue;
         }
-        unreadCountUpdates[keyserverID] = unreadCount[keyserverID];
+        unreadCountUpdates[keyserverID] = thinThreadsUnreadCount[keyserverID];
       }
 
       let queriedUnreadCounts: { +[keyserverID: string]: ?number } = {};
-      [queriedUnreadCounts] = await Promise.all([
+      let unreadThickThreadIDs: $ReadOnlyArray<string> = [];
+
+      const handleUnreadThickThreadIDsInNotifsStoragePromise = (async () => {
+        if (tunnelbrokerSocketState.connected) {
+          await updateNotifsUnreadThickThreadIDsStorage({
+            type: 'set',
+            threadIDs: currentUnreadThickThreadIDs,
+            forceWrite: true,
+          });
+          return currentUnreadThickThreadIDs;
+        }
+        return getNotifsUnreadThickThreadIDs();
+      })();
+
+      [queriedUnreadCounts, unreadThickThreadIDs] = await Promise.all([
         queryNotifsUnreadCountStorage(unreadCountQueries),
+        handleUnreadThickThreadIDsInNotifsStoragePromise,
         updateNotifsUnreadCountStorage(unreadCountUpdates),
       ]);
 
@@ -45,16 +69,27 @@
 
       for (const keyserverID in queriedUnreadCounts) {
         if (!queriedUnreadCounts[keyserverID]) {
-          totalUnreadCount += unreadCount[keyserverID];
+          totalUnreadCount += thinThreadsUnreadCount[keyserverID];
           continue;
         }
         totalUnreadCount += queriedUnreadCounts[keyserverID];
       }
 
+      totalUnreadCount += unreadThickThreadIDs.length;
       document.title = getTitle(totalUnreadCount);
       electron?.setBadge(totalUnreadCount === 0 ? null : totalUnreadCount);
     })();
-  }, [unreadCount, connection]);
+  }, [
+    tunnelbrokerSocketState,
+    currentUnreadThickThreadIDs,
+    thinThreadsUnreadCount,
+    connection,
+  ]);
+}
+
+function BadgeHandler(): React.Node {
+  useBadgeHandler();
+  return null;
 }
 
-export default useBadgeHandler;
+export default BadgeHandler;
diff --git a/web/push-notif/notif-crypto-utils.js b/web/push-notif/notif-crypto-utils.js
--- a/web/push-notif/notif-crypto-utils.js
+++ b/web/push-notif/notif-crypto-utils.js
@@ -88,6 +88,12 @@
 const INDEXED_DB_NOTIFS_ACCOUNT_ENCRYPTION_KEY_DB_LABEL =
   'notificationAccountEncryptionKey';
 
+// thick threads unread count
+const INDEXED_DB_UNREAD_THICK_THREAD_IDS = 'unreadThickThreadIDs';
+const INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL =
+  'unreadThickThreadIDsEncryptionKey';
+const INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY = 'unreadThickThreadIDsSyncKey';
+
 async function deserializeEncryptedData<T>(
   encryptedData: EncryptedData,
   encryptionKey: CryptoKey,
@@ -456,16 +462,25 @@
       updatedOlmData = resultUpdatedOlmData;
       updatedNotifsAccount = resultUpdatedNotifsAccount;
 
-      await persistNotifsAccountWithOlmData({
-        accountWithPicklingKey: updatedNotifsAccount,
-        accountEncryptionKey,
-        encryptionKey,
-        olmData: updatedOlmData,
-        olmDataKey,
-        olmEncryptionKeyDBLabel,
-        synchronizationValue,
-        forceWrite: false,
-      });
+      const { threadID } = decryptedNotification;
+
+      await Promise.all([
+        persistNotifsAccountWithOlmData({
+          accountWithPicklingKey: updatedNotifsAccount,
+          accountEncryptionKey,
+          encryptionKey,
+          olmData: updatedOlmData,
+          olmDataKey,
+          olmEncryptionKeyDBLabel,
+          synchronizationValue,
+          forceWrite: false,
+        }),
+        updateNotifsUnreadThickThreadIDsStorage({
+          type: 'add',
+          threadIDs: [threadID],
+          forceWrite: false,
+        }),
+      ]);
 
       return { id, ...decryptedNotification };
     }
@@ -585,16 +600,26 @@
           encryptedPayload,
         );
 
-      await persistNotifsAccountWithOlmData({
-        accountWithPicklingKey: updatedNotifsAccount,
-        accountEncryptionKey,
-        encryptionKey,
-        olmData: updatedOlmData,
-        olmDataKey,
-        olmEncryptionKeyDBLabel,
-        synchronizationValue,
-        forceWrite: false,
-      });
+      const { threadID } = decryptedNotification;
+      invariant(typeof threadID === 'string', 'threadID should be string');
+
+      await Promise.all([
+        persistNotifsAccountWithOlmData({
+          accountWithPicklingKey: updatedNotifsAccount,
+          accountEncryptionKey,
+          encryptionKey,
+          olmData: updatedOlmData,
+          olmDataKey,
+          olmEncryptionKeyDBLabel,
+          synchronizationValue,
+          forceWrite: false,
+        }),
+        updateNotifsUnreadThickThreadIDsStorage({
+          type: 'add',
+          threadIDs: [threadID],
+          forceWrite: false,
+        }),
+      ]);
 
       return decryptedNotification;
     }
@@ -1253,6 +1278,118 @@
   return Object.fromEntries(queriedUnreadCounts);
 }
 
+async function updateNotifsUnreadThickThreadIDsStorage(input: {
+  +type: 'add' | 'remove' | 'set',
+  +threadIDs: $ReadOnlyArray<string>,
+  +forceWrite: boolean,
+}): Promise<void> {
+  const { type, threadIDs, forceWrite } = input;
+
+  const {
+    values: {
+      [INDEXED_DB_UNREAD_THICK_THREAD_IDS]: encryptedData,
+      [INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL]:
+        encryptionKey,
+    },
+    synchronizationValue,
+  } = await localforage.getMultipleItems<{
+    unreadThickThreadIDs: ?EncryptedData,
+    unreadThickThreadIDsEncryptionKey: ?(CryptoKey | SubtleCrypto$JsonWebKey),
+  }>(
+    [
+      INDEXED_DB_UNREAD_THICK_THREAD_IDS,
+      INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL,
+    ],
+    INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY,
+  );
+
+  let unreadThickThreadIDs;
+  let unreadThickThreadIDsEncryptionKey;
+
+  if (encryptedData && encryptionKey) {
+    unreadThickThreadIDsEncryptionKey = await validateCryptoKey(encryptionKey);
+    unreadThickThreadIDs = new Set(
+      await deserializeEncryptedData<Array<string>>(
+        encryptedData,
+        unreadThickThreadIDsEncryptionKey,
+      ),
+    );
+  } else {
+    unreadThickThreadIDs = new Set<string>();
+    unreadThickThreadIDsEncryptionKey = await generateCryptoKey({
+      extractable: isDesktopSafari,
+    });
+  }
+
+  if (type === 'add') {
+    for (const threadID of threadIDs) {
+      unreadThickThreadIDs.add(threadID);
+    }
+  } else if (type === 'remove') {
+    for (const threadID of threadIDs) {
+      unreadThickThreadIDs.delete(threadID);
+    }
+  } else {
+    unreadThickThreadIDs = new Set(threadIDs);
+  }
+
+  const [encryptionKeyPersistentForm, updatedEncryptedData] = await Promise.all(
+    [
+      getCryptoKeyPersistentForm(unreadThickThreadIDsEncryptionKey),
+      serializeUnencryptedData(
+        [...unreadThickThreadIDs],
+        unreadThickThreadIDsEncryptionKey,
+      ),
+    ],
+  );
+
+  const newSynchronizationValue = uuid.v4();
+  await localforage.setMultipleItems(
+    {
+      [INDEXED_DB_UNREAD_THICK_THREAD_IDS]: updatedEncryptedData,
+      [INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL]:
+        encryptionKeyPersistentForm,
+    },
+    INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY,
+    synchronizationValue,
+    newSynchronizationValue,
+    forceWrite,
+  );
+}
+
+async function getNotifsUnreadThickThreadIDs(): Promise<
+  $ReadOnlyArray<string>,
+> {
+  const {
+    values: {
+      [INDEXED_DB_UNREAD_THICK_THREAD_IDS]: encryptedData,
+      [INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL]:
+        encryptionKey,
+    },
+  } = await localforage.getMultipleItems<{
+    unreadThickThreadIDs: ?EncryptedData,
+    unreadThickThreadIDsEncryptionKey: ?(CryptoKey | SubtleCrypto$JsonWebKey),
+  }>(
+    [
+      INDEXED_DB_UNREAD_THICK_THREAD_IDS,
+      INDEXED_DB_UNREAD_THICK_THREAD_IDS_ENCRYPTION_KEY_DB_LABEL,
+    ],
+    INDEXED_DB_UNREAD_THICK_THREADS_SYNC_KEY,
+  );
+
+  if (!encryptionKey || !encryptedData) {
+    return [];
+  }
+
+  const unreadThickThreadIDsEncryptionKey =
+    await validateCryptoKey(encryptionKey);
+
+  return await deserializeEncryptedData<Array<string>>(
+    encryptedData,
+    unreadThickThreadIDsEncryptionKey,
+  );
+}
+
 export {
   decryptWebNotification,
   decryptDesktopNotification,
@@ -1268,4 +1405,6 @@
   persistEncryptionKey,
   retrieveEncryptionKey,
   persistNotifsAccountWithOlmData,
+  updateNotifsUnreadThickThreadIDsStorage,
+  getNotifsUnreadThickThreadIDs,
 };