diff --git a/src/Cache.cpp b/src/Cache.cpp
index f4a014c1cbe31ea71aab85aa6908dabd510ece66..f3ad4fc54c1b3bb9f27cc6c2edbcc007d5e27e96 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -1543,18 +1543,12 @@ Cache::updateState(const std::string &room, const mtx::responses::StateEvents &s
     saveStateEvents(txn, statesdb, stateskeydb, membersdb, eventsDb, room, state.events);
 
     RoomInfo updatedInfo;
-    updatedInfo.name       = getRoomName(txn, statesdb, membersdb).toStdString();
-    updatedInfo.topic      = getRoomTopic(txn, statesdb).toStdString();
-    updatedInfo.avatar_url = getRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
-    updatedInfo.version    = getRoomVersion(txn, statesdb).toStdString();
-    updatedInfo.is_space   = getRoomIsSpace(txn, statesdb);
 
     {
         std::string_view data;
         if (roomsDb_.get(txn, room, data)) {
             try {
-                RoomInfo tmp     = json::parse(std::string_view(data.data(), data.size()));
-                updatedInfo.tags = tmp.tags;
+                RoomInfo updatedInfo = json::parse(std::string_view(data.data(), data.size()));
             } catch (const json::exception &e) {
                 nhlog::db()->warn("failed to parse room info: room_id ({}), {}: {}",
                                   room,
@@ -1564,6 +1558,12 @@ Cache::updateState(const std::string &room, const mtx::responses::StateEvents &s
         }
     }
 
+    updatedInfo.name       = getRoomName(txn, statesdb, membersdb).toStdString();
+    updatedInfo.topic      = getRoomTopic(txn, statesdb).toStdString();
+    updatedInfo.avatar_url = getRoomAvatarUrl(txn, statesdb, membersdb).toStdString();
+    updatedInfo.version    = getRoomVersion(txn, statesdb).toStdString();
+    updatedInfo.is_space   = getRoomIsSpace(txn, statesdb);
+
     roomsDb_.put(txn, room, json(updatedInfo).dump());
     updateSpaces(txn, {room}, {room});
     txn.commit();
@@ -1628,6 +1628,9 @@ Cache::saveState(const mtx::responses::Sync &res)
         updatedInfo.version    = getRoomVersion(txn, statesdb).toStdString();
         updatedInfo.is_space   = getRoomIsSpace(txn, statesdb);
 
+        updatedInfo.notification_count = room.second.unread_notifications.notification_count;
+        updatedInfo.highlight_count    = room.second.unread_notifications.highlight_count;
+
         if (updatedInfo.is_space) {
             bool space_updates = false;
             for (const auto &e : room.second.state.events)
@@ -4693,6 +4696,9 @@ to_json(json &j, const RoomInfo &info)
     j["join_rule"]    = info.join_rule;
     j["guest_access"] = info.guest_access;
 
+    j["notification_count"] = info.notification_count;
+    j["highlight_count"]    = info.highlight_count;
+
     if (info.member_count != 0)
         j["member_count"] = info.member_count;
 
@@ -4713,6 +4719,9 @@ from_json(const json &j, RoomInfo &info)
     info.join_rule    = j.at("join_rule");
     info.guest_access = j.at("guest_access");
 
+    info.notification_count = j.value("notification_count", 0);
+    info.highlight_count    = j.value("highlight_count", 0);
+
     if (j.count("member_count"))
         info.member_count = j.at("member_count");
 
diff --git a/src/CacheStructs.h b/src/CacheStructs.h
index a208fcf8de4973b272b174feb34f7cba7897a0f6..b391705828100bf3b97ff5bd7e5c92a14ad06342 100644
--- a/src/CacheStructs.h
+++ b/src/CacheStructs.h
@@ -88,6 +88,9 @@ struct RoomInfo
     bool guest_access                      = false;
     //! The list of tags associated with this room
     std::vector<std::string> tags;
+
+    uint16_t highlight_count    = 0;
+    uint16_t notification_count = 0;
 };
 
 void
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index e80cc659bbba9cf7471f40c7fdf0cd02b5304482..8d7b7919ff55e182e8c26b3563744be657f66bdf 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -349,11 +349,13 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
 {
     lastMessage_.timestamp = 0;
 
-    if (auto create =
-          cache::client()->getStateEvent<mtx::events::state::Create>(room_id_.toStdString()))
-        this->isSpace_ = create->content.type == mtx::events::state::room_type::space;
     this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString());
 
+    auto roomInfo            = cache::singleRoomInfo(room_id_.toStdString());
+    this->isSpace_           = roomInfo.is_space;
+    this->notification_count = roomInfo.notification_count;
+    this->highlight_count    = roomInfo.highlight_count;
+
     // this connection will simplify adding the plainRoomNameChanged() signal everywhere that it
     // needs to be
     connect(this, &TimelineModel::roomNameChanged, this, &TimelineModel::plainRoomNameChanged);