diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp
index 7f5da0d629459f0649b82627e38aa70877d2bc79..79601e12008b437ad65bfec80fc01c2a2ba089ee 100644
--- a/src/authority/databasehelper.cpp
+++ b/src/authority/databasehelper.cpp
@@ -342,6 +342,11 @@ addContact(Database& db, const std::string& accountUri, const std::string& conta
     }
 }
 
+int
+countUnreadFromInteractions(Database& db, const std::string& conversationId)
+{
+    return db.count("status", "interactions", "status='UNREAD' AND conversation_id='" + conversationId + "'");
+}
 
 } // namespace database
 
diff --git a/src/authority/databasehelper.h b/src/authority/databasehelper.h
index 34d61250077ac9a4ec4d92246b6ef1cd5d608ac0..b61d616713a03b69f20398b7725a687c80a7388d 100644
--- a/src/authority/databasehelper.h
+++ b/src/authority/databasehelper.h
@@ -210,6 +210,10 @@ void removeAccount(Database& db, const std::string& accountUri);
  */
 void addContact(Database& db, const std::string& accountUri, const std::string& contactUri);
 
+/**
+ * count number of 'UNREAD' from 'interactions' table.
+ */
+int countUnreadFromInteractions(Database& db, const std::string& conversationId);
 
 } // namespace database
 
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 5db7a81892a06ed9cb01b55e5deb96c4fe5b9815..f9614ff07ed55b9bf43eae918aad08fa160bd595 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -125,6 +125,11 @@ public:
      */
     void placeCall(const std::string& uid, bool isAudioOnly = false);
 
+    /**
+     * get number of unread messages
+     */
+    int getNumberOfUnreadMessagesFor(const std::string& uid);
+
     const ConversationModel& linked;
     Database& db;
     const CallbacksHandler& callbacksHandler;
@@ -276,7 +281,11 @@ ConversationModel::filteredConversation(const unsigned int row) const
     const auto& conversations = allFilteredConversations();
     if (row >= conversations.size())
         return conversation::Info();
-    return conversations.at(row);
+
+    auto conversationInfo = conversations.at(row);
+    conversationInfo.unreadMessages = pimpl_->getNumberOfUnreadMessagesFor(conversationInfo.uid);
+
+    return conversationInfo;
 }
 
 void
@@ -896,6 +905,7 @@ ConversationModelPimpl::addConversationWith(const std::string& convId,
         }
     }
 
+    conversation.unreadMessages = getNumberOfUnreadMessagesFor(convId);
     conversations.emplace_front(conversation);
     dirtyConversations = true;
 }
@@ -1163,6 +1173,12 @@ ConversationModelPimpl::slotConferenceRemoved(const std::string& confId)
     }
 }
 
+int
+ConversationModelPimpl::getNumberOfUnreadMessagesFor(const std::string& uid)
+{
+    database::countUnreadFromInteractions(db, uid);
+}
+
 } // namespace lrc
 
 #include "api/moc_conversationmodel.cpp"
diff --git a/src/database.cpp b/src/database.cpp
index 46fb2c0ddd53fdb42762e819b097c7a32840d738..78a2973e86d5863f1fe9dc083fcf2fc1e65316d9 100644
--- a/src/database.cpp
+++ b/src/database.cpp
@@ -250,6 +250,23 @@ Database::select(const std::string& select,                            // "id",
     return std::move(result);
 }
 
+int
+Database::count(const std::string& count, // "id", "body", ...
+                const std::string& table, // "tests"
+                const std::string& where) // "contact=:name AND id=:id"
+{
+    QSqlQuery query;
+    std::string columnsSelect;
+    auto prepareStr = std::string("SELECT count(" + count + ") FROM " + table + " WHERE " + where);
+    query.prepare(prepareStr.c_str());
+
+    if (not query.exec())
+        throw QueryError(query);
+
+    query.next();
+    return query.value(0).toInt();
+}
+
 void
 Database::deleteFrom(const std::string& table,                             // "tests"
                      const std::string& where,                             // "contact=:name AND id=:id
diff --git a/src/database.h b/src/database.h
index 3d67ac2cbd5f58aaf5229c69e288bac0c55107af..4b9cf6981d4f8e3e273ba4545310c8f66d382e66 100644
--- a/src/database.h
+++ b/src/database.h
@@ -208,6 +208,14 @@ public:
                             const std::string& where,
                             const std::map<std::string, std::string>& bindsWhere);
 
+    /**
+     * Returns the count of an expression.
+     * @param count is the column to count.
+     * @param table where to perfom the action on.
+     * @param where defines the conditional to select.
+     */
+    int count(const std::string& count, const std::string& table, const std::string& where);
+
 private:
     void createTables();
     void storeVersion(const std::string& version);
diff --git a/test/databasetester.cpp b/test/databasetester.cpp
index 8ee0013b3b4b8ad9522b70543bbeb4adbf69d96a..35222a5d1b8c7e371d975fb61671c14fdde12b9b 100644
--- a/test/databasetester.cpp
+++ b/test/databasetester.cpp
@@ -220,5 +220,13 @@ DatabaseTester::testDeleteInexistantValue()
     // Should not throw anything if fails
 }
 
+void
+DatabaseTester::testCountUnreadMessages()
+{
+    auto table = "profiles";
+    auto count = database_->count("uri", table, "status='0'");
+    CPPUNIT_ASSERT(count == 1);
+}
+
 } // namespace test
 } // namespace ring
diff --git a/test/databasetester.h b/test/databasetester.h
index dc0ff629d4254bb8cb66e908cacb0f2d282aebe5..291a353949b92970cb44cc82be78eb94bf3fb885 100644
--- a/test/databasetester.h
+++ b/test/databasetester.h
@@ -39,6 +39,7 @@ class DatabaseTester : public CppUnit::TestFixture {
 
     CPPUNIT_TEST_SUITE(DatabaseTester);
     CPPUNIT_TEST(testInsertAndSelectCorrectValue);
+    CPPUNIT_TEST(testCountUnreadMessages);
     CPPUNIT_TEST(testInsertIncorrectFail);
     CPPUNIT_TEST(testSelectInexistantValue);
     CPPUNIT_TEST(testUpdateCorrectValue);
@@ -84,6 +85,10 @@ public:
      * Delete inexistant value in the database
      */
     void testDeleteInexistantValue();
+    /**
+     * Count the number of unread messages.
+     */
+    void testCountUnreadMessages();
 
 protected:
     std::unique_ptr<lrc::Database> database_;