// Create pinned message
val pinExpirationDate = Calendar.getInstance().apply { set(2077, 1, 1) }.time
val message = Message(
text = "Hey punk",
pinned = true,
pinExpires = pinExpirationDate
)
channel.sendMessage(message).enqueue { /* ... */ }
// Unpin message
channel.unpinMessage(message).enqueue { /* ... */ }
// Pin message for 120 seconds
channel.pinMessage(message, timeout = 120).enqueue { /* ... */ }
// Change message expiration to 2077
channel.pinMessage(message, expirationDate = pinExpirationDate).enqueue { /* ... */ }
// Remove expiration date from pinned message
channel.pinMessage(message, expirationDate = null).enqueue { /* ... */ }
Pinned messages
Pinned messages allow users to highlight important messages, make announcements, or temporarily promote content. Pinning a message is, by default, restricted to certain user roles, but this is flexible. Each channel can have multiple pinned messages and these can be created or updated with or without an expiration.
Pin and unpin a message
An existing message can be updated to be pinned or unpinned by using the .pinMessage
and .unpinMessage
methods. Or a new message can be pinned when it is sent by setting the pinned
and pin_expires
fields when using channel.sendMessage
.
// create pinned message
const { message } = await channel.sendMessage({
text: "my message",
pinned: true,
pin_expires: "2077-01-01T00:00:00Z",
});
// unpin message
await client.unpinMessage(message);
// pin message for 120 seconds
await client.pinMessage(message, 120);
// change message expiration to 2077
await client.pinMessage(message, "2077-01-01T00:00:00Z");
// remove expiration date from pinned message
await client.pinMessage(message, null);
// create pinned message
final message = await channel
.sendMessage(Message(
text: 'my message',
pinned: true,
pinExpires: DateTime.now().add(Duration(days: 3)),
))
.then((resp) => resp.message);
// unpin message
await channel.unpinMessage(message);
// pin message for 120 seconds
await channel.pinMessage(message, 120);
// change message expiration to 2077
await channel.pinMessage(message, DateTime(2077));
// remove expiration date from pinned message
await channel.pinMessage(message, null);
let messageController = client.messageController(cid: .init(type: .messaging, id: "general"), messageId: "message-id")
// Pin message for 120 seconds
messageController.pin(.expirationTime(120))
// Unpin message
messageController.unpin()
// Pin message to specific date
messageController.pin(.expirationDate(Date()))
// Not yet supported in the Unreal SDK
$response = $channel->sendMessage([
'text' => 'Hey punk',
'pinned' => true,
'pin_expires' => "2077-01-01T00:00:00Z",
],
$user["id"]);
// unpin message
$client->unPinMessage($response["message"]["id"], $user["id"]);
// pin message for 120 seconds
$client->pinMessage($response["message"]["id"], $user["id"], 120);
response = channel.send_message({"pinned": True, "text": "hello world"}, user["id"])
# unpin message:
client.unpin_message(response["message"]["id"], user["id"])
# pin message for 120 secs:
client.pin_message(response["message"]["id"], user["id"], 120)
response = channel.send_message({pinned: true, text: "hello world"}, user["id"])
# unpin message:
client.unpin_message(response["message"]["id"], user["id"])
# pin message for 120 secs:
client.pin_message(response["message"]["id"], user["id"], 120)
msg := &Message{Text: "Hey punk", Pinned: true}
messageResp, err := channel.SendMessage(ctx, msg, user.ID)
// pin message
client.UnPinMessage(ctx, msg.ID, user.ID)
// pin message for 120 secs:
exp := time.Now().Add(time.Second * 120)
client.PinMessage(context.Background(), messageResp.Message.ID, user.ID, &exp)
var msg = new MessageRequest { Text = "hey punk", Pinned = true };
var response = await messageClient.SendMessageAsync(channel.Type, channel.Id, msg, user.Id);
// unpin message
await messageClient.UnpinMessageAsync(response.Message.Id, user.Id);
// pin message for 120 sec:
await messageClient.PinMessageAsync(response.Message.Id, user.Id, TimeSpan.FromSeconds(120));
// Pin until unpinned
await message.PinAsync();
// Pin for 7 days
await message.PinAsync(new DateTime().AddDays(7));
// Unpin previously pinned message
await message.UnpinAsync();
// Android SDK
// Create pinned message
Calendar calendar = Calendar.getInstance();
calendar.set(2077, 1, 1);
Date pinExpirationDate = calendar.getTime();
Message message = new Message();
message.setText("Hey punk");
message.setPinned(true);
message.setPinExpires(pinExpirationDate);
channelClient.sendMessage(message).enqueue(result -> { /* ... */ });
// Unpin message
channelClient.unpinMessage(message).enqueue(result -> { /* ... */ });
// Pin message for 120 seconds
channelClient.pinMessage(message, 120).enqueue(result -> { /* ... */ });
// Change message expiration to 2077
channelClient.pinMessage(message, pinExpirationDate).enqueue(result -> { /* ... */ });
// Remove expiration date from pinned message
channelClient.pinMessage(message, null).enqueue(result -> { /* ... */ });
// Backend SDK
// create pinned message
Message message =
Message.send(channelType, channelId)
.message(
MessageRequestObject.builder()
.text("my message")
.pinned(true)
.pinExpires(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
.parse("2077-01-01T00:00:00Z"))
.userId(userId)
.build())
.request()
.getMessage();
// unpin message
MessageRequestObject messageRequestObject = MessageRequestObject.buildFrom(message);
messageRequestObject.setPinned(false);
Message message2 =
Message.update(message.getId()).message(messageRequestObject).request().getMessage();
// pin message for 120 seconds
MessageRequestObject messageRequestObject2 = MessageRequestObject.buildFrom(message2);
messageRequestObject2.setPinned(true);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 120);
messageRequestObject2.setPinExpires(calendar.getTime());
Message message3 =
Message.update(message2.getId()).message(messageRequestObject2).request().getMessage();
// change message expiration to 2077
MessageRequestObject messageRequestObject3 = MessageRequestObject.buildFrom(message3);
messageRequestObject3.setPinExpires(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse("2077-01-01T00:00:00Z"));
Message message4 =
Message.update(message3.getId()).message(messageRequestObject3).request().getMessage();
// remove expiration date from pinned message
MessageRequestObject messageRequestObject4 = MessageRequestObject.buildFrom(message4);
messageRequestObject4.setPinExpires(null);
Message.update(message4.getId()).message(messageRequestObject4).request();
name | type | description | default | optional |
---|---|---|---|---|
pinned | boolean | Indicates whether the message is pinned or not | false | ✓ |
pinned_at | string | Date when the message got pinned | - | ✓ |
pin_expires | string | Date when the message pin expires. An empty value means that message does not expire | null | ✓ |
pinned_by | User | The user that pinned the message | - | ✓ |
To pin the message user has to have PinMessage
permission. You can find the list of permissions and defaults in Permission Resources and Default Permissions sections
Retrieve pinned messages
You can easily retrieve the last 10 pinned messages from the channel.pinned_messages
field:
channelClient.query(QueryChannelRequest()).enqueue { result ->
if (result.isSuccess) {
val pinnedMessages: List<Message> = result.data().pinnedMessages
} else {
// Handle result.error()
}
}
// get channel state
const channelState = await client.channel("messaging", channelId).query();
// get pinned messages from it
const pinnedMessages = channelState.pinned_messages;
// get channel state
final channelState = await channel.query();
// get pinned messages from it
final pinnedMessages = channelState.pinnedMessages;
let channelController = client.channelController(for: .init(type: .messaging, id: "general"))
channelController.synchronize() { error in
if error == nil {
channelController.channel?.pinnedMessages
}
}
// Not yet supported in the Unreal SDK
$response = $channel->query([
"watch" => false,
"state" => false,
"presence" => false
]);
$pinnedMessages = $response["pinned_messages"]
channel_state = channel.query(watch=False, state=False, presence=False)
pinned_message = channel_state["pinned_messages"]
channel_state = channel.query(watch: false, state: false, presence: false)
pinned_message = channel_state['pinned_messages']
_, err = channel.Query(ctx, map[string]interface{}{"watch": false, "state": true})
msgs := channel.PinnedMessages
var currentChannelState = await _channelClient.GetOrCreateAsync(_channel.Type, _channel.Id, new ChannelGetRequest
{
State = true,
Watch = false,
});
var pinnedMessags = currentChannelState.PinnedMessages;
// Will be implemented soon, raise a GitHub issue if you need this feature https://github.com/GetStream/stream-chat-unity/issues/
// Android SDK
channelClient.query(new QueryChannelRequest()).enqueue(result -> {
if (result.isSuccess()) {
List<Message> pinnedMessages = result.data().getPinnedMessages();
} else {
// Handle result.error()
}
});
// Backend SDK
ChannelGetResponse resp = Channel.getOrCreate("type", "id").request();
List<Message> messages = resp.getPinnedMessages();
To learn more about channels you can visit Querying Channels page
Paginate over all pinned messages
Stream Chat also provides dedicated endpoint for pinned messages of the channel which can be used to retrieve all pinned messages page by page:
// List the first page of pinned messages, pinned before now, of the channel with descending direction (newest on top)
channelClient.getPinnedMessages(
limit = 10,
sort = QuerySortByField.descByName("pinnedAt"),
pagination = PinnedMessagesPagination.BeforeDate(
date = Date(),
inclusive = false,
),
).enqueue { result ->
if (result.isSuccess) {
val pinnedMessages: List<Message> = result.data()
} else {
// Handle result.error()
}
}
// You can use a pinnedAt date retrieved from the previous request to get the next page
val nextDate = Date()
// List the next page of pinned messages
channelClient.getPinnedMessages(
limit = 10,
sort = QuerySortByField.descByName("pinnedAt"),
pagination = PinnedMessagesPagination.BeforeDate(
date = nextDate,
inclusive = false,
),
).enqueue { result ->
if (result.isSuccess) {
val pinnedMessages: List<Message> = result.data()
} else {
// Handle result.error()
}
}
// list first page of pinned messages of the channel with descending direction (newest on top)
const descPage1 = await channel.getPinnedMessages({ limit: 10 });
const descLastMsg = descPage1.messages[descPage1.messages.length - 1];
// list next page of pinned messages
const descPage2 = await channel.getPinnedMessages({
limit: 10,
id_lt: descLastMsg.id,
});
// list first page of pinned messages of the channel with ascending direction (oldest on top)
const ascPage1 = await channel.getPinnedMessages(
{ limit: 10 },
{ pinned_at: 1 },
);
const ascLastMsg = ascPage1.messages[ascPage1.messages.length - 1];
// list next page of pinned messages with ascending direction
const ascPage2 = await channel.getPinnedMessages(
{ limit: 10, id_gt: ascLastMsg.id },
{ pinned_at: 1 },
);
// Not yet supported in the Unreal SDK
// not implemented yet
# not implemented yet
# not implemented yet
// not implemented yet
// not implemented yet
// Will be implemented soon, raise a GitHub issue if you need this feature https://github.com/GetStream/stream-chat-unity/issues/
// Android SDK
// List the first page of pinned messages, pinned before now, of the channel with descending direction (newest on top)
channelClient.getPinnedMessages(10, QuerySortByField.descByName("pinnedAt"), new PinnedMessagesPagination.BeforeDate(new Date(), false))
.enqueue(result -> {
if (result.isSuccess()) {
List<Message> pinnedMessages = result.data();
} else {
// Handle result.error()
}
});
// You can use a pinnedAt date retrieved from the previous request to get the next page
Date nextDate = new Date();
// List the next page of pinned messages
channelClient.getPinnedMessages(10, QuerySortByField.descByName("pinnedAt"), new PinnedMessagesPagination.BeforeDate(nextDate, false))
.enqueue(result -> {
if (result.isSuccess()) {
List<Message> pinnedMessages = result.data();
} else {
// Handle result.error()
}
});
// Backend SDK
Message.search()
.filterCondition("pinned", true) // Additional filters can also be applied
.request();
channelController.loadPinnedMessages(
pageSize: 10,
sorting: [.init(key: .pinnedAt, isAscending: false)],
pagination: .earlier(Date(), inclusive: true)) { result in
switch result {
case .success(let pinnedMessages):
print(pinnedMessages)
case .failure(let failure):
// …
}
}
// Next page can be fetched using before message id
let fetchedPinnedMessageId = …
channelController.loadPinnedMessages(
pagination: .before(fetchedPinnedMessageId, inclusive: false)) { result in
// …
}