Skip to content

Messages Overview

Messages are the core building blocks of a chat application. This page covers sending, retrieving, updating, and deleting messages, as well as how Stream processes and formats message content.

Sending a Message

To send a message to a channel, use the sendMessage method:

const message = await channel.sendMessage({
  text: "Hello, world!",
});
Info:

Server-side SDKs require a user_id parameter to specify who is sending the message. Client-side SDKs set this automatically based on the connected user.

Message Parameters

Name Type Description Default Optional
text string The message text. Supports markdown and automatic URL enrichment.
attachments array A list of attachments (audio, video, image, text). Maximum 30 attachments per message with a combined size limit of 5KB.
user_id object Required for server-side SDKs. Set automatically in client-side mode.
mentioned_users array A list of user IDs mentioned in the message. You receive back the full user data in the response. Maximum 25 users.
mentioned_here bool When true, notifies all online channel members. false
mentioned_channel bool When true, notifies all channel members regardless of online status. false
mentioned_roles array A list of role names to mention (e.g. admin, channel_moderator). Maximum 10 roles.
mentioned_group_ids array A list of user group IDs to mention. All members of the specified groups who are also channel members will be notified. Maximum 10 groups.
custom data object Extra data for the message. Must not exceed 5KB in size.
skip_push bool If true, do not send a push notification for this message. false
restricted_visibility array Send the message only to specific channel members, identified by their user IDs.

Mentions

Stream supports five types of mentions. Only users who are members of the channel will be notified — mentioning a user, role, or group that has no members in the channel has no effect.

Mention Type Field Description Permission
User mentions mentioned_users Notify specific users by their ID, provided they are members of the channel CreateMention
@here mentioned_here Notify all online channel members NotifyHere
@channel mentioned_channel Notify all channel members regardless of online status NotifyChannel
Role mentions mentioned_roles Notify channel members who have one of the specified roles NotifyRole
Group mentions mentioned_group_ids Notify members of the specified user groups who are also members of the channel NotifyGroup
// Send a message mentioning all online users
const message = await channel.sendMessage({
  text: "Hey everyone!",
  mentioned_here: true,
});

// Send a message mentioning all channel members
const allMessage = await channel.sendMessage({
  text: "Important announcement!",
  mentioned_channel: true,
});

// Send a message mentioning specific roles
const roleMessage = await channel.sendMessage({
  text: "Attention moderators!",
  mentioned_roles: ["channel_moderator", "admin"],
});

// Send a message mentioning a user group
const groupMessage = await channel.sendMessage({
  text: "Design team, please review!",
  mentioned_group_ids: ["design-team-id"],
});
Info:

Each mention type requires its own permission as shown in the table above. The sender must have the corresponding permission or the mention will be rejected. For more information about user groups, see User Groups.

Sending Messages with Attachments

Messages can include attachments such as images, videos, audio files, and custom content. The following example shows how to send a message with an image attachment and user mentions:

const message = await channel.sendMessage(
  {
    text: "@Josh Check out this image!",
    attachments: [
      {
        type: "image",
        asset_url: "https://bit.ly/2K74TaG",
        thumb_url: "https://bit.ly/2Uumxti",
        myCustomField: 123,
      },
    ],
    mentioned_users: [josh.id],
    priority: "high",
  },
  { skip_push: true },
);

Supported Attachment Types

Stream's UI components support the following attachment types by default:

  • Audio: Audio files and recordings
  • Video: Video files
  • Image: Photos and images
  • Text: Text-based attachments

You can define custom attachment types as long as you implement the frontend rendering logic to handle them. Common use cases include embedding products (with photos, descriptions, and links) or sharing user locations.

The React tutorial explains how to customize the Attachment component.

Message Processing

When you send a message, Stream performs several processing steps:

  1. Markdown parsing: The message text is parsed for markdown formatting.
  2. URL enrichment: The first URL in the message text is scraped for Open Graph data, adding preview information automatically.
  3. Slash commands: Commands like /giphy, /ban, and /flag are processed and executed.

URL Enrichment

When a message contains a URL, Stream automatically scrapes the page for Open Graph metadata and creates an attachment with the preview information:

const response = await channel.sendMessage({
  text: "Check this out https://imgur.com/r/bears/4zmGbMN",
});

The resulting message includes an automatically generated attachment:

{
  "id": "message-id",
  "text": "Check this out https://imgur.com/r/bears/4zmGbMN",
  "attachments": [
    {
      "type": "image",
      "author_name": "Imgur",
      "title": "An update: Dushi made it safe to Bear Sanctuary",
      "title_link": "https://imgur.com/4zmGbMN",
      "text": "1678 views on Imgur",
      "image_url": "https://i.imgur.com/4zmGbMN.jpg?fb",
      "thumb_url": "https://i.imgur.com/4zmGbMN.jpg?fb",
      "og_scrape_url": "https://imgur.com/r/bears/4zmGbMN"
    }
  ]
}

URL Attachment Fields

