Moderate misbehaving users as a chat administrator
note
Enable App Context in the Admin Portal to work with user metadata.
Administrators are chat users with SDK instances initialized with secretKey. Admin moderation capabilities:
- Mute users on channels
- Ban users from accessing channels
Use Access Manager to enforce restrictions. See also moderation for regular users.
Mute or ban users as an administrator
Mute or ban users with setRestrictions() on the Chat, User, or Channel object. All three produce the same output with different input parameters.
How it works:
- Muting/banning creates a
moderationevent (mutedorbanned) - A moderation membership is created with
PUBNUB_INTERNAL_MODERATION_prefix (secured via Access Manager, filtered fromgetMemberships()results) - Lifting restrictions removes the moderation membership and creates a
liftedevent
Listen to moderation events to trigger actions like removing memberships. Check restrictions to verify user status.
Secret Key required
Initialize with Secret Key (from Admin Portal) for admin operations. Never expose secretKey to clients. If compromised, generate a new one in the Admin Portal.
Method signature
These methods take the following parameters:
-
setRestrictions()(on theChatobject)1chat.setRestrictions(
2 userId: string,
3 channelId: string,
4 {
5 ban?: boolean,
6 mute?: boolean,
7 reason?: string
8 }
9): Promise<void> -
setRestrictions()(on theUserobject)1user.setRestrictions(
2 channel: Channel,
3 {
4 ban?: boolean,
5 mute?: boolean,
6 reason?: string
7 }
8): Promise<void> -
setRestrictions()(on theChannelobject)1channel.setRestrictions(
2 user: User,
3 {
4 ban?: boolean,
5 mute?: boolean,
6 reason?: string
7 }
8): Promise<void>
Input
| Parameter | Required for Chat | Required for User | Required for Channel | Description |
|---|---|---|---|---|
userIdType: stringDefault: n/a | Yes | No | No | Unique User ID that becomes your app's current user. It's a string of up to 92 characters that identifies a single client (end user, device, or server) that connects to PubNub. Based on User ID, PubNub calculates pricing for your apps' usage. User ID should be persisted and remain unchanged. If you don't set userId, you won't be able to connect to PubNub. In this method, userId stands for the user that you want to mute or ban. |
channelIdType: stringDefault: n/a | Yes | No | No | ID of the channel on/from which the user should be muted or banned. |
channelType: ChannelDefault: n/a | No | Yes | No | Channel object on/from which the user should be muted or banned. |
userType: UserDefault: n/a | No | No | Yes | User object to be muted or banned. |
→ banType: booleanDefault: n/a | No | No | No | Value that represents the user's moderation restrictions. Set to true to ban the user from the channel or to false to unban them. |
→ muteType: booleanDefault: n/a | No | No | No | Value that represents the user's moderation restrictions. Set to true to mute the user on the channel or to false to unmute them. |
→ reasonType: stringDefault: n/a | No | No | No | Reason why you want to ban or mute the user. |
Output
| Type | Description |
|---|---|
Promise<void> | Method returns no output data. |
Errors
Whenever you try to mute or ban a user on a client that was not initialized with a Secret Key, you'll get the Moderation restrictions can only be set by clients initialized with a Secret Key error.
Sample code
Mute
Mute support_agent_15 on the support channel.
-
setRestrictions()(on theChatobject)1await chat.setRestrictions(
2 userId: "support_agent_15",
3 channelId: "support",
4 {
5 mute: true
6 }
7) -
setRestrictions()(on theUserobject)1// reference "support-agent-15"
2const user = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const support = await chat.getChannel("support")
6
7// mute the user
8await user.setRestrictions(
9 channel: support,
10 {
11 mute: true
12 }
13) -
setRestrictions()(on theChannelobject)1// reference "support-agent-15"
2const mutedUser = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const channel = await chat.getChannel("support")
6
7// mute the user
8channel.setRestrictions(
9 user: mutedUser,
10 {
11 mute: true
12 }
13)
Ban
Ban support_agent_15 from the support channel.
-
setRestrictions()(on theChatobject)1// reference "support-agent-15"
2const user = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const channel = await chat.getChannel("support")
6
7// ban the user
8await chat.setRestrictions(
9 userId: "support_agent_15",
10 channelId: "support",
11 {
12 ban: true
13 }
14) -
setRestrictions()(on theUserobject)1// reference "support-agent-15"
2const user = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const support = await chat.getChannel("support")
6
7// ban the user
8await user.setRestrictions(
9 channel: support,
10 {
11 ban: true
12 }
13) -
setRestrictions()(on theChannelobject)1// reference "support-agent-15"
2const mutedUser = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const channel = await chat.getChannel("support")
6
7// ban the user
8channel.setRestrictions(
9 user: mutedUser,
10 {
11 ban: true
12 }
13)
Check restrictions
One user on one channel
Check mute or ban restrictions for a user on a specific channel with getChannelRestrictions() or getUserRestrictions().
Method signature
These methods take the following parameters:
-
getChannelRestrictions()1user.getChannelRestrictions(
2 channel: Channel
3): Promise<{
4 ban: boolean,
5 mute: boolean,
6 reason: string | number | boolean,
7}> -
getUserRestrictions()1channel.getUserRestrictions(
2 user: User
3): Promise<{
4 ban: boolean;
5 mute: boolean;
6 reason: string | number | boolean,
7}>
Input
| Parameter | Required in getChannelRestrictions() | Required in getUserRestrictions() | Description |
|---|---|---|---|
channelType: ChannelDefault: n/a | Yes | No | Channel object on/from which the user can be muted or banned. |
userType: UserDefault: n/a | No | Yes | User object that can be muted or banned. |
Output
| Parameter | Description |
|---|---|
Promise<>Type: object | Returned object containing two fields: ban and mute. |
→ banType: boolean | Info whether the user is banned from the channel. |
→ muteType: boolean | Info whether the user is muted on the channel. |
→ reasonType: string, number, or boolean | Reason why the user was banned or muted. |
Sample code
Check if the user support_agent_15 has any restrictions set on the support channel.
-
getChannelRestrictions()1// reference "support-agent-15"
2const user = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const support = await chat.getChannel("support")
6
7// check user restrictions
8await user.getChannelRestrictions(
9 channel: support
10) -
getUserRestrictions()1// reference "support-agent-15"
2const restrictedUser = await chat.getUser("support_agent_15")
3
4// reference the "support" channel
5const channel = await chat.getChannel("support")
6
7// check user restrictions
8await channel.getUserRestrictions(
9 user: restrictedUser
10)
One user on all channels
Check mute or ban restrictions for a user across all their channels with getChannelsRestrictions().
Method signature
This method takes the following parameters:
1user.getChannelsRestrictions(
2 {
3 limit?: number,
4 page?: {
5 next?: string,
6 prev?: string
7 },
8 sort?: object
9 }
10): Promise<{
11 page: {
12 next: string,
13 prev: string,
14 },
15 total: number,
show all 23 linesInput
| Parameter | Description |
|---|---|
limitType: numberDefault: 100 | Number of objects to return in response. The default (and maximum) value is 100. |
pageType: objectDefault: n/a | Object used for pagination to define which previous or next result page you want to fetch. |
→ nextType: stringDefault: n/a | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
→ prevType: stringDefault: n/a | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the next parameter is supplied. |
sortType: objectDefault: n/a | Key-value pair of a property to sort by, and a sort direction. Available options are id, name, and updated. Use asc or desc to specify the sorting direction, or specify null to take the default sorting direction (ascending). For example: {name: "asc"}. By default, the items are sorted by the last updated date. |
Output
| Parameter | Description |
|---|---|
Promise<>Type: object | Returned object containing these fields: page, total, status, and restrictions. |
→ pageType: object | Object used for pagination to define which previous or next result page you want to fetch. |
→ nextType: string | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
→ prevType: string | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the next parameter is supplied. |
→ totalType: number | Total number of restrictions. |
→ statusType: number | Status code of a server response, like 200. |
→ restrictionsType: object | Object containing a list of restrictions. |
→ banType: boolean | Info whether the user is banned from the given channel. |
→ muteType: boolean | Info whether the user is muted on the given channel. |
→ reasonType: string, number, or boolean | Reason why the user was banned or muted. |
→ channelIdType: string | ID of the channel containing user restrictions. |
Sample code
List all mute and ban restrictions set for the user support_agent_15.
1// reference "support-agent-15"
2const user = await chat.getUser("support_agent_15")
3
4// list all restrictions set for that user
5await user.getChannelsRestrictions()
All users on one channel
Check mute or ban restrictions for all members of a channel with getUsersRestrictions().
Method signature
This method takes the following parameters:
1channel.getUsersRestrictions(
2 {
3 limit?: number,
4 page?: {
5 next?: string,
6 prev?: string
7 },
8 sort?: object
9 }
10): Promise<{
11 page: {
12 next: string,
13 prev: string,
14 },
15 total: number,
show all 22 linesInput
| Parameter | Description |
|---|---|
limitType: numberDefault: 100 | Number of objects to return in response. The default (and maximum) value is 100. |
pageType: objectDefault: n/a | Object used for pagination to define which previous or next result page you want to fetch. |
→ nextType: stringDefault: n/a | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
→ prevType: stringDefault: n/a | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the next parameter is supplied. |
sortType: objectDefault: n/a | Key-value pair of a property to sort by, and a sort direction. Available options are id, name, and updated. Use asc or desc to specify the sorting direction, or specify null to take the default sorting direction (ascending). For example: {name: "asc"}. By default, the items are sorted by the last updated date. |
Output
| Parameter | Description |
|---|---|
Promise<>Type: object | Returned object containing these fields: page, total, status, and restrictions. |
→ pageType: object | Object used for pagination to define which previous or next result page you want to fetch. |
→ nextType: string | Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off. |
→ prevType: string | Random string returned from the server, indicating a specific position in a data set. Used for backward pagination, it fetches the previous page, enabling access to earlier data. Ignored if the next parameter is supplied. |
→ totalType: number | Total number of restrictions. |
→ statusType: number | Status code of a server response, like 200. |
→ restrictionsType: object | Object containing a list of restrictions. |
→ banType: boolean | Info whether the user is banned from the given channel. |
→ muteType: boolean | Info whether the user is muted on the given channel. |
→ userIdType: string | ID of the restricted user. |
Sample code
List all mute and ban restrictions set for the support channel.
1// reference the "support" channel
2const channel = await chat.getChannel("support")
3
4// list all restrictions on the "support" channel
5await channel.getUsersRestrictions()
Secure moderation
Client-side UI restrictions (hiding channels, disabling input) can be bypassed. Secure with server-side logic using Access Manager, plus optional client-side feedback.
note
See Moderation as user for client-side moderation options.
Server-side restrictions
Use Access Manager with Chat SDK methods to grant/revoke permissions based on muting/banning restrictions.
Access Manager permissions
With syncMutedUsers enabled, grant these permissions (replace $currentUserId with actual user ID):
readonPN_PRV.$currentUserId.mute1channelupdate,delete,getonPN_PRV.$currentUserId.mute1user
Recommended workflow:
- Admin sets restrictions via dashboard (e.g., Channel Monitor)
- Get moderation restrictions for users
- Call Access Manager API to generate/revoke tokens
Implementation steps:
-
Enable Access Manager in the Admin Portal.
-
Initialize Chat SDK with
authKeyon the frontend to authenticate users and grant access to PubNub resources.1import { Chat } from "@pubnub/chat"
2
3const userId = "your-user-id"
4const authToken = "token-from-your-server"
5...
6
7const chat = Chat.init(
8 subscribeKey: "your-subscribe-key-from-admin-portal",
9 publishKey: "your-publish-key-from-admin-portal"
10 userId: userId,
11 authKey: authToken
12) -
Initialize backend with
secretKey(secretKey) to secure your PubNub instance.tip
secretKeysigns and verifies messages for Access Manager. Never expose to clients.1import { Chat } from "@pubnub/chat"
2
3const serverId = "auth-server"
4
5export const chat = await Chat.init({
6 subscribeKey: "your-subscribe-key-from-admin-portal",
7 publishKey: "your-publish-key-from-admin-portal",
8 secretKey: "your-secret-key-from-admin-portal",
9 userId: serverId,
10}) -
Get user permissions - Retrieve restrictions and convert to permission format (read/write/access per channel).
show all 20 lines1async function defineUserPermissions(userId: string) {
2 // Retrieve user information and channel restrictions
3 const user = await chat.getUser(userId);
4 const userRestrictions = await user.getChannelsRestrictions();
5
6 // Simplify the detailed channel restrictions into a format suitable for the authorization token
7 const reducedChannels = userRestrictions.restrictions.reduce((acc, curr) => {
8 return {
9 ...acc,
10 [curr.channelId]: {
11 read: !curr.ban,
12 write: (!curr.mute && !curr.ban),
13 get: true,
14 }
15 }; -
Generate authorization token - Assign an access token with channel permissions and validity period.
tip
See Permissions for the complete operation-to-permission mapping.
show all 28 lines1async function generateAuthToken(userId: string, reducedChannels: Record<string, any>) {
2 // Set up parameters for the authorization token
3 const grantTokenParams = {
4 ttl: 43200,
5 authorized_uuid: userId,
6 patterns: {
7 channels: {
8 ".*": {
9 get: true,
10 read: true,
11 write: true,
12 },
13 },
14 },
15 resources: {Short TTLs recommended
Use short-lived tokens (TTLs) for up-to-date restrictions, or revoke tokens with
chat.sdk.revokeToken(). -
Listen for moderation events - All events are sent to
PUBNUB_INTERNAL_MODERATION.[user_id]. Configure via Events & Actions in the Admin Portal with Messages as the event source.
-
Act on moderation events - Create a Webhook action in Events & Actions pointing to your server URL for token changes. Link to the event listener.

Client-side restrictions
With server-side permissions enforced, add optional client-side UI feedback.
note
See Client-side restrictions for regular user moderation.
Listen to moderation events
listenForEvents() sends notifications when users are muted/banned or removes memberships on ban.
tip
See Chat events for moderation event details.
Method signature
This method has the following parameters:
1chat.listenForEvents({
2 channel: PUBNUB_INTERNAL_MODERATION.${userId};
3 type?: "moderation";
4 callback: (event: Event<"moderation">) => unknown;
5}): () => void
Input
| Parameter | Description |
|---|---|
channel *Type: PUBNUB_INTERNAL_MODERATION.${userId}Default: n/a | Channel of the user from whom you want to get moderation events. |
typeType: stringDefault: n/a | Type of events. moderation is the type defined for all events emitted when a user is muted/banned for misbehaving, or when these permissions are lifted. |
callback *Type: n/a Default: n/a | Callback function passed as a parameter. It defines the custom behavior to be executed whenever a moderation event type is detected on the specific channel. |
Output
| Type | Description |
|---|---|
() => void | Function you can call to disconnect (unsubscribe) from the channel and stop receiving moderation events. |
Sample code
Send a moderation event to the muted user.
1user.setRestrictions(PUBNUB_INTERNAL_MODERATION.${chat.currentUser.id}, { mute: true, reason: "Bad behavior" });
2
3(async () => {
4 await chat.listenForEvents({
5 channel: PUBNUB_INTERNAL_MODERATION.${chat.currentUser.id},
6 type: "moderation",
7 callback: (event: Event<"moderation">) => {
8 if (event.payload.restriction === "muted") {
9 console.log(`You were muted on channel ${event.payload.channelId}`);
10 }
11 },
12 });
13})();
Flag/Report users (deprecated)
DEPRECATED_report() flags a user and reports them to admins. Requires a reason. Creates a report event on PUBNUB_INTERNAL_ADMIN_CHANNEL.
Method signature
This method takes the following parameters:
1user.DEPRECATED_report(reason: string): Promise<any>
Input
| Parameter | Description |
|---|---|
reason *Type: stringDefault: n/a | Reason for reporting/flagging a given user. |
Output
| Type | Description |
|---|---|
Promise<any> | Returned object with a value of any type. |
Sample code
Report support_agent_15 to the admin for posting offensive images on the support channel.
1// reference the "chat" object and invoke the "getUser()" method
2const user = await chat.getUser("support_agent_15")
3// report "support_agent_15" to the admin and provide the reason
4await user.DEPRECATED_report("Could you please mute Mike as he keeps sending offensive photos?")
Listen to report events (deprecated)
report events (deprecated)Monitor user reports with listenForEvents() for moderation dashboard alerts.
Method signature
This method has the following parameters:
1chat.listenForEvents({
2 channel: string;
3 type?: "report";
4 callback: (event: Event<"report">) => unknown;
5}): () => void
Input
| Parameter | Description |
|---|---|
channel *Type: stringDefault: n/a | Channel to listen for new report events. Set this value to a dedicated PUBNUB_INTERNAL_ADMIN_CHANNEL where all report events are sent. |
typeType: stringDefault: n/a | Type of events. report is the type defined for all events emitted when a user is flagged/reported by someone for misbehaving. |
callback *Type: n/a Default: n/a | Callback function passed as a parameter. It defines the custom behavior to be executed whenever a report event type is detected on the specific channel. |
methodType: stringDefault: | This parameter is deprecated. You no longer have to provide a method used to send this event type as the method is now passed automatically. publish for all events related to reporting. |
Output
| Type | Description |
|---|---|
() => void | Function you can call to disconnect (unsubscribe) from the channel and stop receiving report events. |
Sample code
Notify an admin when one user reports another user.
1user.DEPRECATED_report("Inappropriate content");
2
3(async () => {
4 await chat.listenForEvents({
5 channel: "admin",
6 type: "report",
7 callback: (event) => {
8 console.log(`User ${event.userId} reported user ${event.payload.reported} for ${event.payload.reason}`);
9 },
10 });
11})();