diff --git a/src/call.cpp b/src/call.cpp
index 34aa646ccc86bff05b9667500c08a62dba2c4c4f..5ea31729d71bf3eba2956cc198ab7ec6b2f66e12 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -63,6 +63,7 @@
 #include "media/audio.h"
 #include "media/video.h"
 #include "media/text.h"
+#include "media/textrecording.h"
 #include "media/file.h"
 
 #include "securityevaluationmodel.h"
@@ -2219,6 +2220,12 @@ QVariant Call::roleData(int role) const
          return QVariant::fromValue(account()->securityEvaluationModel()->securityLevel());
       case static_cast<int>(Call::Role::SecurityLevelIcon): //TODO remove
          return GlobalInstances::pixmapManipulator().securityLevelIcon(account()->securityEvaluationModel()->securityLevel());
+      case static_cast<int>(Ring::Role::UnreadTextMessageCount):
+         if (peerContactMethod() && peerContactMethod()->textRecording())
+            return peerContactMethod()->textRecording()->unreadInstantTextMessagingModel()->rowCount();
+         else
+            return 0;
+         break;
       default:
          break;
    };
diff --git a/src/contactmethod.cpp b/src/contactmethod.cpp
index 6833172165c2115746e9369a4fa4d8f11cd0f14d..49760d19342b9de28741876f2394e788d330cc1c 100644
--- a/src/contactmethod.cpp
+++ b/src/contactmethod.cpp
@@ -542,6 +542,12 @@ QVariant ContactMethod::roleData(int role) const
          break;
       case static_cast<int>(Call::Role::LifeCycleState):
          return QVariant::fromValue(Call::LifeCycleState::FINISHED);
+      case static_cast<int>(Ring::Role::UnreadTextMessageCount):
+         if (auto rec = textRecording())
+            cat = rec->unreadInstantTextMessagingModel()->rowCount();
+         else
+            cat = 0;
+         break;
    }
    return cat;
 }
diff --git a/src/itemdataroles.h b/src/itemdataroles.h
index ff27f181bdbc8e5a2761440d659af37bff901d16..257b58f1bd5ad3ca5b0dbffa5456cdce46934f7c 100644
--- a/src/itemdataroles.h
+++ b/src/itemdataroles.h
@@ -46,6 +46,7 @@ enum class Role
     FormattedState     ,
     Length             ,
     DropState          ,
+    UnreadTextMessageCount,
     UserRole           = Qt::UserRole + 100  // this should always be the last role in the list
 };
 
diff --git a/src/person.cpp b/src/person.cpp
index 2c8e04b4c8c64af0112ea0dbb4e4bdcc83ef2d04..0ff6dbffda56b933e0da7c87b627cb8420df534b 100644
--- a/src/person.cpp
+++ b/src/person.cpp
@@ -601,6 +601,16 @@ QVariant Person::roleData(int role) const
          return QVariant(QDateTime::fromTime_t( lastUsedTime()));
       case static_cast<int>(Person::Role::Filter):
          return filterString();
+      case static_cast<int>(Ring::Role::UnreadTextMessageCount):
+         {
+            int unread = 0;
+            for (int i = 0; i < d_ptr->m_Numbers.size(); ++i) {
+               if (auto rec = d_ptr->m_Numbers.at(i)->textRecording())
+                  unread += rec->unreadInstantTextMessagingModel()->rowCount();
+            }
+            return unread;
+         }
+         break;
       default:
          break;
    }