Skip to content

List messages

Query messages from a conversation using filters including time ranges, delivery status, and content types. You can either retrieve the full message list or just get a message count for efficiency.

Method parameters

All parameters are optional and can be combined to create precise filters and sorts:

ParameterTypeDescription
limitInt / Long / bigintMaximum number of messages to return
beforeNs / sentBeforeNsInt64 / Long / bigintFilter messages sent before this timestamp (nanoseconds)
afterNs / sentAfterNsInt64 / Long / bigintFilter messages sent after this timestamp (nanoseconds)
directionSortDirection / stringSort order: descending (default, newest first) or ascending (oldest first)
deliveryStatusMessageDeliveryStatus / stringFilter by delivery status: all (default), published, unpublished, or failed
excludeContentTypes / excludedContentTypesArrayContent types to exclude (e.g., reactions, read receipts).
excludeSenderInboxIdsArray of stringsInbox IDs whose messages should be excluded.
insertedBeforeNsInt64 / Long / bigintFilter messages inserted into the local database before this timestamp (nanoseconds)
insertedAfterNsInt64 / Long / bigintFilter messages inserted into the local database after this timestamp (nanoseconds)
sortBySortBy / enumSort by SENT_TIME (default, when message was sent) or INSERTED_TIME (when message was added to local database)

List messages with enriched metadata

The enrichedMessages() method retrieves messages from conversations with enriched metadata automatically included. This means reactions, replies, and other associated data are "baked in" to each message, eliminating the need for separate queries to fetch this information.

You may want to use enriched messages by default. The enrichedMessages() method provides better performance and simpler code.

Be sure to handle content types properly by using the generic content<T>() method with the appropriate type for reactions and replies.

List messages enriched with reaction metadata

Use reactions to get a list of reaction messages associated with the message.

Kotlin
// Retrieve messages with enriched data from a group
val groupMessages = group.enrichedMessages()
 
// Retrieve messages with enriched data from a DM
val dmMessages = dm.enrichedMessages()
 
// Access reaction data for each message
// Same enriched data is available for both groups and DMs
groupMessages.forEach { message ->
  // Access the list of reactions
  message.reactions.forEach { reaction ->
    val reactionContent = reaction.content<Reaction>()
    println("Reaction: ${reactionContent.content}")
  }
}

List messages enriched with reply metadata

Messages returned by enrichedMessages() include reply information when a message is a reply to another message.

Kotlin
// Retrieve messages with enriched data from a group
val groupMessages = group.enrichedMessages()
 
// Retrieve messages with enriched data from a DM
val dmMessages = dm.enrichedMessages()
 
// Access reply data for each message
// Same enriched data is available for both groups and DMs
groupMessages.forEach { message ->
  // Check if the message is a reply
  if (message.contentType == ContentTypeReply) {
    val replyContent = message.content<Reply>()
 
    if (replyContent != null) {
      println("This is a reply to message: ${replyContent.reference}")
      println("Reply text: ${replyContent.content}")
    }
  }
}

List messages (unenriched)

Retrieve messages from a conversation.

Browser
// Get all messages
const messages = await group.messages();
 
// Get the 10 most recent messages
const recentMessages = await group.messages({ limit: 10n });
 
// Get messages after a specific time (e.g., for pagination or unread messages)
const lastCheckTimestamp = 1738620126404999936n;
const newMessages = await group.messages({
  sentAfterNs: lastCheckTimestamp,
});
 
// Get messages from a DM conversation
const dm = await client.conversations.findOrCreateDm(recipientInboxId);
const dmMessages = await dm.messages({ limit: 50n });

Count messages in a conversation

Get a count of messages without retrieving the full message list. This is more efficient when you only need the number, such as for unread message badges.

Browser
// Get total message count
const totalCount = await group.countMessages();
 
// Get count of messages after last check (for unread badge)
const lastCheckTimestamp = 1738620126404999936n;
const unreadCount = await group.countMessages({
  sentAfterNs: lastCheckTimestamp,
});
 
