> ## Documentation Index
> Fetch the complete documentation index at: https://docs.discord.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate Moderation

> Implement moderation features and safety controls in your application.

export const TextControllerIcon = props => <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="currentColor" d="M24 5.7c0-1.54-.2-2.66-.34-3.23C23.35 1.17 22.3.92 21.2.68a.68.68 0 0 0-.62.18c-.16.16-.35.33-.58.32a19.27 19.27 0 0 0-2 0c-.23 0-.42-.16-.58-.32a.68.68 0 0 0-.62-.18c-1.1.24-2.15.5-2.46 1.8-.13.56-.34 1.68-.34 3.22v2.23a1.4 1.4 0 0 0 2.66.63l.8-1.6c.1-.2.34-.3.56-.25.26.06.62.12.98.12s.72-.06.98-.12a.5.5 0 0 1 .56.25l.8 1.6A1.4 1.4 0 0 0 24 7.93V5.7Z" /><path fill="currentColor" d="M10.18 8h1.33c.27 0 .5.22.54.49.03.21.09.43.16.63.15.38-.1.88-.52.88H9.85l-.67 4h4.97l.37-2.23c.05-.29.33-.47.62-.45l.26.01h.63c.31 0 .55.28.5.59L16.18 14H20a1 1 0 1 1 0 2h-4.15l-.86 5.16a1 1 0 1 1-1.98-.32l.8-4.84H8.86l-.86 5.16A1 1 0 1 1 6 20.84L6.82 16H3a1 1 0 1 1 0-2h4.15l.67-4H4a1 1 0 0 1 0-2h4.15l.86-5.16a1 1 0 1 1 1.98.32L10.19 8Z" /></svg>;

export const VoiceNormalIcon = props => <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="currentColor" d="M12 3a1 1 0 0 0-1-1h-.06a1 1 0 0 0-.74.32L5.92 7H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.92l4.28 4.68a1 1 0 0 0 .74.32H11a1 1 0 0 0 1-1V3ZM15.1 20.75c-.58.14-1.1-.33-1.1-.92v-.03c0-.5.37-.92.85-1.05a7 7 0 0 0 0-13.5A1.11 1.11 0 0 1 14 4.2v-.03c0-.6.52-1.06 1.1-.92a9 9 0 0 1 0 17.5Z" /><path fill="currentColor" d="M15.16 16.51c-.57.28-1.16-.2-1.16-.83v-.14c0-.43.28-.8.63-1.02a3 3 0 0 0 0-5.04c-.35-.23-.63-.6-.63-1.02v-.14c0-.63.59-1.1 1.16-.83a5 5 0 0 1 0 9.02Z" /></svg>;

export const ChatIcon = props => <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="currentColor" d="M12 22a10 10 0 1 0-8.45-4.64c.13.19.11.44-.04.61l-2.06 2.37A1 1 0 0 0 2.2 22H12Z" /></svg>;

This guide will walk you through integrating and managing content moderation for your game when using the Discord Social SDK.

## Overview

Effective moderation is essential for creating healthy social experiences. This guide will help you:

* Better understand your moderation responsibilities
* Implement server-side moderation for text content using Discord's moderation metadata API
* Implement client-side moderation for audio content with the Discord Social SDK

## Prerequisites

Before you begin, make sure you have:

* A basic understanding of how the SDK works from the [Getting Started Guide](/developers/discord-social-sdk/getting-started)
* A basic understanding of your game's communication features
* Familiarity with [provisional accounts](/developers/discord-social-sdk/development-guides/provisional-accounts/overview)
* Reviewed the [Discord Social SDK Terms](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms)

## Your Moderation Responsibilities

### Moderation on Discord

