Flutter Firebase Chat App – Part 5: Message Status System (Sent, Delivered, Read)
Learn how to implement message status indicators like Sent, Delivered, and Read in a Flutter chat app using Firebase Firestore.
Introduction
Modern messaging apps provide visual feedback for message delivery. Users expect to know whether their message has been sent, delivered, or read.
In this article we will implement a message status system similar to WhatsApp.
The three states are:
- Sent
- Delivered
- Read
Message Status Flow
User sends message
↓
Message saved in Firestore
↓
Receiver device receives message
↓
Status updated to delivered
↓
Receiver opens chat
↓
Status updated to read
Firestore Message Document Structure
{
"senderId": "user1",
"text": "Hello",
"createdAt": Timestamp,
"status": "sent"
}
Possible status values:
- sent
- delivered
- read
Step 1: Set Initial Status When Sending
await messageRef.set({
"senderId": currentUserId,
"text": text,
"createdAt": Timestamp.now(),
"status": "sent"
});
Step 2: Update Status to Delivered
When receiver device loads the message stream, update status to delivered.
await messageRef.update({
"status": "delivered"
});
Step 3: Mark Messages as Read
When receiver opens the chat screen:
QuerySnapshot messages =
await FirebaseFirestore.instance
.collection('conversations')
.doc(conversationId)
.collection('messages')
.where('status', isEqualTo: 'delivered')
.get();
for (var doc in messages.docs) {
doc.reference.update({
"status": "read"
});
}
Message Status UI Icons
if (message.status == "sent") {
Icon(Icons.check)
}
if (message.status == "delivered") {
Icon(Icons.done_all)
}
if (message.status == "read") {
Icon(Icons.done_all, color: Colors.blue)
}
WhatsApp Style Status Meaning
- ✓ Message sent to server
- ✓✓ Message delivered to device
- ✓✓ Blue Message read
Only Show Status for Sender
if (message.senderId == currentUserId) {
showStatusIcon();
}
Performance Optimization
- Batch update read messages
- Avoid updating each message individually
Batch Update Example
WriteBatch batch = FirebaseFirestore.instance.batch();
for (var doc in messages.docs) {
batch.update(doc.reference, {"status": "read"});
}
await batch.commit();
Real-Time UI Update
Since we are using Firestore streams, message status updates automatically appear in the UI.
Prevent Updating Own Messages
if (message.senderId != currentUserId) {
updateStatus();
}
Scaling Strategy
- Update status only for visible messages
- Avoid updating very old messages
Security Rules Example
match /conversations/{conversationId}/messages/{messageId} {
allow update: if request.auth != null;
}
Common Mistakes
- Updating read status too frequently
- No batching
- Updating messages not belonging to user
Production Flow Summary
Message sent
↓
Status = sent
↓
Receiver device loads message
↓
Status = delivered
↓
Receiver opens chat
↓
Status = read
Conclusion
Adding message status indicators greatly improves the user experience of a messaging app.
Users feel confident knowing their messages have been delivered and read.
In Part 6, we will implement: Typing Indicator (User is typing...).
Share
What's Your Reaction?
Like
0
Dislike
0
Love
0
Funny
0
Angry
0
Sad
0
Wow
0