Name Type Description
type string The attachment type based on the URL resource: audio, image, or video
author_name string The name of the author
title string The attachment title
title_link string The link the attachment points to
text string The attachment description text
image_url string The URL to the attached image
thumb_url string The URL to the attachment thumbnail
asset_url string The URL to the audio, video, or image resource
og_scrape_url string The original URL that was scraped
Info:

The Open Graph scraper uses this user agent: getstream.io/opengraph-bot facebookexternalhit/1.1. If you control the target website, ensure this user agent is not blocked for optimal results.

Message Response Structure

The API returns a message object containing all information about the message, including the author, attachments, reactions, and metadata.

Message Fields

Field Name Description
id Unique message identifier. Maximum 255 characters; cannot contain , or %.
text The raw message text
html Safe HTML generated from the text. Can only be set via server-side APIs or import.
type Message type: regular, ephemeral, error, reply, system, or deleted
cid The channel ID in the format type:id
user The author user object
attachments List of attachments (maximum 30)
mentioned_users Users mentioned in the message
mentioned_here Whether the message mentions all online users
mentioned_channel Whether the message mentions all channel members
mentioned_roles Roles mentioned in the message
mentioned_group_ids User group IDs mentioned in the message
reaction_counts Reaction counts by type (deprecated, use reaction_groups)
reaction_scores Reaction scores by type
reaction_groups Reaction statistics grouped by type with count, scores, and timestamps
latest_reactions The 10 most recent reactions
own_reactions Reactions added by the current user
reply_count Number of replies to this message
thread_participants Users who have participated in the thread
parent_id ID of the parent message if this is a reply
quoted_message_id ID of a quoted message
pinned Whether the message is pinned
pinned_at When the message was pinned
pinned_by User who pinned the message
pin_expires When the pin expires (null for no expiration)
silent Whether this is a silent message (no push notifications)
created_at When the message was created
updated_at When the message was last updated
deleted_at When the message was deleted
message_text_updated_at When the message text was last updated

Message Types

Type Description
regular A standard message posted to the channel. This is the default type.
ephemeral A temporary message delivered only to one user. Not stored in channel history. Used by commands like /giphy.
error An error message from a failed command. Ephemeral and only delivered to one user.
reply A message in a reply thread. Messages with a parent_id are automatically this type.
system A message generated by a system event, such as updating the channel or muting a user.
deleted A soft-deleted message.

Retrieving a Message

Use getMessage to retrieve a single message by its ID:

const message = await serverClient.getMessage(messageID);

// For soft-deleted messages, retrieve the original content (server-side only)
const deletedMessage = await serverClient.getMessage(messageID, {
  show_deleted_message: true,
});

Get Message Options

Name Type Description Default Optional
show_deleted_message boolean If true, returns the original content of a soft-deleted message false
Info:

The show_deleted_message option is only available for server-side calls.

Updating a Message

To replace a message, send the new message data. Use this when you want the message to contain only the fields you send. If you only want to edit a few fields and keep the rest, use partial update.

const message = { id: messageId, text: "Updated message text" };
const updated = await client.updateMessage(message);

Partial Update

Use partial updates to change only selected fields. This is the best choice for most edits because fields you do not include stay unchanged. You can also remove fields with Unset.

// Update text
await client.partialUpdateMessage(originalMessage.id, {
  set: { text: "Updated text" },
});

// Remove a custom field
await client.partialUpdateMessage(originalMessage.id, {
  unset: ["color"],
});

// Update nested properties
await client.partialUpdateMessage(originalMessage.id, {
  set: { "details.status": "complete" },
});

Deleting a Message

Messages can be deleted in three ways:

  • Soft delete: The message is marked as deleted but data is preserved. Can be undeleted.
  • Hard delete: The message and all related data (reactions, replies) are permanently removed.
  • Delete for me: The message is marked as deleted only for the current user. Other channel members are not affected.
Warning:

Deleting a message does not delete its file attachments. See deleting attachments for more information.

Note:

The Delete for me feature only works client-side with a user token. It is not supported with server-side admin or API tokens.

// Soft delete
await client.deleteMessage(messageID);

// Hard delete
await client.deleteMessage(messageID, { hardDelete: true });

// Delete for me
await client.deleteMessage(messageID, { deleteForMe: true });

Delete Type Comparison

Behavior Soft Delete Hard Delete Delete for Me
Can be done client-side
Message type set to "deleted" -
Data preserved - ✓ (for user)
Reactions and replies kept -
Can be undeleted - -
Affects other users -
Recoverable - -
Info:

Delete for me is limited to 100 messages per user per channel. Contact support to increase this limit.

Undeleting a Message

Soft-deleted messages can be restored using a server-side call:

await client.undeleteMessage(messageID, userID);

Messages can be undeleted if:

  • The message was soft-deleted (not hard-deleted)
  • The channel has not been deleted
  • It is not a reply to a deleted message (the parent must be undeleted first)
  • The user performing the undelete is valid