[Discord's Community Guidelines](https://discord.com/guidelines) and [Terms of Service](https://discord.com/terms) apply to any content that is rendered on Discord, including:

* Text messages, audio, and video sent within Discord's platform
* Text messages that are appear on Discord (such as in DMs or Linked Channels) after being sent by players in your game (whether they have linked their Discord account or are using a provisional account)

Discord can take various actions against such content on Discord for violating its terms or policies, including through Discord platform-wide account bans and restrictions. Actions against a player's Discord account will not affect their separate account in the game (see [below](#handling-users-with-banned-discord-accounts) for more details); however, if a player's Discord account is banned, they will no longer have access to the SDK features that require an account connection.

### Game Developer's Responsibility

Your terms and policies apply to the content in your game. You are responsible for:

* Ensuring you comply with the [Discord Social SDK Terms](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms)
* Creating game-specific content policies and enforcing them
* In-game content moderation for messages or audio within your game
* Implementing appropriate UIs for reporting and moderation; this includes providing players a way to report issues or violations of your policies and reviewing and taking appropriate action on such reports

<Warning>
  As a reminder, you are responsible for any third-party moderation toolkits or services you use for your game and will ensure you comply with any applicable terms and laws, including obtaining consents from players as necessary for processing their data using such moderation services.
</Warning>

## Server-Side Chat Moderation

Discord's moderation metadata API lets your backend evaluate messages and attach application scoped
`moderation_metadata` to them. The metadata is persisted by Discord and delivered to active game
sessions via realtime `GAME_DIRECT_MESSAGE_UPDATE` or `LOBBY_MESSAGE_UPDATE` [Webhook Events](/developers/events/webhook-events) — no polling required.
Metadata is never exposed to other applications and is not included in other API endpoints or Gateway events.

### How It Works

1. Your backend receives a webhook event when a message is created or updated.
2. Your moderation system evaluates the message and updates the `moderation_metadata` on the message via the Discord
   API to indicate what action should be taken (hide, blur, replace, etc.).
3. Discord persists the metadata and dispatches an update event to relevant game client participants via the Social SDK.
4. The Game client is notified of the update via [`Client::SetMessageUpdatedCallback`], and retrieves the
   [`MessageHandle::ModerationMetadata`] from specified [`MessageHandle`] in the firing callback, and renders the message accordingly.
5. If the message content is edited, Discord clears the moderation metadata before dispatching a new update,
   indicating the message needs to be re-moderated.

```mermaid theme={"system"}
sequenceDiagram
    participant User as Game Client
    participant SDK as Social SDK
    participant Discord as Discord
    participant Webhook as Game HTTP Server
    participant Mod as Moderation Service

    Note over User,Mod: DM Message Send & Moderation Flow

    User->>SDK: Client::SendUserMessage()
    SDK->>Discord: Sends message to be created
    Discord->>Discord: Stores message
    Discord->>SDK: Return message (unmoderated)
    SDK->>User: Client::SetMessageUpdatedCallback() fires<br/>MessageHandle.ModerationMetadata() = {}
    Note left of User: Optional: Display message<br/>with pending moderation,<br/>or wait for moderation metadata<br/>to be populated.

    Discord->>Webhook: HTTP POST: GAME_DIRECT_MESSAGE_CREATE
    Note right of Webhook: Webhook event via HTTP<br/>Contains message content,<br/>IDs, author info

    Webhook-->>Discord: HTTP 204 (acknowledge)

    Webhook->>Mod: Process message for moderation
    Note right of Mod: Apply moderation rules<br/>(toxicity check, filters, etc.)

    Mod->>Webhook: Return moderation result
    Note right of Mod: e.g., action: "hide"<br/>reason: "toxicity"<br/>rewritten: "censored text"

    Webhook->>Discord: PUT /partner-sdk/dms/{user_id_1}/{user_id_2}/messages/{message_id}/moderation-metadata
    Note right of Webhook: Attach moderation metadata<br/>as key-value pairs

    Discord->>Discord: Update message.moderation_metadata

    Discord->>SDK: Dispatch update with moderation_metadata
    Note left of Discord: No webhook event fired

    SDK->>User: MessageHandle.ModerationMetadata()<br/>has moderation data
    Note left of User: Read MessageHandle.ModerationMetadata()<br/>Render based on action (hide/show/censor)

    Note over User,Mod: Message Edit Flow

    User->>SDK: Client::EditUserMessage()
    SDK->>Discord: Sends updated message
    Discord->>Discord: Clear moderation_metadata
    Note right of Discord: Stale moderation cleared

    Discord->>SDK: Return updated message (unmoderated)
    SDK->>User: Client::SetMessageUpdatedCallback() fires<br/>MessageHandle.ModerationMetadata() = {}
    Note left of User: Optional: Display edited message<br/>with pending moderation,<br/>or wait for moderation metadata<br/>to be re-populated.

    Discord->>Webhook: HTTP POST: GAME_DIRECT_MESSAGE_UPDATE
    Webhook-->>Discord: HTTP 204 (acknowledge)
    Webhook->>Mod: Re-moderate new content
    Mod->>Webhook: New moderation result
    Webhook->>Discord: PUT /partner-sdk/dms/{user_id_1}/{user_id_2}/messages/{message_id}/moderation-metadata
    Discord->>Discord: Update with new metadata
    Discord->>SDK: Dispatch update with new moderation_metadata
    SDK->>User: SetMessageUpdatedCallback fires<br/>MessageHandle.ModerationMetadata()<br/>has new moderation data
    Note left of User: Read metadata map<br/>Render based on action<br/>(hide/show/censor)
```

<Info>
  While this sequence diagram demonstrates moderation for direct messaging, the same flow applies to lobby messages.
  See below for the appropriate Social SDK methods, Webhook Event types and API paths to use instead.
</Info>

### Webhook Events

The first thing you will need to do is [subscribe to the following events](/developers/events/webhook-events#subscribing-to-events)
on your app's webhook to receive messages for moderation:

| Event                        | Description                                          |
| ---------------------------- | ---------------------------------------------------- |
| `GAME_DIRECT_MESSAGE_CREATE` | Fired when a DM is created in a Social SDK session   |
| `GAME_DIRECT_MESSAGE_UPDATE` | Fired when a DM is updated (content edit)            |
| `LOBBY_MESSAGE_CREATE`       | Fired when a message is created in a lobby           |
| `LOBBY_MESSAGE_UPDATE`       | Fired when a lobby message is updated (content edit) |

See the [Webhook Events reference](/developers/events/webhook-events) for full event schemas.

<Info>
  Metadata-only updates do **not** fire webhook events — they are delivered only via realtime SDK
  callbacks to active game sessions.
</Info>

### Applying Moderation Decisions

Once your moderation backend receives and evaluates a message, apply the decision by updating the `moderation_metadata`
on the message to indicate what action the game client should take with the content.

#### DM Messages

`user_id_1` and `user_id_2` are the two DM participants; order does not matter.

```python theme={"system"}
import requests

API_ENDPOINT = 'https://discord.com/api/v10'
BOT_TOKEN = 'YOUR_BOT_TOKEN'

def apply_dm_moderation(user_id_1, user_id_2, message_id, metadata):
  r = requests.put(
    f'{API_ENDPOINT}/partner-sdk/dms/{user_id_1}/{user_id_2}/messages/{message_id}/moderation-metadata',
    headers={
      'Authorization': f'Bot {BOT_TOKEN}',
      'Content-Type': 'application/json',
    },
    json=metadata
  )
  r.raise_for_status()

# Instruct the client to hide this message — moderation service flagged it as toxic
metadata = {
  'action': 'hide',   # client will not render this message
  'reason': 'toxicity',  # logged by the client for reporting purposes
}
apply_dm_moderation(user_id_1, user_id_2, message_id, metadata)

# Alternatively, instruct the client to show this message — moderation service approved it
metadata = {
  'action': 'show',  # client will render the message normally
}
apply_dm_moderation(user_id_1, user_id_2, message_id, metadata)
```

#### Lobby Messages

```python theme={"system"}
import requests

API_ENDPOINT = 'https://discord.com/api/v10'
BOT_TOKEN = 'YOUR_BOT_TOKEN'

def apply_lobby_moderation(lobby_id, message_id, metadata):
  r = requests.put(
    f'{API_ENDPOINT}/lobbies/{lobby_id}/messages/{message_id}/moderation-metadata',
    headers={
      'Authorization': f'Bot {BOT_TOKEN}',
      'Content-Type': 'application/json',
    },
    json=metadata
  )
  r.raise_for_status()

# Instruct the client to replace the message content with a policy reminder
metadata = {
  'action': 'replace',  # client will display replacement text instead of the original
  'replacement': 'Be kind to others!',  # the text the client will render in place of the message
}
apply_lobby_moderation(lobby_id, message_id, metadata)
```

<Info>
  Both endpoints return `HTTP 204: No Content` on success.
</Info>

### Moderation Metadata Fields

The metadata body is a free-form key–value map. Use any keys your client understands.
Some common conventions might include:

| Key           | Example values                    | Purpose                                         |
| ------------- | --------------------------------- | ----------------------------------------------- |
| `action`      | `hide`, `show`, `blur`, `replace` | How the client should render the message        |
| `reason`      | `toxicity`, `spam`                | Why the action was taken (useful for logging)   |
| `replacement` | any string                        | Text to display instead of the original message |
| `severity`    | `low`, `medium`, `high`           | Optional severity classification                |

**Limits:** Up to 5 keys per message; key length ≤ 1024 characters; value length ≤ 2000 characters (the maximum
Discord message length, so values can contain modified message content).

<Info>
  Moderation metadata is application scoped — only your application can read it, even for messages that are visible in
  Discord.
</Info>

### Handling Moderation Metadata on the Client

Register [`Client::SetMessageUpdatedCallback`] to receive metadata updates. Access the metadata
through [`MessageHandle::ModerationMetadata`], which returns the key–value map written by your backend.

```cpp theme={"system"}
client->SetMessageUpdatedCallback([&client](uint64_t messageId) {
    if (auto message = client->GetMessageHandle(messageId)) {
        auto metadata = message->ModerationMetadata();
        if (metadata.empty()) {
            // No moderation decision yet — render as pending, normally, or hide completely,
            // depending on your moderation requirements
            renderPendingModeration(message);
            return;
        }
        auto action = metadata.count("action") ? metadata.at("action") : "show";
        if (action == "hide") {
            hideMessage(messageId);
        } else if (action == "show") {
            renderMessage(message);
        } else if (action == "replace") {
            renderMessage(messageId, metadata.at("replacement"));
        } else if (action == "blur") {
            renderBlurred(message);
        } else {
            std::cerr << "Unknown moderation action: " << action << "\n";
            renderMessage(message);  // fall back to rendering normally
        }
    }
});
```

<Info>
  While moderation is in progress, consider not rendering new messages, or rendering in a "pending moderation"
  state to avoid briefly displaying unmoderated content.
</Info>

### Handling Content Edits

When a message is edited, Discord automatically clears the stored `moderation_metadata` and
dispatches a new update notification for the message.

The [`Client::SetMessageUpdatedCallback`] will fire with an empty metadata map for the edited message, and
your backend will receive a `GAME_DIRECT_MESSAGE_UPDATE` or `LOBBY_MESSAGE_UPDATE` webhook
event for the edit, which you can use to trigger re-moderation of the new content.

<Info>
  While re-moderation is in progress, consider not rendering the new, updated message, or rendering in a "pending
  moderation" state to avoid briefly displaying unmoderated content.
</Info>

## Handling Users with Banned Discord Accounts

### Discord Platform Bans

When a player's Discord account is banned by Discord — whether temporarily or permanently — they will no longer be able to authenticate to your app via Discord, their existing [`Client`] is disconnected, their OAuth2 tokens are invalidated, and an [`APPLICATION_DEAUTHORIZED`](/developers/events/webhook-events#application-deauthorized) webhook is fired.

A ban is mechanically an [unmerge](/developers/discord-social-sdk/development-guides/provisional-accounts/unmerging-accounts#unmerging-provisional-accounts) that Discord initiates — the OAuth2 tokens are deleted and a new cross-platform-restricted provisional account takes the place of the linked Discord identity.
For the full lifecycle see [Ban-Driven Unmerge](/developers/discord-social-sdk/development-guides/provisional-accounts/unmerging-accounts#ban-driven-unmerge) in the Provisional Accounts guide. For the auth-side observable signals and recommended integration architecture, see [Out-of-Band Revocation](/developers/discord-social-sdk/development-guides/account-linking-with-discord#out-of-band-revocation) in the Account Linking guide.

### Discord Server Bans

If you wish to tie your in-game moderation policies to a specific Discord server that you own, such as your official community server, you are able to retrieve ban information for your Discord Server via our REST APIs.

See the references for the REST endpoints[`{guild.id}/guilds/{guild.id}/bans`](/developers/resources/guild#get-guild-bans)
or [`/guilds/{guild.id}/bans/{user.id}`](/developers/resources/guild#get-guild-ban)
for more information on retrieving all bans for your guild, or ban information for a specific user within your guild.

## Voice Chat Moderation

The Discord Social SDK provides access to audio streams for in-game voice calls, allowing you to implement audio
moderation for your game's voice chat functionality. The data for the call is available through
[`Client::StartCallWithAudioCallbacks`], and can be passed to your voice moderation system.

```cpp theme={"system"}
// Example: Capturing local voice chat audio for asynchronous moderation.

// Callback for local users' audio with moderation
auto capturedCallback = [](int16_t const* data,
                     uint64_t samplesPerChannel, int32_t sampleRate,
                     uint64_t channels) {
    // Call the moderation function
    moderateCapturedVoice(data, samplesPerChannel);
};

// Start the call with our moderation callback
auto call = client->StartCallWithAudioCallbacks(lobbyId, receivedCallback, capturedCallback);
```

***

## Next Steps

<CardGroup cols={3}>
  <Card title="Sending Direct Messages" href="/developers/discord-social-sdk/development-guides/sending-direct-messages" icon={<ChatIcon/>}>
    Enable private messaging between players.
  </Card>

  <Card title="Managing Voice Chat" href="/developers/discord-social-sdk/development-guides/managing-voice-chat" icon={<VoiceNormalIcon/>}>
    Add in-game voice communication.
  </Card>

  <Card title="Linked Channels" href="/developers/discord-social-sdk/development-guides/linked-channels" icon={<TextControllerIcon/>}>
    Connect game lobbies to Discord text channels.
  </Card>
</CardGroup>

Need help? Join the [Discord Developers Server](https://discord.gg/discord-developers) and share questions in the `#social-sdk-dev-help` channel for support from the community.

If you encounter a bug while working with the Social SDK, please report it here:  [https://dis.gd/social-sdk-bug-report](https://dis.gd/social-sdk-bug-report)

***

## Change Log

| Date         | Changes                                                                     |
| ------------ | --------------------------------------------------------------------------- |
| May 22, 2026 | Move platform-ban lifecycle details to the Account Linking guide            |
| Feb 20, 2026 | Replaced client-side message moderation with server-side message moderation |
| May 22, 2025 | initial release                                                             |

[`Client`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a91716140c699d8ef0bdf6bfd7ee0ae13

[`Client::SetMessageUpdatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#aa01cf3c15403f29780dabfcfaf3b1dcd

[`Client::StartCallWithAudioCallbacks`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#abcaa891769f9e912bfa0e06ff7221b05

[`MessageHandle`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1MessageHandle.html#ae25595b43bc74b0c4c92c5165d16382f

[`MessageHandle::ModerationMetadata`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1MessageHandle.html#afb9ae126f6b1f0de006f2be8e3688205
