Moderate misbehaving users as a chat user
Apart from moderation mechanisms designed for chat administrators, the Chat SDK provides moderation options for regular chat users. Users whose Chat SDK instances weren't initialized with the secretKey
(as it's restricted to admins) can decide to hide messages from undesirable users.
The user IDs that a given chat user wants to hide messages from (mute them) are saved to a list. This mute list is soft-limited to 200 users and, by default, is only persisted for the duration of the user session.
You can decide to save and retrieve a local mute list during client initialization, effectively persisting the mute list beyond the scope of a single session, but then the hard 32KiB server data limit applies.
Mute list user limit
A persisted mute list can hold roughly up to 200 users (32KiB of data). If the size of the list exceeds that limit, the Chat SDK throws an HTTP 413 error and the list won't be persisted. The users will still be muted for the duration of the session.
All events and messages originating from a muted user are still received by the client, but are ignored. The mute list affects the following means of message delivery:
channel.connect()
channel.join()
channel.getHistory()
chat.listenForEvents()
chat.getEventsHistory()
Requires App Context
To mute users, you must enable App Context for your app's keyset in the Admin Portal.
Mute users as a regular chat user
As a regular chat user, you can mute a specific user on all channels.
Method signature
chat.mutedUsersManager.muteUser(userId): Promise<any>;
Input
Parameter | Type | Required | Description |
---|---|---|---|
userId | string | Yes | User ID of the user you want to mute. |
Output
This method returns a Promise
that succeeds when the data has been synced with the server. If syncMutedUsers
is not enabled, the Promise
always succeeds.
Errors
If the size of the mute list exceeds 32KiB (roughly 200 users), you'll get the HTTP 413 (Request Entity Too Large)
error.
Basic usage
import { Chat } from "@pubnub/chat"
const chat = Chat.init({
publishKey: "demo",
subscribeKey: "demo",
userId: "myUniqueUserId"
})
let userToMute = "user_1905"
await chat.mutedUsersManager.muteUser(userToMute)
Unmute users as a regular chat user
You can unmute a specific user on all channels. This removes the user from the mute list, allowing the client to see all messages and events originating from the user again.
Method signature
chat.mutedUsersManager.unmuteUser(userId): Promise<any>;
Input
Parameter | Type | Required | Description |
---|---|---|---|
userId | string | Yes | User ID of the user you want to unmute. |
Output
This method returns a Promise
that succeeds when the data has been synced with the server. If syncMutedUsers
is not enabled, the Promise
always succeeds.
Basic usage
import { Chat } from "@pubnub/chat"
const chat = Chat.init({
publishKey: "demo",
subscribeKey: "demo",
userId: "myUniqueUserId"
})
let userToUnmute = "user_1905"
await chat.mutedUsersManager.unmuteUser(userToUnmute)
Check muted users
You can check which users have been muted by inspecting the items in the mute list.
Method signature
chat.mutedUsersManager.mutedUsers
Output
This property returns a Array<String>
where each String
is a user ID of a muted user.
Basic usage
import { Chat } from "@pubnub/chat";
const chat = Chat.init({
publishKey: "demo",
subscribeKey: "demo",
userId: "myUniqueUserId"
});
let userToMute = "user_1905";
// Mute the user
await chat.mutedUsersManager.muteUser(userToMute)
// Once the user is muted, get the list of muted users
const mutedUsers = chat.mutedUsersManager.mutedUsers;
show all 17 linesPersist the mute list
By default, the mute list is only persisted for the duration of the user session. You can save and retrieve the mute list during client initialization, effectively persisting the mute list by setting the syncMutedUsers
parameter to true
during client initialization.
Mute list and Access Manager
If you use Access Manager for user moderation within your chat app and syncMutedUsers
is enabled, you must grant the Chat SDK user the following permissions:
read
permission to thePN_PRV.$currentUserId.mute1
channel.update
,delete
, andget
permissions for thePN_PRV.$currentUserId.mute1
user.
Make sure to change $currentUserId
to the user ID of the chat user that will use the mute list functionality.
Check restrictions
You can check if the chat administrator imposed any mute
or ban
restrictions for the following scenarios. Refer to the linked sections for more information.
- For a single user on a single channel
- For a single user on all channels
- For all users on a single channel
Basic usage
Single user on a single channel
// List all mute and ban restrictions set by the admin
// for the user support_agent_15.
// reference "support-agent-15"
const user = await chat.getUser("support_agent_15")
// list all restrictions set for that user
await user.getChannelsRestrictions()
All users on a single channel
// List all mute and ban restrictions set by the admin
// for the support channel.
// reference the "support" channel
const channel = await chat.getChannel("support")
// list all restrictions on the "support" channel
await channel.getUsersRestrictions()
Single user on all channels
// List all mute and ban restrictions set by the admin
// for the user support_agent_15.
// reference "support-agent-15"
const user = await chat.getUser("support_agent_15")
// list all restrictions set for that user
await user.getChannelsRestrictions()
Secure moderation
Client-side restrictions can easily be bypassed if not secured with an additional server-side logic that uses Access Manager to allow or block user's access to PubNub resources (channels and users). This server-side can also be followed by additional client-side errors that inform app users about their restrictions up front.
Client-side restrictions
Once you enable and define server-side permissions with Access Manager, you can be sure that your muting and banning restrictions are always enforced.
Additionally, you can read moderation restrictions set with the Chat SDK methods also on your app's frontend to let a given user know upfront that they are muted on a channel or banned from accessing a channel using popup messages, iconography, etc. For example, before a user tries to write a message on a channel where they are muted and tries to search for the input field that is either greyed out or unavailable, you can display a popup message informing them about the restriction.
To let the client application react in real-time to changes in user permissions and present this information to the users effectively, the app needs to listen to and act on changes in moderation events:
-
Listen for moderation events.
Set up a listener to listen for the
moderation
event type ("banned," "muted," or "lifted") generated when UI restrictions are added or removed.useEffect(() => {
// Set up a listener for moderation events on the current user's channel
const moderationListener = chat.listenForEvents({
channel: chat.currentUser.id,
type: "moderation",
callback: handleModerationEvent,
});
return () => {
moderationListener(); // Remove the moderation event listener on cleanup
};
}, [chat]); -
Act on moderation events.
Update permissions in response to moderation events and generate new tokens if necessary.
show all 29 lines// Callback function to handle different moderation events
async function handleModerationEvent(moderationPayload: Event<"moderation">) {
const { channelId, restriction, reason } = moderationPayload.payload;
// Handle different moderation events
if (restriction === "banned") {
// Revoke specific permissions for banning
console.log(`User ${chat.currentUser.id} is banned on channel ${channelId}. Reason: ${reason || "N/A"}`);
// Revoke access rights specific to banning logic here
// For example, you might remove write access
} else if (restriction === "muted") {
// Revoke specific permissions for muting
console.log(`User ${chat.currentUser.id} is muted on channel ${channelId}. Reason: ${reason || "N/A"}`); -
Remove the event listener.
return () => {
moderationListener(); // Remove the moderation event listener on cleanup
};