// Get count for a DM conversation
const dm = await client.conversations.findOrCreateDm(recipientInboxId);
const dmUnreadCount = await dm.countMessages({
  sentAfterNs: lastCheckTimestamp,
});

Count unread messages excluding reactions

You can combine filters to count messages after the last check, excluding reactions, for example.

Browser
// Get count of unread messages, excluding reactions
const lastCheckTimestamp = 1738620126404999936n;
const unreadCount = await group.countMessages({
  sentAfterNs: lastCheckTimestamp,
  excludeContentTypes: [ContentType.Reaction],
});

Filter messages and message counts

Apply the same filtering parameters to both retrieve filtered messages with messages() or get counts of filtered messages with countMessages().

Browser
// Using messages()
const messages = await group.messages({
  sentAfterNs: 1738620126404999936n, // Filter by time
  deliveryStatus: 'published', // Filter by delivery status
  excludeContentTypes: [ContentType.Reaction], // Exclude content types
});
 
// Using countMessages()
const count = await group.countMessages({
  sentAfterNs: 1738620126404999936n, // Filter by time
  excludeSenderInboxIds: ['inbox_id_1'], // Exclude senders
});

Filter messages by insertion time

You can filter messages using insertion time ranges with insertedAfterNs and insertedBeforeNs. This is useful when you need to query based on when messages were added to the local database rather than when they were sent.

React Native
// Get messages inserted after a specific time
const lastInsertionTime = 1738620126404999936;
const newMessages = await group.messages({
  insertedAfterNs: lastInsertionTime,
  sortBy: 'INSERTED',
});
 
// Get messages inserted within a time range
const messages = await group.messages({
  insertedAfterNs: startTime,
  insertedBeforeNs: endTime,
  sortBy: 'INSERTED',
});

Sort messages by insertion time

You can sort messages using insertedAtNs.

React Native
  // Sort by insertion time for reliable pagination
  const messages = await group.messages({
      sortBy: "INSERTED",
      limit: 20
  });
 
  // Each message has both timestamps available
  messages.forEach((message) => {
      console.log(`Sent at: ${message.sentAtNs}`);
      console.log(`Inserted at: ${message.insertedAtNs}`);
  });

Paginate messages

Paginate by insertion time (recommended)

By default, messages are sorted by their sentAtNs timestamp (time when the message was sent). When you sort by sentAtNs, messages might arrive out of order. For example, a message sent 5 minutes ago might arrive in the local database after a message sent 1 minute ago. This can cause pagination issues, where you might miss messages when loading the next page.

Therefore, when paginating messages, it's more reliable to sort by insertedAtNs (time when the message was inserted into the local database). Sorting by insertedAtNs provides a totally ordered list because insertion timestamps are strictly sequential in the local database and are also deterministic and consistent.

Here's how to implement reliable message pagination using insertion time:

React Native
// First page
const firstPage = await group.messages({
  limit: 20,
  sortBy: 'INSERTED',
});
 
// Next page
const secondPage = await group.messages({
  limit: 20,
  insertedBeforeNs: firstPage[firstPage.length - 1].insertedAtNs,
  sortBy: 'INSERTED',
});

Paginate by sent time

You can also paginate using the message sent time, though this may have ordering issues if messages arrive out of sequence:

Browser
async function loadMoreMessages(
  conversation: Conversation,
  pageSize: number = 20
): Promise<DecodedMessage[]> {
  // Get the oldest message currently loaded
  const oldestMessage = currentMessages[currentMessages.length - 1];
 
  // Load the next page of messages before the oldest one
  return await conversation.messages({
    limit: BigInt(pageSize),
    sentBeforeNs: oldestMessage?.sentAtNs,
    direction: 'descending',
  });
}
 
// Initial load
let currentMessages = await group.messages({ limit: 20n });
 
// Load next page
const nextPage = await loadMoreMessages(group);
currentMessages = [...currentMessages, ...nextPage];