Delivered and Seen Receipts
Product deprecation notice
Effective April 30th, 2026, Vonage In-App Messaging will no longer be available. Access for new users will be closed, and the service will be discontinued for all existing users.
If you have any questions regarding this product’s discontinuation, please contact your account manager or our support team.
Overview
This guide covers delivered and seen receipts within a conversation.
Before you begin, make sure you added the SDK to your app and you are able to create a conversation.
NOTE: A step-by-step tutorial to build a chat application is available here.
This guide will make use of the following concepts:
Conversation Events:
message:deliveredevents that fire on a Conversation, after you are a Membermessage:seenevents that fire on a Conversation, after you are a Member
Set Message Status to Delivered
There is a method that will set a Message status to delivered. The following code snippet will set a messages's status to delivered once a message event happens in the conversation.
conversation.on('message', (sender, event) => {
// Can't set your own message status to delivered
if (conversation.me.id !== event.from) {
event.delivered().then(() => {
console.log("message event status set to delivered");
}).catch((error)=>{
console.error("error setting message event status to delivered ", error);
});
};
});
override fun onMessageEvent(messageEvent: NexmoMessageEvent) {
messageEvent.markAsDelivered(object: NexmoRequestListener<Void> {
override fun onError(error: NexmoApiError) {}
override fun onSuccess(result: Void?) {}
})
}
public void onMessageEvent(@NonNull NexmoMessageEvent messageEvent) {
messageEvent.markAsDelivered(new NexmoRequestListener() {
@Override
public void onError(@NonNull NexmoApiError error) { ... }
@Override
public void onSuccess(@Nullable Object result) { ... }
});
}
if conversation.myMember?.memberUuid != event.fromMemberId {
conversation.sendMarkDeliveredMessage(event.uuid, completionHandler: nil)
}
if (conversation.myMember.memberUuid != event.fromMemberId) {
[conversation sendMarkDeliveredMessage:event.uuid completionHandler:nil];
}
Message Delivered Receipt
Given a conversation you are already a member of, message:delivered events will be received when Message events are set to delivered in the context of the current conversation:
conversation.on('message:delivered', (data, event) => {
console.log(event);
});
private val messageListener = object : NexmoMessageEventListener {
override fun onTypingEvent(typingEvent: NexmoTypingEvent) {}
override fun onAttachmentEvent(attachmentEvent: NexmoAttachmentEvent) {}
override fun onTextEvent(textEvent: NexmoTextEvent) {}
override fun onSeenReceipt(seenEvent: NexmoSeenEvent) {}
override fun onEventDeleted(deletedEvent: NexmoDeletedEvent) {}
override fun onDeliveredReceipt(deliveredEvent: NexmoDeliveredEvent) {
val userName = deliveredEvent.getEmbeddedInfo.user.name
Log.d("TAG", "Event ${deliveredEvent.initialEventId()} delivered to User $userName")
}
}
conversation.addMessageEventListener(messageListener)
private NexmoMessageEventListener messageListener = new NexmoMessageEventListener() {
@Override
public void onTextEvent(@NonNull NexmoTextEvent textEvent) {}
@Override
public void onAttachmentEvent(@NonNull NexmoAttachmentEvent attachmentEvent) {}
@Override
public void onEventDeleted(@NonNull NexmoDeletedEvent deletedEvent) {}
@Override
public void onSeenReceipt(@NonNull NexmoSeenEvent seenEvent) {}
@Override
public void onDeliveredReceipt(@NonNull NexmoDeliveredEvent deliveredEvent) {
String userName = deliveredEvent.getEmbeddedInfo().getUser().getName();
Log.d("TAG", "Event " + deliveredEvent.initialEventId() + "delivered to User " + userName);
}
@Override
public void onTypingEvent(@NonNull NexmoTypingEvent typingEvent) {}
};
conversation.addMessageEventListener(messageListener);
Add NXMConversationDelegate as an extension to a ViewController or similar, and implement conversation(_ conversation: NXMConversation, didReceive event: NXMMessageStatusEvent):
Note: The first method below is required when implementing NXMConversationDelegate:
extension ViewController: NXMConversationDelegate {
func conversation(_ conversation: NXMConversation, didReceive error: Error) {
NSLog("Conversation error: \(error.localizedDescription)")
}
func conversation(_ conversation: NXMConversation, didReceive event: NXMMessageStatusEvent) {
if event.status == .delivered {
NSLog("Received delivered event: \(event.referenceEventUuid)")
}
}
}
Have a ViewController, or similar, conform to NXMConversationDelegate and implement conversation:didReceiveMessageStatusEvent::
Note: The first method below is required when implementing NXMConversationDelegate:
- (void)conversation:(NXMConversation *)conversation didReceive:(NSError *)error {
NSLog(@"Conversation error: %@", error.localizedDescription);
}
- (void)conversation:(NXMConversation *)conversation didReceiveMessageStatusEvent:(NXMMessageStatusEvent *)event {
if (event.status == NXMMessageStatusTypeDelivered) {
NSLog(@"Received delivered event: %li", (long)event.referenceEventUuid);
}
}
Set Message Status to Seen
There is a method that will set a Message status to seen. The following code snippet will set a messages's status to seen once a message event happens in the conversation.
conversation.on('message', (sender, event) => {
// Can't set your own message status to seen
if (conversation.me.id !== event.from) {
event.seen().then(() => {
console.log("message event status set to seen");
}).catch((error)=>{
console.error("error setting message event status to seen ", error);
});
};
});
override fun onMessageEvent(messageEvent: NexmoMessageEvent) {
messageEvent.markAsSeen(object: NexmoRequestListener<Void> {
override fun onError(error: NexmoApiError) {...}
override fun onSuccess(result: Void?) {...}
})
}
public void onMessageEvent(@NonNull NexmoMessageEvent messageEvent) {
messageEvent.markAsSeen(new NexmoRequestListener() {
@Override
public void onError(@NonNull NexmoApiError error) { ... }
@Override
public void onSuccess(@Nullable Object result) { ... }
});
}
if conversation.myMember?.memberUuid != event.fromMemberId {
conversation.sendMarkSeenMessage(event.uuid, completionHandler: nil)
}
if (conversation.myMember.memberUuid != event.fromMemberId) {
[conversation sendMarkSeenMessage:event.uuid completionHandler:nil];
}
Message Seen Receipt
Given a conversation you are already a member of, message:seen events will be received when Message events are set to seen in the context of the current conversation:
conversation.on('message:seen', (data, event) => {
console.log(event);
});
private val messageListener = object : NexmoMessageEventListener {
override fun onTypingEvent(typingEvent: NexmoTypingEvent) {}
override fun onAttachmentEvent(attachmentEvent: NexmoAttachmentEvent) {}
override fun onTextEvent(textEvent: NexmoTextEvent) {}
override fun onSeenReceipt(seenEvent: NexmoSeenEvent) {
val userName = seenEvent.getEmbeddedInfo.user.name
Log.d("TAG", "Event ${seenEvent.initialEventId()} seen by User $userName")
}
override fun onEventDeleted(deletedEvent: NexmoDeletedEvent) {}
override fun onDeliveredReceipt(deliveredEvent: NexmoDeliveredEvent) {}
}
conversation.addMessageEventListener(messageListener)
private NexmoMessageEventListener messageListener = new NexmoMessageEventListener() {
@Override
public void onTextEvent(@NonNull NexmoTextEvent textEvent) {}
@Override
public void onAttachmentEvent(@NonNull NexmoAttachmentEvent attachmentEvent) {}
@Override
public void onEventDeleted(@NonNull NexmoDeletedEvent deletedEvent) {}
@Override
public void onSeenReceipt(@NonNull NexmoSeenEvent seenEvent) {
String userName = seenEvent.getEmbeddedInfo().getUser().getName();
Log.d("TAG", "Event " + seenEvent.initialEventId() + "seen by User " + userName);
}
@Override
public void onDeliveredReceipt(@NonNull NexmoDeliveredEvent deliveredEvent) {}
@Override
public void onTypingEvent(@NonNull NexmoTypingEvent typingEvent) {}
};
conversation.addMessageEventListener(messageListener);
Add NXMConversationDelegate as an extension to a ViewController or similar, and implement conversation(_ conversation: NXMConversation, didReceive event: NXMMessageStatusEvent):
Note: The first method below is required when implementing NXMConversationDelegate:
extension ViewController: NXMConversationDelegate {
func conversation(_ conversation: NXMConversation, didReceive error: Error) {
NSLog("Conversation error: \(error.localizedDescription)")
}
func conversation(_ conversation: NXMConversation, didReceive event: NXMMessageStatusEvent) {
if event.status == .seen {
NSLog("Received seen event: \(event.referenceEventUuid)")
}
}
}
Have a ViewController, or similar, conform to NXMConversationDelegate and implement conversation:didReceiveMessageStatusEvent::
Note: The first method below is required when implementing NXMConversationDelegate:
- (void)conversation:(NXMConversation *)conversation didReceive:(NSError *)error {
NSLog(@"Conversation error: %@", error.localizedDescription);
}
- (void)conversation:(NXMConversation *)conversation didReceiveMessageStatusEvent:(NXMMessageStatusEvent *)event {
if (event.status == NXMMessageStatusTypeSeen) {
NSLog(@"Received seen event: %li", (long)event.referenceEventUuid);
}
}