From 49032840acfe29e1e29dbf356e5f0fa4a2e9dad2 Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Tue, 13 Jan 2026 17:50:21 +0530 Subject: [PATCH 1/9] docs(moderation): restructure flagged messages documentation with comprehensive guides - Restructure flagged messages overview with improved clarity and visual flow diagrams - Add mermaid flowchart illustrating the message flagging workflow and moderation process - Create comparison tables for Dashboard vs REST API access methods - Reorganize flagging methods into clear sections: manual flagging and automatic rule engine flagging - Add accordion sections linking to UI Kit and SDK implementations for report message feature - Enhance manual flagging section with details on configurable flag reasons - Improve automatic flagging explanation with practical examples - Update gitignore to exclude MCP settings file - Expand documentation with better navigation and cross-references to related APIs and features --- .gitignore | 1 + moderation/flagged-messages.mdx | 121 ++++++++-- moderation/overview.mdx | 222 ++++++++++++----- sdk/javascript/ai-moderation.mdx | 400 +++++++++++++++++++++++++------ ui-kit/react/core-features.mdx | 16 ++ 5 files changed, 621 insertions(+), 139 deletions(-) diff --git a/.gitignore b/.gitignore index e6aff516..ea37644a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store +.kiro/settings/mcp.json diff --git a/moderation/flagged-messages.mdx b/moderation/flagged-messages.mdx index fad279ed..ce44a8fe 100644 --- a/moderation/flagged-messages.mdx +++ b/moderation/flagged-messages.mdx @@ -4,68 +4,157 @@ title: "Flagged Messages" ## Overview -The Flagged Messages endpoint in the Moderation Service API enables app owners and collaborators to review messages that have been flagged for potentially violating moderation rules. Messages can be flagged automatically by the rule engine based on predefined rules, or manually by end users who find certain content inappropriate or concerning. +The Flagged Messages feature in CometChat's Moderation Service enables app owners and collaborators to review messages that have been flagged for potentially violating moderation rules. Messages can be flagged automatically by the rule engine based on predefined rules, or manually by end users who find certain content inappropriate or concerning. -When a message is flagged, it becomes visible in the CometChat Dashboard under the flagged messages section. Moderators can then review these flagged messages and take one of two actions: +When a message is flagged, it becomes visible in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages**. Moderators can then review these flagged messages and take one of two actions: 1. **Approve** - The message is deemed acceptable and the moderation status remains approved 2. **Block** - The message violates platform policies and the moderation status is changed to disapproved Once either action is taken, the message is automatically moved to the Reviewed list, which contains all messages that have been reviewed by moderators. -#### Manual Flagging by End Users +## How It Works + +```mermaid +flowchart LR + A[Message Sent] --> B{Flagging} + B --> C[Manual Flag by User] + B --> D[Auto Flag by Rule Engine] + C --> E[Review Queue] + D --> E + E --> F{Moderator Action} + F --> G[Approve] + F --> H[Block] + G --> I[Reviewed List] + H --> I +``` + +| Step | Description | +|------|-------------| +| 1. Message Sent | A user sends a message in a conversation | +| 2. Flagging | Message is flagged either manually by users or automatically by the rule engine | +| 3. Review Queue | Flagged message appears in the Dashboard for moderator review | +| 4. Moderator Action | Moderator reviews and either approves or blocks the message | +| 5. Reviewed List | Message moves to the reviewed list with its final status | + +## Dashboard vs REST API + +You can manage flagged messages through either the Dashboard or REST API: + +| Action | Dashboard | REST API | +|--------|-----------|----------| +| List flagged messages | **Moderation > Flagged Messages** | [List Flagged Messages API](/rest-api/moderation/list-flagged-messages) | +| Approve message | Click "Approve" button | [Approve/Block API](/rest-api/moderation/blockreview-flagged-message) | +| Block message | Click "Block" button | [Approve/Block API](/rest-api/moderation/blockreview-flagged-message) | +| Flag a message | - | [Flag Message API](/rest-api/moderation/flag-a-message) | +| Configure flag reasons | **Moderation > Advanced Settings** | [Reason APIs](/rest-api/moderation/create-reasons) | + +## Flagging Methods + +### Manual Flagging by End Users + +End users can manually flag messages they find inappropriate or concerning by selecting from a predefined list of reasons. These flag reasons are configurable through the CometChat Dashboard, where you can either use the default options or create custom flagging reasons tailored to your platform's needs. -End users can manually flag messages they find inappropriate or concerning by selecting from a predefined list of reasons. These flag reasons are configurable through the CometChat Dashboard, where you can either use the default options or create custom flagging reasons tailored to your platform's needs. Once configured, these reasons will appear in the user interface, allowing users to select the most appropriate reason when reporting a message. -Messages can also be flagged via [Flag Message API](/rest-api/moderation/flag-a-message) -#### Automatic Flagging by Rule Engine +Once configured, these reasons will appear in the user interface, allowing users to select the most appropriate reason when reporting a message. + +Messages can also be flagged programmatically via the [Flag Message API](/rest-api/moderation/flag-a-message). + + +The Report Message feature is available in CometChat UI Kits. Users can report messages directly from the message actions menu: + + + } href="/ui-kit/react/core-features#report-message" horizontal /> + } href="/ui-kit/react-native/core-features" horizontal /> + } href="/ui-kit/android/core-features" horizontal /> + } href="/ui-kit/ios/core-features" horizontal /> + } href="/ui-kit/flutter/core-features" horizontal /> + } href="/ui-kit/angular/core-features" horizontal /> + } href="/ui-kit/vue/overview" horizontal /> + + + + +You can implement message flagging directly using CometChat Chat SDKs: + + + } href="/sdk/javascript/flag-message" horizontal /> + } href="/sdk/react-native/flag-message" horizontal /> + } href="/sdk/android/flag-message" horizontal /> + } href="/sdk/ios/flag-message" horizontal /> + } href="/sdk/flutter/flag-message" horizontal /> + + + +### Automatic Flagging by Rule Engine Messages can be automatically flagged when they violate predefined moderation rules. When setting up moderation rules in the Dashboard, you can configure the action to "flag" messages that match specific criteria. This ensures that potentially problematic content is automatically identified and queued for review without requiring manual intervention from users. -For e.g. if the message contains any profane words, then it would be automatically flagged. + +For example, if a message contains profane words, it would be automatically flagged. + -#### Configuring Flag Reasons +### Configuring Flag Reasons + +You can customize the flagging reasons available to end users through the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Advanced Settings**. The platform provides a set of default flagging reasons that cover common moderation scenarios, or you can create custom reasons that align with your platform's specific community guidelines and policies. -You can customize the flagging reasons available to end users through the CometChat Dashboard. The platform provides a set of default flagging reasons that cover common moderation scenarios, or you can create custom reasons that align with your platform's specific community guidelines and policies. These configuration options are accessible through the Advanced Settings within the Moderation section of your dashboard. -Flag reasons can be also be configured via REST APIs [Reason APIs](/rest-api/moderation/create-reasons). + +Flag reasons can also be configured via the [Reason APIs](/rest-api/moderation/create-reasons). + +## Managing Flagged Messages ### List Flagged Messages -Retrieves the list of messages that have been flagged by the moderation system or manually by moderators. +Retrieves the list of messages that have been flagged by the moderation system or manually by users. + -You can also set this up from your end using the [List Flagged Messages REST API](/rest-api/moderation/list-flagged-messages). +**REST API:** [List Flagged Messages](/rest-api/moderation/list-flagged-messages) --- ### Approve Flagged Message -Allows the approval of messages that were previously flagged. Approving a flagged message indicates that it has been reviewed and is considered acceptable according to platform guidelines. +Approving a flagged message indicates that it has been reviewed and is considered acceptable according to platform guidelines. The message remains visible to all users. -You can also set this up from your end using the [Approve Flagged Message REST API](/rest-api/moderation/blockreview-flagged-message). +**REST API:** [Approve/Block Flagged Message](/rest-api/moderation/blockreview-flagged-message) --- ### Block Flagged Message -Allows the blocking of messages that were flagged. Blocking a flagged message will automatically mark it as reviewed. +Blocking a flagged message marks it as disapproved and moves it to the reviewed list. Blocked messages are hidden from the conversation and are no longer visible to users. -You can also set this up from your end using the [Block Flagged Message REST API](/rest-api/moderation/blockreview-flagged-message). +**REST API:** [Approve/Block Flagged Message](/rest-api/moderation/blockreview-flagged-message) + +## Frequently Asked Questions + + + + Blocked messages are hidden from the conversation and are no longer visible to users. The message is marked as disapproved and moved to the Reviewed list in the Dashboard. + + + By default, users are not notified when their message is blocked. The message simply becomes hidden from the conversation. + + + Yes, the Dashboard supports bulk actions. You can select multiple flagged messages and approve or block them in a single action. + + diff --git a/moderation/overview.mdx b/moderation/overview.mdx index 382e9d27..152b92dc 100644 --- a/moderation/overview.mdx +++ b/moderation/overview.mdx @@ -2,82 +2,192 @@ title: "Overview" --- -The Moderation feature provides a comprehensive suite of capabilities designed to manage and enforce message moderation rules across various types of messages, ensuring your platform remains safe and compliant for all users. These capabilities include rule management for creating, updating, and deleting moderation rules, as well as keyword lists for detecting inappropriate content. Additionally, automated actions promptly address potential violations, and detailed reports on blocked messages help to continuously improve safety and compliance measures. By leveraging these robust functionalities, you can effectively maintain a secure and welcoming environment on your platform. +The Moderation feature provides a comprehensive suite of capabilities designed to manage and enforce message moderation rules across various types of messages, ensuring your platform remains safe and compliant for all users. + +## Key Benefits + +- **Automated Content Filtering** - Automatically detect and handle inappropriate content before it reaches users +- **Customizable Rules** - Create rules tailored to your platform's specific community guidelines +- **Multi-format Support** - Moderate text messages, images, and videos +- **Real-time Protection** - Messages are moderated instantly as they are sent +- **Manual Review** - Users can report content, and moderators can review flagged messages + +## How It Works + +```mermaid +flowchart LR + A[Message Sent] --> B{Moderation Rules} + B -->|Pass| C[Message Delivered] + B -->|Violation| D{Action} + D --> E[Block] + D --> F[Flag for Review] + E --> G[Blocked Messages] + F --> H[Flagged Messages] + H --> I{Moderator Review} + I --> J[Approve] + I --> K[Block] +``` + +## Quick Navigation + + + + Create and manage moderation rules to detect inappropriate content + + + Manage keyword lists and regex patterns for content filtering + + + Review messages flagged by users or the rule engine + + + View messages that were blocked due to rule violations + + + +## Getting Started + + + + Navigate to the [CometChat Dashboard](https://app.cometchat.com) and go to **Moderation** section + + + Set up rules to automatically detect and handle inappropriate content. See [Rules Management](/moderation/rules-management) + + + Customize the reasons users can select when reporting messages. Go to **Moderation > Advanced Settings** + + + Enable moderation features in your UI Kit or implement using the SDK/REST API + + + +## Platform Integration + +Moderation is supported across all CometChat platforms. Choose your integration method: + +### UI Kits + +UI Kits provide built-in support for message moderation and the Report Message feature: + + + } href="/ui-kit/react/core-features#message-moderation" horizontal /> + } href="/ui-kit/react-native/core-features" horizontal /> + } href="/ui-kit/android/core-features" horizontal /> + } href="/ui-kit/ios/core-features" horizontal /> + } href="/ui-kit/flutter/core-features" horizontal /> + } href="/ui-kit/angular/core-features" horizontal /> + } href="/ui-kit/vue/overview" horizontal /> + + +### Chat SDKs + +Implement message flagging directly using CometChat Chat SDKs: + + + } href="/sdk/javascript/flag-message" horizontal /> + } href="/sdk/react-native/flag-message" horizontal /> + } href="/sdk/android/flag-message" horizontal /> + } href="/sdk/ios/flag-message" horizontal /> + } href="/sdk/flutter/flag-message" horizontal /> + + +### REST API + +For server-side integration and advanced moderation workflows: + + + + + + + + + + +## Dashboard vs REST API + +| Feature | Dashboard | REST API | +|---------|-----------|----------| +| Create/manage rules | ✅ **Moderation > Rules** | [Rules API](/rest-api/moderation/create-rule) | +| Create/manage keyword lists | ✅ **Moderation > Lists** | [Lists API](/rest-api/moderation/create-list) | +| Review flagged messages | ✅ **Moderation > Flagged Messages** | [Flagged Messages API](/rest-api/moderation/list-flagged-messages) | +| View blocked messages | ✅ **Moderation > Blocked Messages** | [Blocked Messages API](/rest-api/moderation/list-blocked-messages) | +| Approve/block messages | ✅ Click action buttons | [Review API](/rest-api/moderation/blockreview-flagged-message) | +| Configure flag reasons | ✅ **Moderation > Advanced Settings** | [Reasons API](/rest-api/moderation/create-reasons) | -import { Steps } from 'mintlify'; - -Here’s an in-depth look at the key functionalities provided by the Moderation Service: +--- ## Rules Management This feature enables you to define and manage a set of moderation rules tailored to address inappropriate messages under various conditions. You can establish specific criteria that determine what constitutes unacceptable behavior or content, such as the use of offensive language, unsafe content, or sharing sensitive information. -By customizing these rules, you ensure that the moderation system effectively identifies and manages messages that violate your platform's standards, thereby maintaining a safe and respectful environment for all users. The ability to manage these rules includes adding new rules, updating existing ones, and removing obsolete rules, providing a flexible and dynamic approach to message moderation. +By customizing these rules, you ensure that the moderation system effectively identifies and manages messages that violate your platform's standards, thereby maintaining a safe and respectful environment for all users. -For more detailed management, refer to the [rules management](/moderation/rules-management) section. +For more detailed management, refer to the [Rules Management](/moderation/rules-management) section. ## Lists Management -This feature allows you to create and manage comprehensive lists of keywords or regex patterns that are used for message moderation. These lists serve as a vital component in identifying and handling inappropriate content. You can customize these lists to include specific terms and patterns that are relevant to your platform's moderation needs. +This feature allows you to create and manage comprehensive lists of keywords or regex patterns that are used for message moderation. These lists serve as a vital component in identifying and handling inappropriate content. -Once created, these keyword lists can be linked to various moderation rules when creating or updating rules, ensuring that the moderation system effectively detects and manages content that violates your standards. The ability to manage these lists includes adding new keywords or patterns or sentences, updating existing ones, and removing those that are no longer relevant, providing a flexible and responsive approach to message moderation. +Once created, these keyword lists can be linked to various moderation rules when creating or updating rules, ensuring that the moderation system effectively detects and manages content that violates your standards. -For more detailed management, refer to the [lists management](/moderation/lists-management) section. +For more detailed management, refer to the [Lists Management](/moderation/lists-management) section. ## Flagged Messages -This feature enables you to access and manage all messages that require moderation review. You can view a complete list of messages that have been automatically flagged by the rule engine for policy violations or manually reported by users for inappropriate content. The system provides filtering to narrow down results using date ranges. +This feature enables you to access and manage all messages that require moderation review. You can view a complete list of messages that have been automatically flagged by the rule engine for policy violations or manually reported by users for inappropriate content. For more details, refer to the [Flagged Messages](/moderation/flagged-messages) section. ## Blocked Messages -This feature allows you to retrieve all the violated messages. You can retrieve a comprehensive list of messages that have been blocked due to violations of moderation rules. Additionally, you can perform searches within this list to find specific messages or filter results based on date ranges and find details for the violation. This functionality helps you effectively monitor and manage inappropriate content, ensuring a safe and compliant environment on your platform. +This feature allows you to retrieve all the violated messages. You can retrieve a comprehensive list of messages that have been blocked due to violations of moderation rules. Additionally, you can perform searches within this list to find specific messages or filter results based on date ranges. For more details, refer to the [Blocked Messages](/moderation/blocked-messages) section. -*** - -## Overview of Moderation Rules - -Our platform offers a wide range of moderation rules to help you detect and manage various types of risky, sensitive, or inappropriate content. Below is an overview of the available rules categorized by content type: - -### 🚩 Message Moderation Rules - -| Name | Description | -|------|-------------| -| **Word Pattern Match** | Identifies profane or offensive words using word matching. | -| **Contact Details Removal** | Detects and removes phone numbers from text. | -| **Email Detection** | Detects and removes email addresses from messages. | -| **Spam Detection (English)** | Detects spam messages in English. | -| **Scam Detection (English)** | Detects scam or fraudulent text in English. | -| **Platform Circumvention (English)** | Identifies attempts to bypass platform rules. | -| **Toxicity Detection (English)** | Detects toxic or harmful language in text. | -| **Explicit or Inappropriate Content Prompt** | Detects explicit sexual descriptions, graphic violence, or other unsuitable text. | -| **Privacy and Sensitive Info Prompt** | Identifies sensitive personal information shared without consent. | -| **Hate and Harassment Prompt** | Detects hateful or harassing language toward individuals or groups. | -| **Self-Harm or Suicidal Content Prompt** | Detects content suggesting self-harm or suicidal thoughts. | -| **Impersonation or Fraud Prompt** | Detects deceptive attempts to impersonate individuals or organizations. | -| **Violent or Terroristic Threats Prompt** | Detects content promoting violence or extremism. | -| **Non-Consensual Sexual Content Prompt** | Detects sexual exploitation, grooming, or non-consensual content. | -| **Spam and Scam Prompt** | Identifies spam, phishing attempts, and fraudulent schemes. | - -### 🖼️ Image Moderation Rules - -| Name | Description | -|------|-------------| -| **Unsafe & Prohibited Content** | Detects unsafe or prohibited content in images. | -| **Terrorism or Extremist Promotion Prompt** | Detects extremist propaganda, terrorist symbols, or images promoting violent ideologies. | -| **Minor Safety and Exploitation Prompt** | Detects child sexual content or exploitative imagery of minors. | -| **Self-Harm or Suicidal Content Prompt** | Detects imagery suggesting self-harm or suicidal ideation. | -| **Privacy or Personal Data Prompt** | Identifies images containing personal or sensitive data. | -| **Graphic Violence or Gore Prompt** | Detects images of extreme violence or gore. | -| **Explicit or Sexual Content Prompt** | Identifies nudity, explicit sexual content, or suggestive imagery. | -| **Hate or Harassment Prompt** | Detects hate symbols, harassment, or extremist imagery. | -| **Fraud or Scam Indicators Prompt** | Flags manipulated or fraudulent images, such as fake IDs. | - -### 🎥 Video Moderation Rules - -| Name | Description | -|------|-------------| -| **Unsafe & Prohibited Content** | Detects unsafe or prohibited content in video files. | +--- + +## Available Moderation Rules + +Our platform offers a wide range of moderation rules to help you detect and manage various types of risky, sensitive, or inappropriate content. + + + + | Name | Description | + |------|-------------| + | **Word Pattern Match** | Identifies profane or offensive words using word matching | + | **Contact Details Removal** | Detects and removes phone numbers from text | + | **Email Detection** | Detects and removes email addresses from messages | + | **Spam Detection (English)** | Detects spam messages in English | + | **Scam Detection (English)** | Detects scam or fraudulent text in English | + | **Platform Circumvention (English)** | Identifies attempts to bypass platform rules | + | **Toxicity Detection (English)** | Detects toxic or harmful language in text | + | **Explicit or Inappropriate Content** | Detects explicit sexual descriptions, graphic violence, or unsuitable text | + | **Privacy and Sensitive Info** | Identifies sensitive personal information shared without consent | + | **Hate and Harassment** | Detects hateful or harassing language toward individuals or groups | + | **Self-Harm or Suicidal Content** | Detects content suggesting self-harm or suicidal thoughts | + | **Impersonation or Fraud** | Detects deceptive attempts to impersonate individuals or organizations | + | **Violent or Terroristic Threats** | Detects content promoting violence or extremism | + | **Non-Consensual Sexual Content** | Detects sexual exploitation, grooming, or non-consensual content | + | **Spam and Scam** | Identifies spam, phishing attempts, and fraudulent schemes | + + + | Name | Description | + |------|-------------| + | **Unsafe & Prohibited Content** | Detects unsafe or prohibited content in images | + | **Terrorism or Extremist Promotion** | Detects extremist propaganda, terrorist symbols, or violent ideologies | + | **Minor Safety and Exploitation** | Detects child sexual content or exploitative imagery of minors | + | **Self-Harm or Suicidal Content** | Detects imagery suggesting self-harm or suicidal ideation | + | **Privacy or Personal Data** | Identifies images containing personal or sensitive data | + | **Graphic Violence or Gore** | Detects images of extreme violence or gore | + | **Explicit or Sexual Content** | Identifies nudity, explicit sexual content, or suggestive imagery | + | **Hate or Harassment** | Detects hate symbols, harassment, or extremist imagery | + | **Fraud or Scam Indicators** | Flags manipulated or fraudulent images, such as fake IDs | + + + | Name | Description | + |------|-------------| + | **Unsafe & Prohibited Content** | Detects unsafe or prohibited content in video files | + + diff --git a/sdk/javascript/ai-moderation.mdx b/sdk/javascript/ai-moderation.mdx index 0818d929..de77652e 100644 --- a/sdk/javascript/ai-moderation.mdx +++ b/sdk/javascript/ai-moderation.mdx @@ -2,85 +2,351 @@ title: "AI Moderation" --- -# Overview +## Overview AI Moderation in the CometChat SDK helps ensure that your chat application remains safe and compliant by automatically reviewing messages for inappropriate content. This feature leverages AI to moderate messages in real-time, reducing manual intervention and improving user experience. -For a broader understanding of moderation features, see the [Moderation Overview](../../moderation/overview). + +For a broader understanding of moderation features, configuring rules, and managing flagged messages, see the [Moderation Overview](/moderation/overview). + -# What Triggers Moderation? +## Prerequisites + +Before using AI Moderation, ensure the following: + +1. Moderation is enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Moderation rules are configured under **Moderation > Rules** +3. You're using CometChat SDK version that supports moderation + +## How It Works + +```mermaid +sequenceDiagram + participant App + participant SDK + participant CometChat + participant Moderation + + App->>SDK: sendMessage() + SDK->>CometChat: Send Message + CometChat->>Moderation: Process Message + CometChat-->>SDK: Message (status: PENDING) + SDK-->>App: onMessageSent (PENDING) + Moderation-->>CometChat: Moderation Result + CometChat-->>SDK: onMessageModerated + SDK-->>App: APPROVED or DISAPPROVED +``` + +| Step | Description | +|------|-------------| +| 1. Send Message | App sends a text, image, or video message | +| 2. Pending Status | Message is sent with `PENDING` moderation status | +| 3. AI Processing | Moderation service analyzes the content | +| 4. Result Event | `onMessageModerated` event fires with final status | + +## Supported Message Types Moderation is triggered **only** for the following message types: -- Text Messages -- Image Messages -- Video Messages +| Message Type | Moderated | Notes | +|--------------|-----------|-------| +| Text Messages | ✅ | Content analyzed for inappropriate text | +| Image Messages | ✅ | Images scanned for unsafe content | +| Video Messages | ✅ | Videos analyzed for prohibited content | +| Custom Messages | ❌ | Not subject to AI moderation | +| Action Messages | ❌ | Not subject to AI moderation | -Other message types are not subject to AI moderation. +## Moderation Status -# Handling Message Moderation Status +The `getModerationStatus()` method returns one of the following values: -When sending text, image, or video messages, the moderation process introduces the following changes to the message flow: +| Status | Enum Value | Description | +|--------|------------|-------------| +| Pending | `CometChat.ModerationStatus.PENDING` | Message is being processed by moderation | +| Approved | `CometChat.ModerationStatus.APPROVED` | Message passed moderation and is visible | +| Disapproved | `CometChat.ModerationStatus.DISAPPROVED` | Message violated rules and was blocked | -1. **Initial Status:** - - On successfully sending a text, image, or video message, the response will include the moderation status as `pending`. - - You can fetch this status using the `getModerationStatus()` method, which returns an Enum: `CometChat.ModerationStatus.PENDING`. +## Implementation -2. **Moderation Result Event:** - - Once the moderation service processes the message, a real-time event is triggered in your `MessageListener` as `onMessageModerated`. - - This event provides the message object with the updated moderation status, which will be either `CometChat.ModerationStatus.APPROVED` or `CometChat.ModerationStatus.DISAPPROVED`. +### Step 1: Send a Message and Check Initial Status -**Example:** +When you send a text, image, or video message, check the initial moderation status: - - ```js - // Check moderation status after sending a message. This check is only applicable for TextMessage & MediaMessage class. - const status = message.getModerationStatus(); - if (status === CometChat.ModerationStatus.PENDING) { - // Message is under moderation - } - - // Listen for moderation result - CometChat.addMessageListener( - 'UNIQUE_LISTENER_ID', - new CometChat.MessageListener({ - onMessageModerated: (message) => { - if (message instanceof CometChat.TextMessage || message instanceof CometChat.MediaMessage) { - if (message.getModerationStatus() === CometChat.ModerationStatus.APPROVED) { - // Message approved - } else if (message.getModerationStatus() === CometChat.ModerationStatus.DISAPPROVED) { - // Message disapproved - } - } - } - }) - ); - ``` - - - ```js - // Check moderation status after sending a message. This check is only applicable for TextMessage & MediaMessage class. - const status: string = message.getModerationStatus(); - if (status === CometChat.ModerationStatus.PENDING) { - // Message is under moderation - } - - // Listen for moderation result - CometChat.addMessageListener( - 'UNIQUE_LISTENER_ID', - new CometChat.MessageListener({ - onMessageModerated: (message: CometChat.BaseMessage) => { - if (message instanceof CometChat.TextMessage || message instanceof CometChat.MediaMessage) { - if (message.getModerationStatus() === CometChat.ModerationStatus.APPROVED) { - // Message approved - } else if (message.getModerationStatus() === CometChat.ModerationStatus.DISAPPROVED) { - // Message disapproved - } - } - } - }) - ); - ``` - - \ No newline at end of file + + ```javascript + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMessage(textMessage).then( + (message) => { + // Check moderation status + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + console.log("Message is under moderation review"); + // Show pending indicator in UI + } + }, + (error) => { + console.log("Message sending failed:", error); + } + ); + ``` + + + ```typescript + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMessage(textMessage).then( + (message: CometChat.TextMessage) => { + // Check moderation status + const status: string = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + console.log("Message is under moderation review"); + // Show pending indicator in UI + } + }, + (error: CometChat.CometChatException) => { + console.log("Message sending failed:", error); + } + ); + ``` + + + +### Step 2: Listen for Moderation Results + +Register a message listener to receive moderation results in real-time: + + + + ```javascript + const listenerID = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageModerated: (message) => { + if ( + message instanceof CometChat.TextMessage || + message instanceof CometChat.MediaMessage + ) { + const status = message.getModerationStatus(); + const messageId = message.getId(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + console.log(`Message ${messageId} approved`); + // Update UI to show message normally + break; + + case CometChat.ModerationStatus.DISAPPROVED: + console.log(`Message ${messageId} blocked`); + // Handle blocked message (hide or show warning) + handleDisapprovedMessage(message); + break; + } + } + } + }) + ); + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + ```typescript + const listenerID: string = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageModerated: (message: CometChat.BaseMessage) => { + if ( + message instanceof CometChat.TextMessage || + message instanceof CometChat.MediaMessage + ) { + const status: string = message.getModerationStatus(); + const messageId: number = message.getId(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + console.log(`Message ${messageId} approved`); + // Update UI to show message normally + break; + + case CometChat.ModerationStatus.DISAPPROVED: + console.log(`Message ${messageId} blocked`); + // Handle blocked message (hide or show warning) + handleDisapprovedMessage(message); + break; + } + } + } + }) + ); + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + +### Step 3: Handle Disapproved Messages + +When a message is disapproved, you should handle it appropriately in your UI: + +```javascript +function handleDisapprovedMessage(message) { + const messageId = message.getId(); + + // Option 1: Hide the message completely + hideMessageFromUI(messageId); + + // Option 2: Show a placeholder message + showBlockedPlaceholder(messageId, "This message was blocked by moderation"); + + // Option 3: Notify the sender (if it's their message) + if (message.getSender().getUid() === currentUserUID) { + showNotification("Your message was blocked due to policy violation"); + } +} +``` + +## Complete Example + +Here's a complete implementation showing the full moderation flow: + + + + ```javascript + class ModerationHandler { + constructor() { + this.pendingMessages = new Map(); + this.setupListener(); + } + + setupListener() { + CometChat.addMessageListener( + "MODERATION_LISTENER", + new CometChat.MessageListener({ + onMessageModerated: (message) => this.onModerated(message) + }) + ); + } + + async sendMessage(receiverUID, text) { + const textMessage = new CometChat.TextMessage( + receiverUID, + text, + CometChat.RECEIVER_TYPE.USER + ); + + try { + const message = await CometChat.sendMessage(textMessage); + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + // Track pending message + this.pendingMessages.set(message.getId(), message); + return { success: true, pending: true, message }; + } + + return { success: true, pending: false, message }; + } catch (error) { + return { success: false, error }; + } + } + + onModerated(message) { + const messageId = message.getId(); + const status = message.getModerationStatus(); + + // Remove from pending + this.pendingMessages.delete(messageId); + + // Emit event for UI update + this.emit("moderationResult", { + messageId, + status, + approved: status === CometChat.ModerationStatus.APPROVED, + message + }); + } + + cleanup() { + CometChat.removeMessageListener("MODERATION_LISTENER"); + } + } + + // Usage + const handler = new ModerationHandler(); + const result = await handler.sendMessage("user123", "Hello!"); + + if (result.pending) { + console.log("Message pending moderation..."); + } + ``` + + + +## Best Practices + + + + Display a visual indicator (like a clock icon or "Reviewing..." text) for messages with `PENDING` status so users know their message is being processed. + + + Don't just hide blocked messages silently. Inform the sender that their message couldn't be delivered due to content policy, without revealing specific details about what triggered the block. + + + Store the moderation status locally so you don't need to re-check when displaying message history. + + + Always remove message listeners when components unmount or when they're no longer needed to prevent memory leaks. + + + +## Related Features + + + + Allow users to manually report inappropriate messages + + + Configure moderation rules and manage flagged messages + + + Review and manage messages flagged by users or AI + + + Learn more about real-time message events + + + +## FAQ + + + + AI moderation typically processes messages within a few seconds. However, processing time may vary based on content type (images and videos take longer than text) and server load. + + + If the moderation service is temporarily unavailable, messages may remain in `PENDING` status longer than usual. The SDK will deliver the moderation result once the service processes the message. + + + The SDK doesn't provide a built-in appeal mechanism. However, you can implement a custom workflow using the [Flag Message](/sdk/javascript/flag-message) feature or by contacting your support team through the Dashboard. + + + No, AI moderation requires an active connection to CometChat servers. Messages sent while offline will be moderated when they're synced after reconnection. + + diff --git a/ui-kit/react/core-features.mdx b/ui-kit/react/core-features.mdx index 21a84129..a03304e0 100644 --- a/ui-kit/react/core-features.mdx +++ b/ui-kit/react/core-features.mdx @@ -155,10 +155,26 @@ The Threaded Conversations feature enables users to respond directly to a specif | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | [Threaded Message Preview](/ui-kit/react/threaded-message-preview) | [Threaded Message Preview](/ui-kit/react/threaded-message-preview) component displays the parent message along with the number of replies. | +## Message Moderation + +CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + +Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. + + +| Components | Functionality | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Message List](/ui-kit/react/message-list) | [Message List](/ui-kit/react/message-list) automatically handles moderated messages, displaying blocked content appropriately based on your moderation settings. | + ## Report Message The Report Message feature allows users to report inappropriate or harmful messages within the chat. Users can choose from predefined reasons and provide additional remarks for detailed context. This feature helps maintain a safe and respectful chat environment. + +Learn more about how flagged messages are handled, reviewed, and moderated in the [Flagged Messages](/moderation/flagged-messages) documentation. + + From e04e1e0123ab462cbe8d8f5e6b6bbbb6009104b4 Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Tue, 13 Jan 2026 19:14:36 +0530 Subject: [PATCH 2/9] docs(moderation): restructure AI moderation documentation and update navigation links - Add AI Moderation documentation for React Native SDK - Restructure AI Moderation guides across all SDKs (Android, iOS, Flutter, JavaScript, React Native) with comprehensive prerequisites and workflow diagrams - Update moderation overview to link to AI Moderation guides instead of flag-message guides - Add moderation section anchors to all UI Kit core-features documentation (React, React Native, Android, iOS, Flutter) - Remove REST API and Dashboard comparison sections from moderation overview for cleaner navigation - Update docs.json to include new React Native AI Moderation page in sidebar navigation - Standardize documentation structure and improve user guidance for implementing AI-powered message moderation across all platforms --- docs.json | 1 + moderation/overview.mdx | 48 ++--- sdk/android/ai-moderation.mdx | 290 ++++++++++++++++++------- sdk/android/flag-message.mdx | 277 +++++++++++++++++------- sdk/flutter/ai-moderation.mdx | 197 +++++++++++++---- sdk/flutter/flag-message.mdx | 224 ++++++++++++++----- sdk/ios/ai-moderation.mdx | 297 +++++++++++++++++++------- sdk/ios/flag-message.mdx | 189 ++++++++++++---- sdk/javascript/ai-moderation.mdx | 51 ----- sdk/javascript/flag-message.mdx | 257 ++++++++++++++++------ sdk/react-native/ai-moderation.mdx | 224 +++++++++++++++++++ sdk/react-native/flag-message.mdx | 257 ++++++++++++++++------ ui-kit/android/core-features.mdx | 16 ++ ui-kit/flutter/core-features.mdx | 16 ++ ui-kit/ios/core-features.mdx | 18 +- ui-kit/react-native/core-features.mdx | 16 ++ ui-kit/react/core-features.mdx | 2 +- 17 files changed, 1778 insertions(+), 602 deletions(-) create mode 100644 sdk/react-native/ai-moderation.mdx diff --git a/docs.json b/docs.json index 2ccdf8f0..39384740 100644 --- a/docs.json +++ b/docs.json @@ -2882,6 +2882,7 @@ "sdk/react-native/transfer-group-ownership" ] }, + "sdk/react-native/ai-moderation", "sdk/react-native/ai-agents", { "group": "Resources", diff --git a/moderation/overview.mdx b/moderation/overview.mdx index 152b92dc..dfe7acef 100644 --- a/moderation/overview.mdx +++ b/moderation/overview.mdx @@ -71,13 +71,13 @@ Moderation is supported across all CometChat platforms. Choose your integration UI Kits provide built-in support for message moderation and the Report Message feature: - } href="/ui-kit/react/core-features#message-moderation" horizontal /> - } href="/ui-kit/react-native/core-features" horizontal /> - } href="/ui-kit/android/core-features" horizontal /> - } href="/ui-kit/ios/core-features" horizontal /> - } href="/ui-kit/flutter/core-features" horizontal /> - } href="/ui-kit/angular/core-features" horizontal /> - } href="/ui-kit/vue/overview" horizontal /> + } href="/ui-kit/react/core-features#moderation" /> + } href="/ui-kit/react-native/core-features#moderation" /> + } href="/ui-kit/android/core-features#moderation" /> + } href="/ui-kit/ios/core-features#moderation" /> + } href="/ui-kit/flutter/core-features#moderation" /> + } href="/ui-kit/angular/core-features#moderation" /> + } href="/ui-kit/vue/overview#moderation" /> ### Chat SDKs @@ -85,37 +85,13 @@ UI Kits provide built-in support for message moderation and the Report Message f Implement message flagging directly using CometChat Chat SDKs: - } href="/sdk/javascript/flag-message" horizontal /> - } href="/sdk/react-native/flag-message" horizontal /> - } href="/sdk/android/flag-message" horizontal /> - } href="/sdk/ios/flag-message" horizontal /> - } href="/sdk/flutter/flag-message" horizontal /> + } href="/sdk/javascript/ai-moderation" /> + } href="/sdk/react-native/ai-moderation" /> + } href="/sdk/android/ai-moderation" /> + } href="/sdk/ios/ai-moderation" /> + } href="/sdk/flutter/ai-moderation" /> -### REST API - -For server-side integration and advanced moderation workflows: - - - - - - - - - - -## Dashboard vs REST API - -| Feature | Dashboard | REST API | -|---------|-----------|----------| -| Create/manage rules | ✅ **Moderation > Rules** | [Rules API](/rest-api/moderation/create-rule) | -| Create/manage keyword lists | ✅ **Moderation > Lists** | [Lists API](/rest-api/moderation/create-list) | -| Review flagged messages | ✅ **Moderation > Flagged Messages** | [Flagged Messages API](/rest-api/moderation/list-flagged-messages) | -| View blocked messages | ✅ **Moderation > Blocked Messages** | [Blocked Messages API](/rest-api/moderation/list-blocked-messages) | -| Approve/block messages | ✅ Click action buttons | [Review API](/rest-api/moderation/blockreview-flagged-message) | -| Configure flag reasons | ✅ **Moderation > Advanced Settings** | [Reasons API](/rest-api/moderation/create-reasons) | - --- ## Rules Management diff --git a/sdk/android/ai-moderation.mdx b/sdk/android/ai-moderation.mdx index 0fb7cdd9..dfe91143 100644 --- a/sdk/android/ai-moderation.mdx +++ b/sdk/android/ai-moderation.mdx @@ -2,93 +2,233 @@ title: "AI Moderation" --- -# Overview +## Overview AI Moderation in the CometChat SDK helps ensure that your chat application remains safe and compliant by automatically reviewing messages for inappropriate content. This feature leverages AI to moderate messages in real-time, reducing manual intervention and improving user experience. -For a broader understanding of moderation features, see the [Moderation Overview](../../moderation/overview). + +For a broader understanding of moderation features, configuring rules, and managing flagged messages, see the [Moderation Overview](/moderation/overview). + -# What Triggers Moderation? +## Prerequisites + +Before using AI Moderation, ensure the following: + +1. Moderation is enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Moderation rules are configured under **Moderation > Rules** +3. You're using CometChat SDK version that supports moderation + +## How It Works + +```mermaid +sequenceDiagram + participant App + participant SDK + participant CometChat + participant Moderation + + App->>SDK: sendMessage() + SDK->>CometChat: Send Message + CometChat->>Moderation: Process Message + CometChat-->>SDK: Message (status: PENDING) + SDK-->>App: onSuccess (PENDING) + Moderation-->>CometChat: Moderation Result + CometChat-->>SDK: onMessageModerated + SDK-->>App: APPROVED or DISAPPROVED +``` + +| Step | Description | +|------|-------------| +| 1. Send Message | App sends a text, image, or video message | +| 2. Pending Status | Message is sent with `PENDING` moderation status | +| 3. AI Processing | Moderation service analyzes the content | +| 4. Result Event | `onMessageModerated` event fires with final status | + +## Supported Message Types Moderation is triggered **only** for the following message types: -- Text Messages -- Image Messages -- Video Messages +| Message Type | Moderated | Notes | +|--------------|-----------|-------| +| Text Messages | ✅ | Content analyzed for inappropriate text | +| Image Messages | ✅ | Images scanned for unsafe content | +| Video Messages | ✅ | Videos analyzed for prohibited content | +| Custom Messages | ❌ | Not subject to AI moderation | +| Action Messages | ❌ | Not subject to AI moderation | + +## Moderation Status -Other message types are not subject to AI moderation. +The `getModerationStatus()` method returns one of the following values: -# Handling Message Moderation Status +| Status | Enum Value | Description | +|--------|------------|-------------| +| Pending | `ModerationStatus.PENDING` | Message is being processed by moderation | +| Approved | `ModerationStatus.APPROVED` | Message passed moderation and is visible | +| Disapproved | `ModerationStatus.DISAPPROVED` | Message violated rules and was blocked | -When sending text, image, or video messages, the moderation process introduces the following changes to the message flow: +## Implementation -1. **Initial Status:** - - On successfully sending a text, image, or video message, the response will include the moderation status as `pending`. - - You can fetch this status using the `getModerationStatus()` method, which returns an Enum: `ModerationStatus.PENDING`. +### Step 1: Send a Message and Check Initial Status -2. **Moderation Result Event:** - - Once the moderation service processes the message, a real-time event is triggered in your `MessageListener` as `onMessageModerated`. - - This event provides the message object with the updated moderation status, which will be either `ModerationStatus.APPROVED` or `ModerationStatus.DISAPPROVED`. +When you send a text, image, or video message, check the initial moderation status: -**Example:** + + + ```kotlin + val textMessage = TextMessage(receiverUID, "Hello, how are you?", CometChatConstants.RECEIVER_TYPE_USER) + + CometChat.sendMessage(textMessage, object : CometChat.CallbackListener() { + override fun onSuccess(message: TextMessage) { + // Check moderation status + if (message.moderationStatus == ModerationStatus.PENDING) { + Log.d(TAG, "Message is under moderation review") + // Show pending indicator in UI + } + } + + override fun onError(e: CometChatException) { + Log.e(TAG, "Message sending failed: ${e.message}") + } + }) + ``` + + + ```java + TextMessage textMessage = new TextMessage(receiverUID, "Hello, how are you?", CometChatConstants.RECEIVER_TYPE_USER); + + CometChat.sendMessage(textMessage, new CometChat.CallbackListener() { + @Override + public void onSuccess(TextMessage message) { + // Check moderation status + if (message.getModerationStatus().equals(ModerationStatus.PENDING)) { + Log.d(TAG, "Message is under moderation review"); + // Show pending indicator in UI + } + } + + @Override + public void onError(CometChatException e) { + Log.e(TAG, "Message sending failed: " + e.getMessage()); + } + }); + ``` + + + +### Step 2: Listen for Moderation Results + +Register a message listener to receive moderation results in real-time: + + + + ```kotlin + val listenerID = "MODERATION_LISTENER" + + CometChat.addMessageListener(listenerID, object : CometChat.MessageListener() { + override fun onMessageModerated(message: BaseMessage) { + when (message) { + is TextMessage -> { + when (message.moderationStatus) { + ModerationStatus.APPROVED -> { + Log.d(TAG, "Message ${message.id} approved") + // Update UI to show message normally + } + ModerationStatus.DISAPPROVED -> { + Log.d(TAG, "Message ${message.id} blocked") + // Handle blocked message (hide or show warning) + } + } + } + is MediaMessage -> { + when (message.moderationStatus) { + ModerationStatus.APPROVED -> { + Log.d(TAG, "Media message ${message.id} approved") + } + ModerationStatus.DISAPPROVED -> { + Log.d(TAG, "Media message ${message.id} blocked") + } + } + } + } + } + }) + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener(listenerID) + ``` + + + ```java + String listenerID = "MODERATION_LISTENER"; + + CometChat.addMessageListener(listenerID, new CometChat.MessageListener() { + @Override + public void onMessageModerated(BaseMessage message) { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + if (textMessage.getModerationStatus().equals(ModerationStatus.APPROVED)) { + Log.d(TAG, "Message " + message.getId() + " approved"); + // Update UI to show message normally + } else if (textMessage.getModerationStatus().equals(ModerationStatus.DISAPPROVED)) { + Log.d(TAG, "Message " + message.getId() + " blocked"); + // Handle blocked message (hide or show warning) + } + } else if (message instanceof MediaMessage) { + MediaMessage mediaMessage = (MediaMessage) message; + if (mediaMessage.getModerationStatus().equals(ModerationStatus.APPROVED)) { + Log.d(TAG, "Media message " + message.getId() + " approved"); + } else if (mediaMessage.getModerationStatus().equals(ModerationStatus.DISAPPROVED)) { + Log.d(TAG, "Media message " + message.getId() + " blocked"); + } + } + } + }); + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + +### Step 3: Handle Disapproved Messages + +When a message is disapproved, handle it appropriately in your UI: - - ```java - // Check moderation status after sending a message. This check is only applicable for TextMessage & MediaMessage class. - if(message.getModerationStatus().equals(ModerationStatus.PENDING)) { - // Message is under moderation - } - - // Listen for moderation result - CometChat.addMessageListener("UNIQUE_LISTENER_ID", new CometChat.MessageListener() { - @Override - public void onMessageModerated(BaseMessage message) { - if(message instanceof TextMessage){ - if(((TextMessage) message).getModerationStatus().equals(ModerationStatus.APPROVED)) { - // Message approved - } else if(((TextMessage) message).getModerationStatus().equals(ModerationStatus.DISAPPROVED)) { - // Message disapproved - } - } - else if(message instanceof MediaMessage){ - if(((MediaMessage) message).getModerationStatus().equals(ModerationStatus.APPROVED)) { - // Message approved - } else if(((MediaMessage) message).getModerationStatus().equals(ModerationStatus.DISAPPROVED)) { - // Message disapproved - } - } - } - }); - ``` - - - - ```kotlin - - // Check moderation status after sending message. This check is only applicable for TextMessage & MediaMessage class. - if (message.moderationStatus == ModerationStatus.PENDING) { - // Message is under moderation - } - - // Listen for moderation result - CometChat.addMessageListener("UNIQUE_LISTENER_ID", object : CometChat.MessageListener() { - override fun onMessageModerated(message: BaseMessage) { - if(baseMessage is TextMessage){ - if(message.moderationStatus == ModerationStatus.APPROVED) { - // Message approved - } else if(message.moderationStatus == ModerationStatus.DISAPPROVED) { - // Message disapproved - } - } else if(baseMessage is MediaMessage){ - if(message.moderationStatus == ModerationStatus.APPROVED) { - // Message approved - } else if(message.moderationStatus == ModerationStatus.DISAPPROVED) { - // Message disapproved - } - } - } - }); - ``` - - \ No newline at end of file + + ```kotlin + fun handleDisapprovedMessage(message: BaseMessage) { + val messageId = message.id + + // Option 1: Hide the message completely + hideMessageFromUI(messageId) + + // Option 2: Show a placeholder message + showBlockedPlaceholder(messageId, "This message was blocked by moderation") + + // Option 3: Notify the sender (if it's their message) + if (message.sender.uid == currentUserUID) { + showNotification("Your message was blocked due to policy violation") + } + } + ``` + + + ```java + private void handleDisapprovedMessage(BaseMessage message) { + int messageId = message.getId(); + + // Option 1: Hide the message completely + hideMessageFromUI(messageId); + + // Option 2: Show a placeholder message + showBlockedPlaceholder(messageId, "This message was blocked by moderation"); + + // Option 3: Notify the sender (if it's their message) + if (message.getSender().getUid().equals(currentUserUID)) { + showNotification("Your message was blocked due to policy violation"); + } + } + ``` + + diff --git a/sdk/android/flag-message.mdx b/sdk/android/flag-message.mdx index 292e37ff..0843d290 100644 --- a/sdk/android/flag-message.mdx +++ b/sdk/android/flag-message.mdx @@ -1,108 +1,227 @@ --- -title: "Flag A Message" +title: "Flag Message" --- -Flagging messages allows users to report inappropriate content to moderators or administrators. CometChat provides methods to flag messages with specific reasons and retrieve available flag reasons configured in your dashboard. +## Overview -## Flag a Message +Flagging messages allows users to report inappropriate content to moderators or administrators. When a message is flagged, it appears in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages** for review. -*In other words, as a user, how do I report a message?* + +For a complete understanding of how flagged messages are reviewed and managed, see the [Flagged Messages](/moderation/flagged-messages) documentation. + -To flag a message, you can use the `flagMessage()` method. This method takes the message ID and a payload containing an optional reason ID and remark. +## Prerequisites - - -```kotlin - val id = 0L; // Id of the message to be flagged - val flagDetail = FlagDetail() - flagDetail.reasonId = "spam" // Required: Reason ID for flagging the message - flagDetail.remark = "This message contains promotional content" // Optional: Additional remarks - CometChat.flagMessage(id, flagDetail, object : CometChat.CallbackListener() { - override fun onSuccess(s: String?) { - Log.i(TAG, "onSuccess: Message flagged successfully: $s") - } +Before using the flag message feature: - override fun onError(e: CometChatException?) { - Log.i(TAG, "onError: Message flagging failed with error: ${e?.message}") - } - }) +1. Moderation must be enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Flag reasons should be configured under **Moderation > Advanced Settings** + +## How It Works + +```mermaid +sequenceDiagram + participant User + participant App + participant SDK + participant CometChat + participant Dashboard + + User->>App: Reports message + App->>SDK: getFlagReasons() + SDK-->>App: Available reasons + App->>User: Show reason picker + User->>App: Select reason + remark + App->>SDK: flagMessage(id, flagDetail) + SDK->>CometChat: Flag message + CometChat-->>SDK: Success response + SDK-->>App: Message flagged + CometChat->>Dashboard: Message in Flagged queue ``` - - - -```java - long id = 0; // Id of the message to be flagged - FlagDetail flagDetail = new FlagDetail(); // Details of the flagging action - flagDetail.setReasonId("spam"); // Required: Reason ID for flagging the message - flagDetail.setRemark("This message contains promotional content"); // Optional: Additional remarks - CometChat.flagMessage(id, flagDetail, new CometChat.CallbackListener() { - @Override - public void onSuccess(String s) { - Log.i(TAG, "onSuccess: Message flagged successfully: " + s); - } - @Override - public void onError(CometChatException e) { - Log.i(TAG, "onError: Message flagging failed with error: " + e.getMessage()); +## Get Flag Reasons + +Before flagging a message, retrieve the list of available flag reasons configured in your Dashboard: + + + + ```kotlin + CometChat.getFlagReasons(object : CometChat.CallbackListener>() { + override fun onSuccess(reasons: MutableList?) { + Log.d(TAG, "Flag reasons fetched: $reasons") + // Use reasons to populate your report dialog UI + reasons?.forEach { reason -> + Log.d(TAG, "Reason ID: ${reason?.id}, Title: ${reason?.reason}") } - }); -``` - + } + + override fun onError(e: CometChatException) { + Log.e(TAG, "Error fetching flag reasons: ${e.message}") + } + }) + ``` + + + ```java + CometChat.getFlagReasons(new CometChat.CallbackListener>() { + @Override + public void onSuccess(List reasons) { + Log.d(TAG, "Flag reasons fetched: " + reasons); + // Use reasons to populate your report dialog UI + for (FlagReason reason : reasons) { + Log.d(TAG, "Reason ID: " + reason.getId() + ", Title: " + reason.getReason()); + } + } + + @Override + public void onError(CometChatException e) { + Log.e(TAG, "Error fetching flag reasons: " + e.getMessage()); + } + }); + ``` + + + +### Response + +The response is a list of `FlagReason` objects containing: + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Unique identifier for the reason | +| reason | String | Display text for the reason | + +## Flag a Message + +To flag a message, use the `flagMessage()` method with the message ID and a `FlagDetail` object: + + + + ```kotlin + val messageId = 123L // ID of the message to flag + + val flagDetail = FlagDetail().apply { + reasonId = "spam" // Required: ID from getFlagReasons() + remark = "This message contains promotional content" // Optional + } + + CometChat.flagMessage(messageId, flagDetail, object : CometChat.CallbackListener() { + override fun onSuccess(response: String?) { + Log.d(TAG, "Message flagged successfully: $response") + } + + override fun onError(e: CometChatException?) { + Log.e(TAG, "Message flagging failed: ${e?.message}") + } + }) + ``` + + + ```java + long messageId = 123L; // ID of the message to flag + + FlagDetail flagDetail = new FlagDetail(); + flagDetail.setReasonId("spam"); // Required: ID from getFlagReasons() + flagDetail.setRemark("This message contains promotional content"); // Optional + + CometChat.flagMessage(messageId, flagDetail, new CometChat.CallbackListener() { + @Override + public void onSuccess(String response) { + Log.d(TAG, "Message flagged successfully: " + response); + } + + @Override + public void onError(CometChatException e) { + Log.e(TAG, "Message flagging failed: " + e.getMessage()); + } + }); + ``` + ### Parameters -| Parameter | Type | Required | Description | -|-------------------------|------------|----------|---------------------------------------------| -| id | long | Yes | The ID of the message to be flagged | -| flagDetail | FlagDetail | Yes | Contains flagging details | -| flagDetail.setReasonId | String | Yes | ID of the flag reason (from getFlagReasons) | -| flagDetail.setRemark | String | No | Additional context or explanation | +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| messageId | long | Yes | The ID of the message to flag | +| flagDetail | FlagDetail | Yes | Contains flagging details | +| flagDetail.reasonId | String | Yes | ID of the flag reason (from `getFlagReasons()`) | +| flagDetail.remark | String | No | Additional context or explanation from the user | ### Response -On successful flagging, you'll receive a response object: - -```String +```json { "message": "Message {id} has been flagged successfully." } ``` -## Get Flag Reasons +## Complete Example -*In other words, what are the available reasons for flagging a message?* - -Before flagging a message, you can retrieve the list of available flag reasons using the `getFlagReasons()` method. These reasons are configured in the CometChat Dashboard. +Here's a complete implementation showing how to build a report message flow: - -```java - CometChat.getFlagReasons(new CometChat.CallbackListener>() { - @Override - public void onSuccess(List reasons) { - Log.e(TAG, "Flag Reasons fetched: " + reasons); - } - - @Override - public void onError(CometChatException e) { - Log.e(TAG, "Error fetching Flag Reasons: " + e.getMessage()); - } - }); -``` - - - -```kotlin - CometChat.getFlagReasons(object : CometChat.CallbackListener?>() { - override fun onSuccess(reasons: MutableList?) { - Log.e(TAG, "Flag Reasons fetched: $reasons") + + ```kotlin + class ReportMessageHandler { + private var flagReasons: List = emptyList() + + // Load flag reasons (call this on app init or when needed) + fun loadFlagReasons(callback: (List) -> Unit) { + CometChat.getFlagReasons(object : CometChat.CallbackListener>() { + override fun onSuccess(reasons: MutableList?) { + flagReasons = reasons ?: emptyList() + callback(flagReasons) + } + + override fun onError(e: CometChatException) { + Log.e(TAG, "Failed to load flag reasons: ${e.message}") + callback(emptyList()) + } + }) + } + + // Get reasons for UI display + fun getReasons(): List = flagReasons + + // Flag a message with selected reason + fun flagMessage( + messageId: Long, + reasonId: String, + remark: String? = null, + callback: (Boolean, String?) -> Unit + ) { + val flagDetail = FlagDetail().apply { + this.reasonId = reasonId + remark?.let { this.remark = it } } - override fun onError(e: CometChatException) { - Log.e(TAG, "Error fetching Flag Reasons: " + e.message) - } - }) -``` - + CometChat.flagMessage(messageId, flagDetail, object : CometChat.CallbackListener() { + override fun onSuccess(response: String?) { + callback(true, response) + } + + override fun onError(e: CometChatException?) { + callback(false, e?.message) + } + }) + } + } + + // Usage + val reportHandler = ReportMessageHandler() + + // Load reasons when app initializes + reportHandler.loadFlagReasons { reasons -> + // Display reasons in UI for user to select + } + + // When user submits the report + reportHandler.flagMessage(123L, "spam", "User is sending promotional links") { success, message -> + if (success) { + showToast("Message reported successfully") + } + } + ``` + diff --git a/sdk/flutter/ai-moderation.mdx b/sdk/flutter/ai-moderation.mdx index a5370e5f..130524a4 100644 --- a/sdk/flutter/ai-moderation.mdx +++ b/sdk/flutter/ai-moderation.mdx @@ -2,64 +2,171 @@ title: "AI Moderation" --- -# Overview +## Overview AI Moderation in the CometChat SDK helps ensure that your chat application remains safe and compliant by automatically reviewing messages for inappropriate content. This feature leverages AI to moderate messages in real-time, reducing manual intervention and improving user experience. -For a broader understanding of moderation features, see the [Moderation Overview](../../moderation/overview). + +For a broader understanding of moderation features, configuring rules, and managing flagged messages, see the [Moderation Overview](/moderation/overview). + -# What Triggers Moderation? +## Prerequisites + +Before using AI Moderation, ensure the following: + +1. Moderation is enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Moderation rules are configured under **Moderation > Rules** +3. You're using CometChat SDK version that supports moderation + +## How It Works + +```mermaid +sequenceDiagram + participant App + participant SDK + participant CometChat + participant Moderation + + App->>SDK: sendMessage() + SDK->>CometChat: Send Message + CometChat->>Moderation: Process Message + CometChat-->>SDK: Message (status: PENDING) + SDK-->>App: onSuccess (PENDING) + Moderation-->>CometChat: Moderation Result + CometChat-->>SDK: onMessageModerated + SDK-->>App: APPROVED or DISAPPROVED +``` + +| Step | Description | +|------|-------------| +| 1. Send Message | App sends a text, image, or video message | +| 2. Pending Status | Message is sent with `PENDING` moderation status | +| 3. AI Processing | Moderation service analyzes the content | +| 4. Result Event | `onMessageModerated` event fires with final status | + +## Supported Message Types Moderation is triggered **only** for the following message types: -- Text Messages -- Image Messages -- Video Messages +| Message Type | Moderated | Notes | +|--------------|-----------|-------| +| Text Messages | ✅ | Content analyzed for inappropriate text | +| Image Messages | ✅ | Images scanned for unsafe content | +| Video Messages | ✅ | Videos analyzed for prohibited content | +| Custom Messages | ❌ | Not subject to AI moderation | +| Action Messages | ❌ | Not subject to AI moderation | + +## Moderation Status + +The `moderationStatus` property returns one of the following enum values: + +| Status | Enum Value | Description | +|--------|------------|-------------| +| Pending | `ModerationStatusEnum.PENDING` | Message is being processed by moderation | +| Approved | `ModerationStatusEnum.APPROVED` | Message passed moderation and is visible | +| Disapproved | `ModerationStatusEnum.DISAPPROVED` | Message violated rules and was blocked | -Other message types are not subject to AI moderation. +## Implementation -# Handling Message Moderation Status +### Step 1: Send a Message and Check Initial Status -When sending text, image, or video messages, the moderation process introduces the following changes to the message flow: +When you send a text, image, or video message, check the initial moderation status: -1. **Initial Status:** - - On successfully sending a text, image, or video message, the response will include the moderation status as `pending`. - - You can fetch this status using the `moderationStatus` property, which returns an Enum: `CometChat.ModerationStatus.PENDING`. + + + ```dart + TextMessage textMessage = TextMessage( + text: "Hello, how are you?", + receiverUid: receiverUID, + receiverType: ReceiverTypeConstants.user, + ); + + CometChat.sendMessage( + textMessage, + onSuccess: (TextMessage message) { + // Check moderation status + if (message.moderationStatus?.value == ModerationStatusEnum.PENDING.value) { + print("Message is under moderation review"); + // Show pending indicator in UI + } + }, + onError: (CometChatException e) { + print("Message sending failed: ${e.message}"); + }, + ); + ``` + + + +### Step 2: Listen for Moderation Results + +Implement the `MessageListener` to receive moderation results in real-time: + + + + ```dart + class ModerationListener with MessageListener { + + @override + void onMessageModerated(BaseMessage message) { + if (message is TextMessage) { + switch (message.moderationStatus?.value) { + case ModerationStatusEnum.APPROVED: + print("Message ${message.id} approved"); + // Update UI to show message normally + break; + + case ModerationStatusEnum.DISAPPROVED: + print("Message ${message.id} blocked"); + // Handle blocked message (hide or show warning) + handleDisapprovedMessage(message); + break; + } + } else if (message is MediaMessage) { + switch (message.moderationStatus?.value) { + case ModerationStatusEnum.APPROVED: + print("Media message ${message.id} approved"); + break; + + case ModerationStatusEnum.DISAPPROVED: + print("Media message ${message.id} blocked"); + handleDisapprovedMessage(message); + break; + } + } + } + } + + // Register the listener + CometChat.addMessageListener("MODERATION_LISTENER", ModerationListener()); + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener("MODERATION_LISTENER"); + ``` + + -2. **Moderation Result Event:** - - Once the moderation service processes the message, a real-time event is triggered in your `MessageListener` as `onMessageModerated`. - - This event provides the message object with the updated moderation status, which will be either `CometChat.ModerationStatus.APPROVED` or `CometChat.ModerationStatus.DISAPPROVED`. +### Step 3: Handle Disapproved Messages -**Example:** +When a message is disapproved, handle it appropriately in your UI: - - ```dart - // Check moderation status after sending a message. This check is only applicable for TextMessage & MediaMessage class. - if(message.moderationStatus.value == ModerationStatusEnum.PENDING.value) { - // Message is under moderation - } - - // Listen for moderation result - class Class_Name with MessageListener { - // CometChat.addMessageListener("listenerId", this); - @override - void onMessageModerated(BaseMessage message) { - if(message is TextMessage) { - if(message.moderationStatus?.value == ModerationStatusEnum.APPROVED.value) { - // Message approved - } else if(message.moderationStatus?.value == ModerationStatusEnum.DISAPPROVED.value) { - // Message disapproved - } - } else if(message is MediaMessage) { - if(message.moderationStatus?.value == ModerationStatusEnum.APPROVED.value) { - // Message approved - } else if(message.moderationStatus?.value == ModerationStatusEnum.DISAPPROVED.value) { - // Message disapproved - } - } - } - } - ``` - + + ```dart + void handleDisapprovedMessage(BaseMessage message) { + int messageId = message.id; + + // Option 1: Hide the message completely + hideMessageFromUI(messageId); + + // Option 2: Show a placeholder message + showBlockedPlaceholder(messageId, "This message was blocked by moderation"); + + // Option 3: Notify the sender (if it's their message) + if (message.sender?.uid == currentUserUID) { + showNotification("Your message was blocked due to policy violation"); + } + } + ``` + diff --git a/sdk/flutter/flag-message.mdx b/sdk/flutter/flag-message.mdx index eb5b90fe..02b71550 100644 --- a/sdk/flutter/flag-message.mdx +++ b/sdk/flutter/flag-message.mdx @@ -1,81 +1,199 @@ --- -title: "Flag A Message" +title: "Flag Message" --- -Flagging messages allows users to report inappropriate content to moderators or administrators. CometChat provides methods to flag messages with specific reasons and retrieve available flag reasons configured in your dashboard. +## Overview -## Flag a Message +Flagging messages allows users to report inappropriate content to moderators or administrators. When a message is flagged, it appears in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages** for review. -*In other words, as a user, how do I report a message?* + +For a complete understanding of how flagged messages are reviewed and managed, see the [Flagged Messages](/moderation/flagged-messages) documentation. + -To flag a message, you can use the `flagMessage()` method. This method takes the message ID and a payload containing an optional reason ID and remark. +## Prerequisites - +Before using the flag message feature: + +1. Moderation must be enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Flag reasons should be configured under **Moderation > Advanced Settings** + +## How It Works - -```dart - int messageId = 0; // ID of the message to be flagged - - FlagDetail flagDetail = FlagDetail() - ..reasonId = "spam" // Required - ..remark = "This message contains promotional content"; // Optional - - CometChat.flagMessage( - messageId, - flagDetail, - onSuccess: (String response) { - print("Message flagged successfully: $response"); - }, - onError: (CometChatException e) { - print("Message flagging failed with error: ${e.message}"); - }, - ); +```mermaid +sequenceDiagram + participant User + participant App + participant SDK + participant CometChat + participant Dashboard + + User->>App: Reports message + App->>SDK: getFlagReasons() + SDK-->>App: Available reasons + App->>User: Show reason picker + User->>App: Select reason + remark + App->>SDK: flagMessage(id, flagDetail) + SDK->>CometChat: Flag message + CometChat-->>SDK: Success response + SDK-->>App: Message flagged + CometChat->>Dashboard: Message in Flagged queue ``` - + +## Get Flag Reasons + +Before flagging a message, retrieve the list of available flag reasons configured in your Dashboard: + + + + ```dart + CometChat.getFlagReasons( + onSuccess: (List reasons) { + print("Flag reasons fetched: $reasons"); + // Use reasons to populate your report dialog UI + for (var reason in reasons) { + print("Reason ID: ${reason.id}, Title: ${reason.title}"); + } + }, + onError: (CometChatException e) { + print("Error fetching flag reasons: ${e.message}"); + }, + ); + ``` + + + +### Response + +The response is a list of `FlagReason` objects containing: + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Unique identifier for the reason | +| title | String | Display text for the reason | + +## Flag a Message + +To flag a message, use the `flagMessage()` method with the message ID and a `FlagDetail` object: + + + + ```dart + int messageId = 123; // ID of the message to flag + + FlagDetail flagDetail = FlagDetail() + ..reasonId = "spam" // Required: ID from getFlagReasons() + ..remark = "This message contains promotional content"; // Optional + + CometChat.flagMessage( + messageId, + flagDetail, + onSuccess: (String response) { + print("Message flagged successfully: $response"); + }, + onError: (CometChatException e) { + print("Message flagging failed: ${e.message}"); + }, + ); + ``` + ### Parameters -| Parameter | Type | Required | Description | -|-------------------------|------------|----------|---------------------------------------------| -| id | long | Yes | The ID of the message to be flagged | -| flagDetail | FlagDetail | Yes | Contains flagging details | -| flagDetail.setReasonId | String | Yes | ID of the flag reason (from getFlagReasons) | -| flagDetail.setRemark | String | No | Additional context or explanation | +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| messageId | int | Yes | The ID of the message to flag | +| flagDetail | FlagDetail | Yes | Contains flagging details | +| flagDetail.reasonId | String | Yes | ID of the flag reason (from `getFlagReasons()`) | +| flagDetail.remark | String | No | Additional context or explanation from the user | ### Response -On successful flagging, you'll receive a response object: - -```String +```json { "message": "Message {id} has been flagged successfully." } ``` -## Get Flag Reasons - -*In other words, what are the available reasons for flagging a message?* +## Complete Example -Before flagging a message, you can retrieve the list of available flag reasons using the `getFlagReasons()` method. These reasons are configured in the CometChat Dashboard. +Here's a complete implementation showing how to build a report message flow: - -```dart + + ```dart + class ReportMessageHandler { + List _flagReasons = []; + + // Load flag reasons (call this on app init or when needed) + Future> loadFlagReasons() async { + final completer = Completer>(); + CometChat.getFlagReasons( - onSuccess: (List reasons) { - print("Flag Reasons fetched: $reasons"); - - // Example: iterate through reasons - for (var reason in reasons) { - print("Reason ID: ${reason.id}, Title: ${reason.title}"); + onSuccess: (List reasons) { + _flagReasons = reasons; + completer.complete(reasons); + }, + onError: (CometChatException e) { + print("Failed to load flag reasons: ${e.message}"); + completer.complete([]); + }, + ); + + return completer.future; } - }, - onError: (CometChatException e) { - print("Error fetching Flag Reasons: ${e.message}"); - }, - ); -``` - + // Get reasons for UI display + List getReasons() => _flagReasons; + + // Flag a message with selected reason + Future flagMessage( + int messageId, + String reasonId, { + String? remark, + }) async { + final completer = Completer(); + + FlagDetail flagDetail = FlagDetail() + ..reasonId = reasonId; + + if (remark != null) { + flagDetail.remark = remark; + } + + CometChat.flagMessage( + messageId, + flagDetail, + onSuccess: (String response) { + print("Message flagged successfully"); + completer.complete(true); + }, + onError: (CometChatException e) { + print("Failed to flag message: ${e.message}"); + completer.complete(false); + }, + ); + + return completer.future; + } + } + + // Usage + final reportHandler = ReportMessageHandler(); + + // Load reasons when app initializes + await reportHandler.loadFlagReasons(); + + // When user submits the report + final success = await reportHandler.flagMessage( + 123, + "spam", + remark: "User is sending promotional links", + ); + + if (success) { + showToast("Message reported successfully"); + } + ``` + diff --git a/sdk/ios/ai-moderation.mdx b/sdk/ios/ai-moderation.mdx index 998b2d88..eda461d9 100644 --- a/sdk/ios/ai-moderation.mdx +++ b/sdk/ios/ai-moderation.mdx @@ -2,101 +2,232 @@ title: "AI Moderation" --- -# Overview +## Overview AI Moderation in the CometChat SDK helps ensure that your chat application remains safe and compliant by automatically reviewing messages for inappropriate content. This feature leverages AI to moderate messages in real-time, reducing manual intervention and improving user experience. -For a broader understanding of moderation features, see the [Moderation Overview](../../moderation/overview). + +For a broader understanding of moderation features, configuring rules, and managing flagged messages, see the [Moderation Overview](/moderation/overview). + -# What Triggers Moderation? +## Prerequisites + +Before using AI Moderation, ensure the following: + +1. Moderation is enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Moderation rules are configured under **Moderation > Rules** +3. You're using CometChat SDK version that supports moderation + +## How It Works + +```mermaid +sequenceDiagram + participant App + participant SDK + participant CometChat + participant Moderation + + App->>SDK: sendMessage() + SDK->>CometChat: Send Message + CometChat->>Moderation: Process Message + CometChat-->>SDK: Message (status: pending) + SDK-->>App: onSuccess (pending) + Moderation-->>CometChat: Moderation Result + CometChat-->>SDK: onMessageModerated + SDK-->>App: approved or disapproved +``` + +| Step | Description | +|------|-------------| +| 1. Send Message | App sends a text, image, or video message | +| 2. Pending Status | Message is sent with `pending` moderation status | +| 3. AI Processing | Moderation service analyzes the content | +| 4. Result Event | `onMessageModerated` event fires with final status | + +## Supported Message Types Moderation is triggered **only** for the following message types: -- Text Messages -- Image Messages -- Video Messages +| Message Type | Moderated | Notes | +|--------------|-----------|-------| +| Text Messages | ✅ | Content analyzed for inappropriate text | +| Image Messages | ✅ | Images scanned for unsafe content | +| Video Messages | ✅ | Videos analyzed for prohibited content | +| Custom Messages | ❌ | Not subject to AI moderation | +| Action Messages | ❌ | Not subject to AI moderation | + +## Moderation Status + +The `getModerationStatus()` method returns one of the following string values: + +| Status | Value | Description | +|--------|-------|-------------| +| Pending | `"pending"` | Message is being processed by moderation | +| Approved | `"approved"` | Message passed moderation and is visible | +| Disapproved | `"disapproved"` | Message violated rules and was blocked | + +## Implementation + +### Step 1: Send a Message and Check Initial Status + +When you send a text, image, or video message, check the initial moderation status: + + + + ```swift + let textMessage = TextMessage(receiverUid: receiverUID, text: "Hello, how are you?", receiverType: .user) + + CometChat.sendTextMessage(message: textMessage) { sentMessage in + // Check moderation status + if let message = sentMessage as? TextMessage { + if message.getModerationStatus() == "pending" { + print("Message is under moderation review") + // Show pending indicator in UI + } + } + } onError: { error in + print("Message sending failed: \(error?.errorDescription ?? "")") + } + ``` + + + ```objc + TextMessage *textMessage = [[TextMessage alloc] initWithReceiverUid:receiverUID text:@"Hello, how are you?" receiverType:ReceiverTypeUser]; + + [CometChat sendTextMessageWithMessage:textMessage onSuccess:^(TextMessage *sentMessage) { + // Check moderation status + if ([[sentMessage getModerationStatus] isEqualToString:@"pending"]) { + NSLog(@"Message is under moderation review"); + // Show pending indicator in UI + } + } onError:^(CometChatException *error) { + NSLog(@"Message sending failed: %@", error.errorDescription); + }]; + ``` + + + +### Step 2: Listen for Moderation Results + +Implement the `onMessageModerated` delegate method to receive moderation results in real-time: + + + + ```swift + extension YourViewController: CometChatMessageDelegate { + + func onMessageModerated(moderatedMessage: BaseMessage) { + if let message = moderatedMessage as? TextMessage { + switch message.getModerationStatus() { + case "approved": + print("Message \(message.id) approved") + // Update UI to show message normally + + case "disapproved": + print("Message \(message.id) blocked") + // Handle blocked message (hide or show warning) + handleDisapprovedMessage(message) + + default: + break + } + } else if let message = moderatedMessage as? MediaMessage { + switch message.getModerationStatus() { + case "approved": + print("Media message \(message.id) approved") + + case "disapproved": + print("Media message \(message.id) blocked") + handleDisapprovedMessage(message) + + default: + break + } + } + } + } -Other message types are not subject to AI moderation. + // Register the delegate + CometChat.addMessageListener("MODERATION_LISTENER", self) -# Handling Message Moderation Status + // Don't forget to remove the listener when done + // CometChat.removeMessageListener("MODERATION_LISTENER") + ``` + + + ```objc + - (void)onMessageModerated:(BaseMessage *)message { + if ([message isKindOfClass:[TextMessage class]]) { + TextMessage *textMessage = (TextMessage *)message; + + if ([[textMessage getModerationStatus] isEqualToString:@"approved"]) { + NSLog(@"Message %d approved", message.id); + // Update UI to show message normally + } else if ([[textMessage getModerationStatus] isEqualToString:@"disapproved"]) { + NSLog(@"Message %d blocked", message.id); + // Handle blocked message (hide or show warning) + [self handleDisapprovedMessage:message]; + } + } else if ([message isKindOfClass:[MediaMessage class]]) { + MediaMessage *mediaMessage = (MediaMessage *)message; + + if ([[mediaMessage getModerationStatus] isEqualToString:@"approved"]) { + NSLog(@"Media message %d approved", message.id); + } else if ([[mediaMessage getModerationStatus] isEqualToString:@"disapproved"]) { + NSLog(@"Media message %d blocked", message.id); + [self handleDisapprovedMessage:message]; + } + } + } -When sending text, image, or video messages, the moderation process introduces the following changes to the message flow: + // Register the delegate + [CometChat addMessageListener:@"MODERATION_LISTENER" delegate:self]; -1. **Initial Status:** - - On successfully sending a text, image, or video message, the response will include the moderation status as `pending`. - - You can fetch this status using the `getModerationStatus()` method, which returns a string `pending`. + // Don't forget to remove the listener when done + // [CometChat removeMessageListener:@"MODERATION_LISTENER"]; + ``` + + -2. **Moderation Result Event:** - - Once the moderation service processes the message, a real-time event is triggered in your `MessageListener` as `onMessageModerated`. - - This event provides the message object with the updated moderation status, which will be either `approved` or `disapproved`. +### Step 3: Handle Disapproved Messages -**Example:** +When a message is disapproved, handle it appropriately in your UI: - - ```swift - // Check moderation status after sending a message. This check is only applicable for TextMessage & MediaMessage class. - if let message = sentMessage as? TextMessage { - if message.getModerationStatus() == "pending" { - // Message is under moderation - } - } else if let message = sentMessage as? MediaMessage { - if message.getModerationStatus() == "pending" { - // Message is under moderation - } - } - - // Listen for moderation result. - func onMessageModerated(moderatedMessage: BaseMessage) { - if let message = moderatedMessage as? TextMessage { - if message.getModerationStatus() == "approved" { - // Message approved - } else if message.getModerationStatus() == "disapproved" { - // Message disapproved - } - } else if let message = moderatedMessage as? MediaMessage { - if message.getModerationStatus() == "approved" { - // Message approved - } else if message.getModerationStatus() == "disapproved" { - // Message disapproved - } - } - } - ``` - - - ```objc - // Check moderation status after sending a message. This check is only applicable for TextMessage & MediaMessage class. - if ([sentMessage isKindOfClass:[TextMessage class]]) { - TextMessage *message = (TextMessage *)sentMessage; - if ([[message getModerationStatus] isEqualToString:@"pending"]) { - // Message is under moderation - } - } else if ([sentMessage isKindOfClass:[MediaMessage class]]) { - MediaMessage *message = (MediaMessage *)sentMessage; - if ([[message getModerationStatus] isEqualToString:@"pending"]) { - // Message is under moderation - } - } - - // Listen for moderation result - - (void)onMessageModerated:(BaseMessage *)message { - if ([message isKindOfClass:[TextMessage class]]) { - TextMessage *textMessage = (TextMessage *)message; - if ([[textMessage getModerationStatus] isEqualToString:@"approved"]) { - // Message approved - } else if ([[textMessage getModerationStatus] isEqualToString:@"disapproved"]) { - // Message disapproved - } - } else if ([message isKindOfClass:[MediaMessage class]]) { - MediaMessage *mediaMessage = (MediaMessage *)message; - if ([[mediaMessage getModerationStatus] isEqualToString:@"approved"]) { - // Message approved - } else if ([[mediaMessage getModerationStatus] isEqualToString:@"disapproved"]) { - // Message disapproved - } - } - } - ``` - - \ No newline at end of file + + ```swift + func handleDisapprovedMessage(_ message: BaseMessage) { + let messageId = message.id + + // Option 1: Hide the message completely + hideMessageFromUI(messageId) + + // Option 2: Show a placeholder message + showBlockedPlaceholder(messageId, text: "This message was blocked by moderation") + + // Option 3: Notify the sender (if it's their message) + if message.sender?.uid == currentUserUID { + showNotification("Your message was blocked due to policy violation") + } + } + ``` + + + ```objc + - (void)handleDisapprovedMessage:(BaseMessage *)message { + int messageId = message.id; + + // Option 1: Hide the message completely + [self hideMessageFromUI:messageId]; + + // Option 2: Show a placeholder message + [self showBlockedPlaceholder:messageId text:@"This message was blocked by moderation"]; + + // Option 3: Notify the sender (if it's their message) + if ([message.sender.uid isEqualToString:currentUserUID]) { + [self showNotification:@"Your message was blocked due to policy violation"]; + } + } + ``` + + diff --git a/sdk/ios/flag-message.mdx b/sdk/ios/flag-message.mdx index 2382239b..37a2be33 100644 --- a/sdk/ios/flag-message.mdx +++ b/sdk/ios/flag-message.mdx @@ -1,62 +1,175 @@ --- -title: "Flag A Message" +title: "Flag Message" --- -Flagging messages allows users to report inappropriate content to moderators or administrators. CometChat provides methods to flag messages with specific reasons and retrieve available flag reasons configured in your dashboard. +## Overview -## Flag a Message +Flagging messages allows users to report inappropriate content to moderators or administrators. When a message is flagged, it appears in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages** for review. -*In other words, as a user, how do I report a message?* + +For a complete understanding of how flagged messages are reviewed and managed, see the [Flagged Messages](/moderation/flagged-messages) documentation. + -To flag a message, you can use the `flagMessage()` method. This method takes the message ID and a payload containing an optional reason ID and remark. +## Prerequisites - - -```swift -let flagDetail = FlagDetail(messageId: message.id, reasonId: reason.id, remark: "i find this inappropriate") - -CometChat.flagMessage(messageId: message.id, detail: <#T##FlagDetail#>) { flagResponse in - print(flagResponse) -} onError: { error in - print(error?.errorDescription) -} +Before using the flag message feature: + +1. Moderation must be enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Flag reasons should be configured under **Moderation > Advanced Settings** + +## How It Works + +```mermaid +sequenceDiagram + participant User + participant App + participant SDK + participant CometChat + participant Dashboard + + User->>App: Reports message + App->>SDK: getFlagReasons() + SDK-->>App: Available reasons + App->>User: Show reason picker + User->>App: Select reason + remark + App->>SDK: flagMessage(messageId, detail) + SDK->>CometChat: Flag message + CometChat-->>SDK: Success response + SDK-->>App: Message flagged + CometChat->>Dashboard: Message in Flagged queue ``` - + +## Get Flag Reasons + +Before flagging a message, retrieve the list of available flag reasons configured in your Dashboard: + + + + ```swift + CometChat.getFlagReasons { reasons in + print("Flag reasons fetched: \(reasons)") + // Use reasons to populate your report dialog UI + for reason in reasons { + print("Reason ID: \(reason.id ?? ""), Title: \(reason.reason ?? "")") + } + } onError: { error in + print("Error fetching flag reasons: \(error?.errorDescription ?? "")") + } + ``` + + + +### Response + +The response is an array of `FlagReason` objects containing: + +| Property | Type | Description | +|----------|------|-------------| +| id | String | Unique identifier for the reason | +| reason | String | Display text for the reason | + +## Flag a Message + +To flag a message, use the `flagMessage()` method with the message ID and a `FlagDetail` object: + + + + ```swift + let messageId = 123 // ID of the message to flag + + let flagDetail = FlagDetail( + messageId: messageId, + reasonId: "spam", // Required: ID from getFlagReasons() + remark: "This message contains promotional content" // Optional + ) + + CometChat.flagMessage(messageId: messageId, detail: flagDetail) { response in + print("Message flagged successfully: \(response)") + } onError: { error in + print("Message flagging failed: \(error?.errorDescription ?? "")") + } + ``` + ### Parameters -| Parameter | Type | Required | Description | -|-------------------------|------------|----------|---------------------------------------------| -| id | long | Yes | The ID of the message to be flagged | -| flagDetail | FlagDetail | Yes | Contains flagging details | -| flagDetail.setReasonId | String | Yes | ID of the flag reason (from getFlagReasons) | -| flagDetail.setRemark | String | No | Additional context or explanation | +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| messageId | Int | Yes | The ID of the message to flag | +| detail | FlagDetail | Yes | Contains flagging details | +| detail.reasonId | String | Yes | ID of the flag reason (from `getFlagReasons()`) | +| detail.remark | String | No | Additional context or explanation from the user | ### Response -On successful flagging, you'll receive a response object: - -```String +```json { "message": "Message {id} has been flagged successfully." } ``` -## Get Flag Reasons - -*In other words, what are the available reasons for flagging a message?* +## Complete Example -Before flagging a message, you can retrieve the list of available flag reasons using the `getFlagReasons()` method. These reasons are configured in the CometChat Dashboard. +Here's a complete implementation showing how to build a report message flow: - -```swift -CometChat.getFlagReasons { reasons in - print("flag reasons: \(reasons)") -} onError: { error in - print(error?.errorDescription) -} -``` - + + ```swift + class ReportMessageHandler { + private var flagReasons: [FlagReason] = [] + + // Load flag reasons (call this on app init or when needed) + func loadFlagReasons(completion: @escaping ([FlagReason]) -> Void) { + CometChat.getFlagReasons { [weak self] reasons in + self?.flagReasons = reasons + completion(reasons) + } onError: { error in + print("Failed to load flag reasons: \(error?.errorDescription ?? "")") + completion([]) + } + } + + // Get reasons for UI display + func getReasons() -> [FlagReason] { + return flagReasons + } + + // Flag a message with selected reason + func flagMessage( + messageId: Int, + reasonId: String, + remark: String? = nil, + completion: @escaping (Bool, String?) -> Void + ) { + let flagDetail = FlagDetail( + messageId: messageId, + reasonId: reasonId, + remark: remark ?? "" + ) + + CometChat.flagMessage(messageId: messageId, detail: flagDetail) { response in + completion(true, response) + } onError: { error in + completion(false, error?.errorDescription) + } + } + } + + // Usage + let reportHandler = ReportMessageHandler() + + // Load reasons when app initializes + reportHandler.loadFlagReasons { reasons in + // Display reasons in UI for user to select + } + + // When user submits the report + reportHandler.flagMessage(messageId: 123, reasonId: "spam", remark: "User is sending promotional links") { success, message in + if success { + showToast("Message reported successfully") + } + } + ``` + diff --git a/sdk/javascript/ai-moderation.mdx b/sdk/javascript/ai-moderation.mdx index de77652e..17fa27e2 100644 --- a/sdk/javascript/ai-moderation.mdx +++ b/sdk/javascript/ai-moderation.mdx @@ -299,54 +299,3 @@ Here's a complete implementation showing the full moderation flow: ``` - -## Best Practices - - - - Display a visual indicator (like a clock icon or "Reviewing..." text) for messages with `PENDING` status so users know their message is being processed. - - - Don't just hide blocked messages silently. Inform the sender that their message couldn't be delivered due to content policy, without revealing specific details about what triggered the block. - - - Store the moderation status locally so you don't need to re-check when displaying message history. - - - Always remove message listeners when components unmount or when they're no longer needed to prevent memory leaks. - - - -## Related Features - - - - Allow users to manually report inappropriate messages - - - Configure moderation rules and manage flagged messages - - - Review and manage messages flagged by users or AI - - - Learn more about real-time message events - - - -## FAQ - - - - AI moderation typically processes messages within a few seconds. However, processing time may vary based on content type (images and videos take longer than text) and server load. - - - If the moderation service is temporarily unavailable, messages may remain in `PENDING` status longer than usual. The SDK will deliver the moderation result once the service processes the message. - - - The SDK doesn't provide a built-in appeal mechanism. However, you can implement a custom workflow using the [Flag Message](/sdk/javascript/flag-message) feature or by contacting your support team through the Dashboard. - - - No, AI moderation requires an active connection to CometChat servers. Messages sent while offline will be moderated when they're synced after reconnection. - - diff --git a/sdk/javascript/flag-message.mdx b/sdk/javascript/flag-message.mdx index a411e1fd..350149f5 100644 --- a/sdk/javascript/flag-message.mdx +++ b/sdk/javascript/flag-message.mdx @@ -1,66 +1,147 @@ --- -title: "Flag A Message" +title: "Flag Message" --- -Flagging messages allows users to report inappropriate content to moderators or administrators. CometChat provides methods to flag messages with specific reasons and retrieve available flag reasons configured in your dashboard. +## Overview -## Flag a Message +Flagging messages allows users to report inappropriate content to moderators or administrators. When a message is flagged, it appears in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages** for review. + + +For a complete understanding of how flagged messages are reviewed and managed, see the [Flagged Messages](/moderation/flagged-messages) documentation. + + +## Prerequisites -*In other words, as a user, how do I report a message?* +Before using the flag message feature: -To flag a message, you can use the `flagMessage()` method. This method takes the message ID and a payload containing an optional reason ID and remark. +1. Moderation must be enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Flag reasons should be configured under **Moderation > Advanced Settings** + +## How It Works + +```mermaid +sequenceDiagram + participant User + participant App + participant SDK + participant CometChat + participant Dashboard + + User->>App: Reports message + App->>SDK: getFlagReasons() + SDK-->>App: Available reasons + App->>User: Show reason picker + User->>App: Select reason + remark + App->>SDK: flagMessage(messageId, payload) + SDK->>CometChat: Flag message + CometChat-->>SDK: Success response + SDK-->>App: Message flagged + CometChat->>Dashboard: Message in Flagged queue +``` + +## Get Flag Reasons + +Before flagging a message, retrieve the list of available flag reasons configured in your Dashboard: - + + ```javascript + CometChat.getFlagReasons().then( + (reasons) => { + console.log("Flag reasons retrieved:", reasons); + // reasons is an array of { id, reason } objects + // Use these to populate your report dialog UI + }, + (error) => { + console.log("Failed to get flag reasons:", error); + } + ); + ``` + + + ```typescript + CometChat.getFlagReasons().then( + (reasons: CometChat.FlagReason[]) => { + console.log("Flag reasons retrieved:", reasons); + // reasons is an array of { id, reason } objects + // Use these to populate your report dialog UI + }, + (error: CometChat.CometChatException) => { + console.log("Failed to get flag reasons:", error); + } + ); + ``` + + + +### Response + +The response is an array of flag reason objects: + ```javascript -let messageId = "ID_OF_THE_MESSAGE_YOU_WANT_TO_FLAG"; -let payload = { - reasonId: "spam", // Required: ID of the flag reason - remark: "This message contains promotional content" // Optional: Additional context -}; - -CometChat.flagMessage(messageId, payload).then( - response => { - console.log("Message flagged successfully", response); - }, error => { - console.log("Message flagging failed with error:", error); - } -); +[ + { "id": "spam", "reason": "Spam or misleading" }, + { "id": "harassment", "reason": "Harassment or bullying" }, + { "id": "hate_speech", "reason": "Hate speech" }, + { "id": "violence", "reason": "Violence or dangerous content" }, + { "id": "inappropriate", "reason": "Inappropriate content" }, + { "id": "other", "reason": "Other" } +] ``` - - - -```typescript -let messageId: string = "ID_OF_THE_MESSAGE_YOU_WANT_TO_FLAG"; -let payload: { reasonId: string; remark?: string } = { - reasonId: "spam", - remark: "This message contains promotional content" -}; - -CometChat.flagMessage(messageId, payload).then( - (response: CometChat.FlagMessageResponse) => { - console.log("Message flagged successfully", response); - }, (error: CometChat.CometChatException) => { - console.log("Message flagging failed with error:", error); - } -); -``` - + +## Flag a Message + +To flag a message, use the `flagMessage()` method with the message ID and a payload containing the reason: + + + + ```javascript + const messageId = "MESSAGE_ID_TO_FLAG"; + const payload = { + reasonId: "spam", // Required: ID from getFlagReasons() + remark: "This message contains promotional content" // Optional + }; + + CometChat.flagMessage(messageId, payload).then( + (response) => { + console.log("Message flagged successfully:", response); + }, + (error) => { + console.log("Message flagging failed:", error); + } + ); + ``` + + + ```typescript + const messageId: string = "MESSAGE_ID_TO_FLAG"; + const payload: { reasonId: string; remark?: string } = { + reasonId: "spam", + remark: "This message contains promotional content" + }; + + CometChat.flagMessage(messageId, payload).then( + (response: CometChat.FlagMessageResponse) => { + console.log("Message flagged successfully:", response); + }, + (error: CometChat.CometChatException) => { + console.log("Message flagging failed:", error); + } + ); + ``` + ### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| messageId | string | Yes | The ID of the message to be flagged | -| payload | object | Yes | Contains flagging details | -| payload.reasonId | string | Yes | ID of the flag reason (from getFlagReasons) | -| payload.remark | string | No | Additional context or explanation | +| messageId | string | Yes | The ID of the message to flag | +| payload.reasonId | string | Yes | ID of the flag reason (from `getFlagReasons()`) | +| payload.remark | string | No | Additional context or explanation from the user | ### Response -On successful flagging, you'll receive a response object: - ```javascript { "success": true, @@ -68,36 +149,72 @@ On successful flagging, you'll receive a response object: } ``` -## Get Flag Reasons - -*In other words, what are the available reasons for flagging a message?* +## Complete Example -Before flagging a message, you can retrieve the list of available flag reasons using the `getFlagReasons()` method. These reasons are configured in the CometChat Dashboard. +Here's a complete implementation showing how to build a report message flow: - - ```javascript -CometChat.getFlagReasons().then( - reasons => { - console.log("Flag reasons retrieved", reasons); - // Use reasons to populate your UI - }, error => { - console.log("Failed to get flag reasons:", error); +class ReportMessageHandler { + constructor() { + this.flagReasons = []; } -); -``` - - - -```typescript -CometChat.getFlagReasons().then( - (reasons: CometChat.FlagReason[]) => { - console.log("Flag reasons retrieved", reasons); - // Use reasons to populate your UI - }, (error: CometChat.CometChatException) => { - console.log("Failed to get flag reasons:", error); + + // Load flag reasons (call this on app init or when needed) + async loadFlagReasons() { + try { + this.flagReasons = await CometChat.getFlagReasons(); + return this.flagReasons; + } catch (error) { + console.error("Failed to load flag reasons:", error); + return []; + } + } + + // Get reasons for UI display + getReasons() { + return this.flagReasons; + } + + // Flag a message with selected reason + async flagMessage(messageId, reasonId, remark = "") { + if (!reasonId) { + throw new Error("Reason ID is required"); + } + + try { + const payload = { reasonId }; + if (remark) { + payload.remark = remark; + } + + const response = await CometChat.flagMessage(messageId, payload); + console.log("Message flagged successfully"); + return { success: true, response }; + } catch (error) { + console.error("Failed to flag message:", error); + return { success: false, error }; + } } +} + +// Usage +const reportHandler = new ReportMessageHandler(); + +// Load reasons when app initializes +await reportHandler.loadFlagReasons(); + +// When user wants to report a message +const reasons = reportHandler.getReasons(); +// Display reasons in UI for user to select... + +// When user submits the report +const result = await reportHandler.flagMessage( + "message_123", + "spam", + "User is sending promotional links" ); + +if (result.success) { + showToast("Message reported successfully"); +} ``` - - diff --git a/sdk/react-native/ai-moderation.mdx b/sdk/react-native/ai-moderation.mdx new file mode 100644 index 00000000..fa0bffd7 --- /dev/null +++ b/sdk/react-native/ai-moderation.mdx @@ -0,0 +1,224 @@ +--- +title: "AI Moderation" +--- + +## Overview + +AI Moderation in the CometChat SDK helps ensure that your chat application remains safe and compliant by automatically reviewing messages for inappropriate content. This feature leverages AI to moderate messages in real-time, reducing manual intervention and improving user experience. + + +For a broader understanding of moderation features, configuring rules, and managing flagged messages, see the [Moderation Overview](/moderation/overview). + + +## Prerequisites + +Before using AI Moderation, ensure the following: + +1. Moderation is enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Moderation rules are configured under **Moderation > Rules** +3. You're using CometChat SDK version that supports moderation + +## How It Works + +```mermaid +sequenceDiagram + participant App + participant SDK + participant CometChat + participant Moderation + + App->>SDK: sendMessage() + SDK->>CometChat: Send Message + CometChat->>Moderation: Process Message + CometChat-->>SDK: Message (status: PENDING) + SDK-->>App: onMessageSent (PENDING) + Moderation-->>CometChat: Moderation Result + CometChat-->>SDK: onMessageModerated + SDK-->>App: APPROVED or DISAPPROVED +``` + +| Step | Description | +|------|-------------| +| 1. Send Message | App sends a text, image, or video message | +| 2. Pending Status | Message is sent with `PENDING` moderation status | +| 3. AI Processing | Moderation service analyzes the content | +| 4. Result Event | `onMessageModerated` event fires with final status | + +## Supported Message Types + +Moderation is triggered **only** for the following message types: + +| Message Type | Moderated | Notes | +|--------------|-----------|-------| +| Text Messages | ✅ | Content analyzed for inappropriate text | +| Image Messages | ✅ | Images scanned for unsafe content | +| Video Messages | ✅ | Videos analyzed for prohibited content | +| Custom Messages | ❌ | Not subject to AI moderation | +| Action Messages | ❌ | Not subject to AI moderation | + +## Moderation Status + +The `getModerationStatus()` method returns one of the following values: + +| Status | Enum Value | Description | +|--------|------------|-------------| +| Pending | `CometChat.ModerationStatus.PENDING` | Message is being processed by moderation | +| Approved | `CometChat.ModerationStatus.APPROVED` | Message passed moderation and is visible | +| Disapproved | `CometChat.ModerationStatus.DISAPPROVED` | Message violated rules and was blocked | + +## Implementation + +### Step 1: Send a Message and Check Initial Status + +When you send a text, image, or video message, check the initial moderation status: + + + + ```javascript + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMessage(textMessage).then( + (message) => { + // Check moderation status + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + console.log("Message is under moderation review"); + // Show pending indicator in UI + } + }, + (error) => { + console.log("Message sending failed:", error); + } + ); + ``` + + + ```typescript + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMessage(textMessage).then( + (message: CometChat.TextMessage) => { + // Check moderation status + const status: string = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + console.log("Message is under moderation review"); + // Show pending indicator in UI + } + }, + (error: CometChat.CometChatException) => { + console.log("Message sending failed:", error); + } + ); + ``` + + + +### Step 2: Listen for Moderation Results + +Register a message listener to receive moderation results in real-time: + + + + ```javascript + const listenerID = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageModerated: (message) => { + if ( + message instanceof CometChat.TextMessage || + message instanceof CometChat.MediaMessage + ) { + const status = message.getModerationStatus(); + const messageId = message.getId(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + console.log(`Message ${messageId} approved`); + // Update UI to show message normally + break; + + case CometChat.ModerationStatus.DISAPPROVED: + console.log(`Message ${messageId} blocked`); + // Handle blocked message (hide or show warning) + handleDisapprovedMessage(message); + break; + } + } + } + }) + ); + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + ```typescript + const listenerID: string = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageModerated: (message: CometChat.BaseMessage) => { + if ( + message instanceof CometChat.TextMessage || + message instanceof CometChat.MediaMessage + ) { + const status: string = message.getModerationStatus(); + const messageId: number = message.getId(); + + switch (status) { + case CometChat.ModerationStatus.APPROVED: + console.log(`Message ${messageId} approved`); + // Update UI to show message normally + break; + + case CometChat.ModerationStatus.DISAPPROVED: + console.log(`Message ${messageId} blocked`); + // Handle blocked message (hide or show warning) + handleDisapprovedMessage(message); + break; + } + } + } + }) + ); + + // Don't forget to remove the listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + +### Step 3: Handle Disapproved Messages + +When a message is disapproved, handle it appropriately in your UI: + +```javascript +function handleDisapprovedMessage(message) { + const messageId = message.getId(); + + // Option 1: Hide the message completely + hideMessageFromUI(messageId); + + // Option 2: Show a placeholder message + showBlockedPlaceholder(messageId, "This message was blocked by moderation"); + + // Option 3: Notify the sender (if it's their message) + if (message.getSender().getUid() === currentUserUID) { + showNotification("Your message was blocked due to policy violation"); + } +} +``` diff --git a/sdk/react-native/flag-message.mdx b/sdk/react-native/flag-message.mdx index a411e1fd..350149f5 100644 --- a/sdk/react-native/flag-message.mdx +++ b/sdk/react-native/flag-message.mdx @@ -1,66 +1,147 @@ --- -title: "Flag A Message" +title: "Flag Message" --- -Flagging messages allows users to report inappropriate content to moderators or administrators. CometChat provides methods to flag messages with specific reasons and retrieve available flag reasons configured in your dashboard. +## Overview -## Flag a Message +Flagging messages allows users to report inappropriate content to moderators or administrators. When a message is flagged, it appears in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages** for review. + + +For a complete understanding of how flagged messages are reviewed and managed, see the [Flagged Messages](/moderation/flagged-messages) documentation. + + +## Prerequisites -*In other words, as a user, how do I report a message?* +Before using the flag message feature: -To flag a message, you can use the `flagMessage()` method. This method takes the message ID and a payload containing an optional reason ID and remark. +1. Moderation must be enabled for your app in the [CometChat Dashboard](https://app.cometchat.com) +2. Flag reasons should be configured under **Moderation > Advanced Settings** + +## How It Works + +```mermaid +sequenceDiagram + participant User + participant App + participant SDK + participant CometChat + participant Dashboard + + User->>App: Reports message + App->>SDK: getFlagReasons() + SDK-->>App: Available reasons + App->>User: Show reason picker + User->>App: Select reason + remark + App->>SDK: flagMessage(messageId, payload) + SDK->>CometChat: Flag message + CometChat-->>SDK: Success response + SDK-->>App: Message flagged + CometChat->>Dashboard: Message in Flagged queue +``` + +## Get Flag Reasons + +Before flagging a message, retrieve the list of available flag reasons configured in your Dashboard: - + + ```javascript + CometChat.getFlagReasons().then( + (reasons) => { + console.log("Flag reasons retrieved:", reasons); + // reasons is an array of { id, reason } objects + // Use these to populate your report dialog UI + }, + (error) => { + console.log("Failed to get flag reasons:", error); + } + ); + ``` + + + ```typescript + CometChat.getFlagReasons().then( + (reasons: CometChat.FlagReason[]) => { + console.log("Flag reasons retrieved:", reasons); + // reasons is an array of { id, reason } objects + // Use these to populate your report dialog UI + }, + (error: CometChat.CometChatException) => { + console.log("Failed to get flag reasons:", error); + } + ); + ``` + + + +### Response + +The response is an array of flag reason objects: + ```javascript -let messageId = "ID_OF_THE_MESSAGE_YOU_WANT_TO_FLAG"; -let payload = { - reasonId: "spam", // Required: ID of the flag reason - remark: "This message contains promotional content" // Optional: Additional context -}; - -CometChat.flagMessage(messageId, payload).then( - response => { - console.log("Message flagged successfully", response); - }, error => { - console.log("Message flagging failed with error:", error); - } -); +[ + { "id": "spam", "reason": "Spam or misleading" }, + { "id": "harassment", "reason": "Harassment or bullying" }, + { "id": "hate_speech", "reason": "Hate speech" }, + { "id": "violence", "reason": "Violence or dangerous content" }, + { "id": "inappropriate", "reason": "Inappropriate content" }, + { "id": "other", "reason": "Other" } +] ``` - - - -```typescript -let messageId: string = "ID_OF_THE_MESSAGE_YOU_WANT_TO_FLAG"; -let payload: { reasonId: string; remark?: string } = { - reasonId: "spam", - remark: "This message contains promotional content" -}; - -CometChat.flagMessage(messageId, payload).then( - (response: CometChat.FlagMessageResponse) => { - console.log("Message flagged successfully", response); - }, (error: CometChat.CometChatException) => { - console.log("Message flagging failed with error:", error); - } -); -``` - + +## Flag a Message + +To flag a message, use the `flagMessage()` method with the message ID and a payload containing the reason: + + + + ```javascript + const messageId = "MESSAGE_ID_TO_FLAG"; + const payload = { + reasonId: "spam", // Required: ID from getFlagReasons() + remark: "This message contains promotional content" // Optional + }; + + CometChat.flagMessage(messageId, payload).then( + (response) => { + console.log("Message flagged successfully:", response); + }, + (error) => { + console.log("Message flagging failed:", error); + } + ); + ``` + + + ```typescript + const messageId: string = "MESSAGE_ID_TO_FLAG"; + const payload: { reasonId: string; remark?: string } = { + reasonId: "spam", + remark: "This message contains promotional content" + }; + + CometChat.flagMessage(messageId, payload).then( + (response: CometChat.FlagMessageResponse) => { + console.log("Message flagged successfully:", response); + }, + (error: CometChat.CometChatException) => { + console.log("Message flagging failed:", error); + } + ); + ``` + ### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| messageId | string | Yes | The ID of the message to be flagged | -| payload | object | Yes | Contains flagging details | -| payload.reasonId | string | Yes | ID of the flag reason (from getFlagReasons) | -| payload.remark | string | No | Additional context or explanation | +| messageId | string | Yes | The ID of the message to flag | +| payload.reasonId | string | Yes | ID of the flag reason (from `getFlagReasons()`) | +| payload.remark | string | No | Additional context or explanation from the user | ### Response -On successful flagging, you'll receive a response object: - ```javascript { "success": true, @@ -68,36 +149,72 @@ On successful flagging, you'll receive a response object: } ``` -## Get Flag Reasons - -*In other words, what are the available reasons for flagging a message?* +## Complete Example -Before flagging a message, you can retrieve the list of available flag reasons using the `getFlagReasons()` method. These reasons are configured in the CometChat Dashboard. +Here's a complete implementation showing how to build a report message flow: - - ```javascript -CometChat.getFlagReasons().then( - reasons => { - console.log("Flag reasons retrieved", reasons); - // Use reasons to populate your UI - }, error => { - console.log("Failed to get flag reasons:", error); +class ReportMessageHandler { + constructor() { + this.flagReasons = []; } -); -``` - - - -```typescript -CometChat.getFlagReasons().then( - (reasons: CometChat.FlagReason[]) => { - console.log("Flag reasons retrieved", reasons); - // Use reasons to populate your UI - }, (error: CometChat.CometChatException) => { - console.log("Failed to get flag reasons:", error); + + // Load flag reasons (call this on app init or when needed) + async loadFlagReasons() { + try { + this.flagReasons = await CometChat.getFlagReasons(); + return this.flagReasons; + } catch (error) { + console.error("Failed to load flag reasons:", error); + return []; + } + } + + // Get reasons for UI display + getReasons() { + return this.flagReasons; + } + + // Flag a message with selected reason + async flagMessage(messageId, reasonId, remark = "") { + if (!reasonId) { + throw new Error("Reason ID is required"); + } + + try { + const payload = { reasonId }; + if (remark) { + payload.remark = remark; + } + + const response = await CometChat.flagMessage(messageId, payload); + console.log("Message flagged successfully"); + return { success: true, response }; + } catch (error) { + console.error("Failed to flag message:", error); + return { success: false, error }; + } } +} + +// Usage +const reportHandler = new ReportMessageHandler(); + +// Load reasons when app initializes +await reportHandler.loadFlagReasons(); + +// When user wants to report a message +const reasons = reportHandler.getReasons(); +// Display reasons in UI for user to select... + +// When user submits the report +const result = await reportHandler.flagMessage( + "message_123", + "spam", + "User is sending promotional links" ); + +if (result.success) { + showToast("Message reported successfully"); +} ``` - - diff --git a/ui-kit/android/core-features.mdx b/ui-kit/android/core-features.mdx index 3dc1732f..ab972822 100644 --- a/ui-kit/android/core-features.mdx +++ b/ui-kit/android/core-features.mdx @@ -139,6 +139,10 @@ Conversation and Advanced Search is a powerful feature provided by CometChat tha The Report Message feature allows users to report inappropriate or harmful messages within the chat. Users can choose from predefined reasons and provide additional remarks for detailed context. This feature helps maintain a safe and respectful chat environment. + +Learn more about how flagged messages are handled, reviewed, and moderated in the [Flagged Messages](/moderation/flagged-messages) documentation. + + @@ -147,6 +151,18 @@ The Report Message feature allows users to report inappropriate or harmful messa | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. | +## Moderation + +CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + +Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. + + +| Components | Functionality | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) automatically handles moderated messages, displaying blocked content appropriately based on your moderation settings. | + ## Threaded Conversations The Threaded Conversations feature enables users to respond directly to a specific message in a chat. This keeps conversations organized and enhances the user experience by maintaining context, especially in group chats. diff --git a/ui-kit/flutter/core-features.mdx b/ui-kit/flutter/core-features.mdx index cb01a210..df32595c 100644 --- a/ui-kit/flutter/core-features.mdx +++ b/ui-kit/flutter/core-features.mdx @@ -110,6 +110,10 @@ Mentions is a robust feature provided by CometChat that enhances the interactivi The Report Message feature allows users to report inappropriate or harmful messages within the chat. Users can choose from predefined reasons and provide additional remarks for detailed context. This feature helps maintain a safe and respectful chat environment. + +Learn more about how flagged messages are handled, reviewed, and moderated in the [Flagged Messages](/moderation/flagged-messages) documentation. + + @@ -118,6 +122,18 @@ The Report Message feature allows users to report inappropriate or harmful messa | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Message List](/ui-kit/flutter/message-list) | [Message List](/ui-kit/flutter/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. | +## Moderation + +CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + +Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. + + +| Widgets | Functionality | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Message List](/ui-kit/flutter/message-list) | [Message List](/ui-kit/flutter/message-list) automatically handles moderated messages, displaying blocked content appropriately based on your moderation settings. | + ## Threaded Conversations The Threaded Conversations feature enables users to respond directly to a specific message in a chat. This keeps conversations organized and enhances the user experience by maintaining context, especially in group chats. diff --git a/ui-kit/ios/core-features.mdx b/ui-kit/ios/core-features.mdx index 2932e0a7..5a89de83 100644 --- a/ui-kit/ios/core-features.mdx +++ b/ui-kit/ios/core-features.mdx @@ -163,10 +163,26 @@ Conversation and Advanced Search is a powerful feature provided by CometChat tha The Report Message feature allows users to report inappropriate or harmful messages within the chat. Users can choose from predefined reasons and provide additional remarks for detailed context. This feature helps maintain a safe and respectful chat environment. + +Learn more about how flagged messages are handled, reviewed, and moderated in the [Flagged Messages](/moderation/flagged-messages) documentation. + + | Components | Functionality | | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. | \ No newline at end of file +| [Message List](/ui-kit/android/message-list) | [Message List](/ui-kit/android/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. | + +## Moderation + +CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + +Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. + + +| Components | Functionality | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Message List](/ui-kit/ios/message-list) | [Message List](/ui-kit/ios/message-list) automatically handles moderated messages, displaying blocked content appropriately based on your moderation settings. | \ No newline at end of file diff --git a/ui-kit/react-native/core-features.mdx b/ui-kit/react-native/core-features.mdx index eff01d21..9ba8e2e1 100644 --- a/ui-kit/react-native/core-features.mdx +++ b/ui-kit/react-native/core-features.mdx @@ -137,6 +137,10 @@ Conversation and Advanced Search is a powerful feature provided by CometChat tha The Report Message feature allows users to report inappropriate or harmful messages within the chat. Users can choose from predefined reasons and provide additional remarks for detailed context. This feature helps maintain a safe and respectful chat environment. + +Learn more about how flagged messages are handled, reviewed, and moderated in the [Flagged Messages](/moderation/flagged-messages) documentation. + + @@ -145,6 +149,18 @@ The Report Message feature allows users to report inappropriate or harmful messa | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Message List](/ui-kit/react-native/message-list) | [Message List](/ui-kit/react-native/message-list) provides the "Report Message" option in the message actions menu, allowing users to initiate the reporting process for inappropriate messages. | +## Moderation + +CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + +Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. + + +| Components | Functionality | +| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Message List](/ui-kit/react-native/message-list) | [Message List](/ui-kit/react-native/message-list) automatically handles moderated messages, displaying blocked content appropriately based on your moderation settings. | + ## Threaded Conversations The Threaded Conversations feature enables users to respond directly to a specific message in a chat. This keeps conversations organized and enhances the user experience by maintaining context, especially in group chats. diff --git a/ui-kit/react/core-features.mdx b/ui-kit/react/core-features.mdx index a03304e0..6f7c19e2 100644 --- a/ui-kit/react/core-features.mdx +++ b/ui-kit/react/core-features.mdx @@ -155,7 +155,7 @@ The Threaded Conversations feature enables users to respond directly to a specif | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | [Threaded Message Preview](/ui-kit/react/threaded-message-preview) | [Threaded Message Preview](/ui-kit/react/threaded-message-preview) component displays the parent message along with the number of replies. | -## Message Moderation +## Moderation CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. From e3c4e49e81f6add8fbe57335508fef2db8c0f6ed Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Tue, 13 Jan 2026 19:37:54 +0530 Subject: [PATCH 3/9] docs(calling): standardize setup documentation filenames across iOS and Android - Rename Android calling setup file from `setup-calling.mdx` to `calling-setup.mdx` for consistency - Rename iOS calling setup file from `calling-integration.mdx` to `calling-setup.mdx` for consistency - Update all internal documentation links to reference new standardized filenames - Update iOS calling setup page title from "Integration" to "Setup" for clarity - Update docs.json navigation configuration to reflect renamed files - Standardize calling setup documentation naming convention across all SDK platforms --- docs.json | 4 ++-- sdk/android/calling-overview.mdx | 2 +- sdk/android/{setup-calling.mdx => calling-setup.mdx} | 0 sdk/android/direct-calling.mdx | 2 +- sdk/android/standalone-calling.mdx | 2 +- sdk/ios/calling-overview.mdx | 2 +- sdk/ios/{calling-integration.mdx => calling-setup.mdx} | 2 +- sdk/ios/direct-calling.mdx | 2 +- sdk/ios/standalone-calling.mdx | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) rename sdk/android/{setup-calling.mdx => calling-setup.mdx} (100%) rename sdk/ios/{calling-integration.mdx => calling-setup.mdx} (99%) diff --git a/docs.json b/docs.json index 39384740..0174f316 100644 --- a/docs.json +++ b/docs.json @@ -3175,7 +3175,7 @@ "group": "Calling", "pages": [ "sdk/ios/calling-overview", - "sdk/ios/calling-integration", + "sdk/ios/calling-setup", "sdk/ios/default-calling", "sdk/ios/direct-calling", "sdk/ios/standalone-calling", @@ -3523,7 +3523,7 @@ "group": "Calling", "pages": [ "sdk/android/calling-overview", - "sdk/android/setup-calling", + "sdk/android/calling-setup", "sdk/android/default-calling", "sdk/android/direct-calling", "sdk/android/standalone-calling", diff --git a/sdk/android/calling-overview.mdx b/sdk/android/calling-overview.mdx index d09702e5..19ef1c0f 100644 --- a/sdk/android/calling-overview.mdx +++ b/sdk/android/calling-overview.mdx @@ -18,7 +18,7 @@ dependencies { } ``` -For detailed setup instructions, see the [Calls SDK Setup](/sdk/android/setup-calling) guide. +For detailed setup instructions, see the [Calls SDK Setup](/sdk/android/calling-setup) guide. ## Choose Your Implementation diff --git a/sdk/android/setup-calling.mdx b/sdk/android/calling-setup.mdx similarity index 100% rename from sdk/android/setup-calling.mdx rename to sdk/android/calling-setup.mdx diff --git a/sdk/android/direct-calling.mdx b/sdk/android/direct-calling.mdx index 897aba29..1c552333 100644 --- a/sdk/android/direct-calling.mdx +++ b/sdk/android/direct-calling.mdx @@ -6,7 +6,7 @@ title: "Call Session" This section demonstrates how to start a call session in an Android application. Previously known as **Direct Calling**. -Before you begin, we strongly recommend you read the [calling setup guide](/sdk/android/setup-calling). +Before you begin, we strongly recommend you read the [calling setup guide](/sdk/android/calling-setup). diff --git a/sdk/android/standalone-calling.mdx b/sdk/android/standalone-calling.mdx index 354a7ae6..77b4e628 100644 --- a/sdk/android/standalone-calling.mdx +++ b/sdk/android/standalone-calling.mdx @@ -7,7 +7,7 @@ title: "Standalone Calling" This section demonstrates how to implement calling functionality using only the CometChat Calls SDK, without requiring the Chat SDK. This is ideal for applications that need video/audio calling capabilities without the full chat infrastructure. -Before you begin, ensure you have completed the [Calls SDK setup](/sdk/android/setup-calling). +Before you begin, ensure you have completed the [Calls SDK setup](/sdk/android/calling-setup). ## User Authentication diff --git a/sdk/ios/calling-overview.mdx b/sdk/ios/calling-overview.mdx index 1ecf19a3..4883e77b 100644 --- a/sdk/ios/calling-overview.mdx +++ b/sdk/ios/calling-overview.mdx @@ -10,7 +10,7 @@ CometChat provides voice and video calling capabilities for your iOS application ## Prerequisites 1. CometChat SDK installed and configured. See the [Setup](/sdk/ios/setup) guide. -2. CometChat Calls SDK added to your project. For detailed setup instructions, see the [Calls SDK Setup](/sdk/ios/calling-integration) guide. +2. CometChat Calls SDK added to your project. For detailed setup instructions, see the [Calls SDK Setup](/sdk/ios/calling-setup) guide. ## Choose Your Implementation diff --git a/sdk/ios/calling-integration.mdx b/sdk/ios/calling-setup.mdx similarity index 99% rename from sdk/ios/calling-integration.mdx rename to sdk/ios/calling-setup.mdx index e21fd6ce..064816a0 100644 --- a/sdk/ios/calling-integration.mdx +++ b/sdk/ios/calling-setup.mdx @@ -1,5 +1,5 @@ --- -title: "Integration" +title: "Setup" --- diff --git a/sdk/ios/direct-calling.mdx b/sdk/ios/direct-calling.mdx index 5b9750a4..b525aa90 100644 --- a/sdk/ios/direct-calling.mdx +++ b/sdk/ios/direct-calling.mdx @@ -6,7 +6,7 @@ title: "Call Session" This section demonstrates how to start a call session in an iOS application. Previously known as **Direct Calling**. -Before you begin, we strongly recommend you read the [calling setup guide](/sdk/ios/calling-integration). +Before you begin, we strongly recommend you read the [calling setup guide](/sdk/ios/calling-setup). If you want to implement a complete calling experience with ringing functionality (incoming/outgoing call UI), follow the [Ringing](/sdk/ios/default-calling) guide first. Once the call is accepted, return here to start the call session. diff --git a/sdk/ios/standalone-calling.mdx b/sdk/ios/standalone-calling.mdx index 5e8d060d..022ee552 100644 --- a/sdk/ios/standalone-calling.mdx +++ b/sdk/ios/standalone-calling.mdx @@ -7,7 +7,7 @@ title: "Standalone Calling" This section demonstrates how to implement calling functionality using only the CometChat Calls SDK, without requiring the Chat SDK. This is ideal for applications that need video/audio calling capabilities without the full chat infrastructure. -Before you begin, ensure you have completed the [Calls SDK setup](/sdk/ios/calling-integration). +Before you begin, ensure you have completed the [Calls SDK setup](/sdk/ios/calling-setup). ## User Authentication From 2194223dc87bade991fd06610b2df646db212e13 Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Tue, 13 Jan 2026 20:35:01 +0530 Subject: [PATCH 4/9] docs(moderation): update navigation paths and remove redundant heading - Update moderation rule navigation from "List" to "Rules" in OpenAI custom setup guide - Remove redundant "Overview" heading from OpenAI overview documentation - Remove Vue UI Kit card from moderation feature support section - Improve documentation consistency and clarity across moderation guides --- moderation/open-ai/openai-custom.mdx | 2 +- moderation/open-ai/openai-overview.mdx | 2 -- moderation/overview.mdx | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/moderation/open-ai/openai-custom.mdx b/moderation/open-ai/openai-custom.mdx index cf8e0b07..9cbeeabf 100644 --- a/moderation/open-ai/openai-custom.mdx +++ b/moderation/open-ai/openai-custom.mdx @@ -36,7 +36,7 @@ CometChat allows you to integrate OpenAI for real-time message moderation, enabl ### **Step 2: Enable OpenAI Moderation** -1. Navigate to **Moderation → List**. +1. Navigate to **Moderation → Rules**. 2. Click **"Create New Rule"**. 3. Select **OpenAI** as the moderation type. 4. Select a predefined **prompt** from the List Section or create your own. diff --git a/moderation/open-ai/openai-overview.mdx b/moderation/open-ai/openai-overview.mdx index 3163b81e..492290b9 100644 --- a/moderation/open-ai/openai-overview.mdx +++ b/moderation/open-ai/openai-overview.mdx @@ -2,8 +2,6 @@ title: "Overview" --- -# Overview - CometChat offers AI-powered message moderation to help maintain a safe and respectful chat environment. You can choose between two moderation options: ### **OpenAI Moderation** diff --git a/moderation/overview.mdx b/moderation/overview.mdx index dfe7acef..dae288ba 100644 --- a/moderation/overview.mdx +++ b/moderation/overview.mdx @@ -77,7 +77,6 @@ UI Kits provide built-in support for message moderation and the Report Message f } href="/ui-kit/ios/core-features#moderation" /> } href="/ui-kit/flutter/core-features#moderation" /> } href="/ui-kit/angular/core-features#moderation" /> - } href="/ui-kit/vue/overview#moderation" /> ### Chat SDKs From 06390fbcfb6f55175dffa9279c85c3e342698bef Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Thu, 15 Jan 2026 18:52:53 +0530 Subject: [PATCH 5/9] docs(moderation): add UI overview images and restructure moderation documentation - Add mobile and React UI kit moderation overview images - Restructure blocked messages documentation with quick start guide and flowchart - Update constraints and limits documentation with improved formatting - Enhance flagged messages documentation with better organization - Improve getting started guide with clearer navigation - Restructure lists management documentation - Update reviewed messages documentation - Reorganize rules management documentation - Add moderation overview images to all UI kit core features (Android, Flutter, iOS, React Native, React) - Improve visual consistency and user experience across moderation docs --- images/mobile-uikit-moderation-overview.png | Bin 0 -> 162508 bytes images/react-uikit-moderation-overview.png | Bin 0 -> 249697 bytes moderation/blocked-messages.mdx | 138 ++- moderation/constraints-and-limits.mdx | 119 ++- moderation/flagged-messages.mdx | 197 ++-- moderation/getting-started.mdx | 546 ++++++++--- moderation/lists-management.mdx | 294 +++--- moderation/reviewed-messages.mdx | 112 ++- moderation/rules-management.mdx | 949 +++++++++----------- ui-kit/android/core-features.mdx | 4 + ui-kit/flutter/core-features.mdx | 4 + ui-kit/ios/core-features.mdx | 4 + ui-kit/react-native/core-features.mdx | 4 + ui-kit/react/core-features.mdx | 4 + 14 files changed, 1434 insertions(+), 941 deletions(-) create mode 100644 images/mobile-uikit-moderation-overview.png create mode 100644 images/react-uikit-moderation-overview.png diff --git a/images/mobile-uikit-moderation-overview.png b/images/mobile-uikit-moderation-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..6830e58fb71939fbe12ab052bfe30d4be38fd70d GIT binary patch literal 162508 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�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 z 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 SJzhFI;G-z3CQ~GB6! +**Blocked messages are hidden immediately.** Unlike flagged messages which wait for review, blocked messages are never delivered to recipients. Use this dashboard to monitor what's being blocked and catch false positives. + -### List Blocked Messages +--- + +## Quick Start + +Review blocked messages in under 2 minutes: -Retrieves the list of blocked messages, with the option to search messages within a specified date range. + + + Login to [CometChat Dashboard](https://app.cometchat.com) → Select your app → **Moderation** → **Blocked Messages** + + + Click on a blocked message to see the content, sender, rule that triggered the block, and timestamp + + + Click **Approve** to unblock a false positive, or **Mark as Reviewed** to acknowledge without approving + + -You can also set this up from your end using the [List Moderation Blocked Message List REST API](/rest-api/moderation/list-moderation-blocked-messages). +--- + +## How It Works + +```mermaid +flowchart LR + A[Message Sent] --> B{Rule Check} + B -->|Matches Rule| C[Message Blocked] + B -->|No Match| D[Message Delivered] + C --> E[Blocked Messages Dashboard] + E --> F{Moderator Review} + F --> G[Approve - Unblock] + F --> H[Mark as Reviewed] + F --> I[No Action] +``` + +| Status | Description | +|--------|-------------| +| **Blocked** | Message matched a rule and was not delivered | +| **Approved** | Moderator reviewed and unblocked the message | +| **Reviewed** | Moderator acknowledged but kept message blocked | + +--- + +## Managing Blocked Messages + +### List Blocked Messages + +View all blocked messages with filtering options: +- **Date range**: Filter by when messages were blocked +- **Rule**: Filter by which rule triggered the block +- **Sender**: Search by sender UID + + + + ### Approve Blocked Message -Allows the approval of messages previously blocked due to moderation violations. -Approving a blocked message automatically marks it as **reviewed**, showing that it has been checked and is okay. +Approving a blocked message: +1. Unblocks the message (makes it visible to recipients) +2. Marks it as reviewed +3. Helps identify false positives in your rules -You can also set this up from your end using the [Approve Blocked Message REST API](/rest-api/moderation/approve-blocked-messages). - + +Approving a message will deliver it to the recipient. Only approve if you're certain the message doesn't violate your guidelines. + -### Review Blocked Message +### Mark as Reviewed -Allows to manually mark a blocked message as reviewed without approving it. +Mark a message as reviewed without approving it: +- Message stays blocked +- Indicates a moderator has seen it +- Useful for tracking review progress -You can also set this up from your end using the [Mark Blocked Message as Reviewed REST API](/rest-api/moderation/review-blocked-message). +--- + +## Best Practices + + + + Check blocked messages weekly to catch false positives and refine rules. + + + Look for patterns in blocked content to identify if rules need adjustment. + + + Filter by date range to focus on recent blocks or investigate specific incidents. + + + If you see many false positives, adjust confidence levels in [Rules Management](/moderation/rules-management). + + + +--- + +## FAQ + + + + Yes. When you approve a blocked message, it becomes visible to the recipient. However, depending on how much time has passed, the message may appear out of context in the conversation. + + + Blocked messages are immediately hidden and never delivered. Flagged messages are delivered but marked for moderator review. Use "Block" for clear violations and "Flag" for borderline content. + + + 1. Increase confidence thresholds in your rules + 2. Add exceptions to your keyword lists + 3. Use more specific patterns instead of broad keywords + + + Yes, select multiple messages and use the bulk approve action. + + + +--- + +## Related Resources + + + + Configure rules that block messages + + + Review messages pending moderation + + + Manage keyword lists used by rules + + + Learn about the moderation system + + diff --git a/moderation/constraints-and-limits.mdx b/moderation/constraints-and-limits.mdx index 6f5948aa..1e3b00b5 100644 --- a/moderation/constraints-and-limits.mdx +++ b/moderation/constraints-and-limits.mdx @@ -1,42 +1,105 @@ --- -title: "Constraints And Limits" +title: "Constraints and Limits" +--- + +This page outlines the system constraints and limitations for CometChat's Moderation Service. Understanding these limits helps you design your moderation strategy effectively. + + +**Need higher limits?** Contact [CometChat Support](https://www.cometchat.com/contact) to discuss enterprise options for increased limits. + + --- ## Constraints -### Rule Management + + + | Parameter | Limit | + |-----------|-------| + | **Rule ID** | Max 100 characters, no spaces or special characters | + | **Name** | Max 100 characters | + | **Description** | Max 255 characters | + | **Filters per rule** | Max 10 filters | + | **Conditions per rule** | Max 10 conditions | + | **Rules per app** | Max 25 custom rules (excludes default rules) | + + + | Parameter | Limit | + |-----------|-------| + | **List ID** | Max 100 characters, no spaces or special characters | + | **Name** | Max 100 characters | + | **Description** | Max 255 characters | + | **CSV file size** | Max 1 MB | + | **Lists per app** | Max 25 custom lists (excludes default lists) | + + + | Parameter | Limit | + |-----------|-------| + | **AI Context** | Max 50 messages sent to OpenAI/Custom API for analysis | + | **Custom Flag Reasons** | Max 5 per app | + + + +--- + +## Supported Formats + +| Media Type | Supported Formats | +|------------|-------------------| +| **Images** | JPEG, PNG | +| **Videos** | MP4, MOV, AVI | + + +Other image and video formats are not currently supported for AI moderation. + -Here are the constraints for managing rules within the system: +--- -| Parameter | Constraint | -| ------------------- | ------------------------------------------------------------------------- | -| **Rule ID** | No spaces or special characters allowed, Maximum length of 100 characters | -| **Name** | Maximum length of 100 characters | -| **Description** | Maximum length of 255 characters | -| **Rule Filters** | Each rule can have a maximum of 10 filters | -| **Rule Conditions** | Each rule can have a maximum of 10 conditions | -| **Rules per app** | An app can have up to 25 rules (exluding default rules) | +## Known Limitations -### Lists Management + + + Moderation features require SDK version **3.0 or higher**. Ensure your app is updated before enabling moderation. + + + If a message is marked as delivered/read and previous messages include pending or disapproved ones, those will also be automatically marked as delivered/read—even though they weren't actually delivered to the receiver. + + -Here are the constraints for managing lists within the system: +--- -| Parameter | Constraint | -| ----------------- | ------------------------------------------------------------------------- | -| **ID** | No spaces or special characters allowed, Maximum length of 100 characters | -| **Name** | Maximum length of 100 characters | -| **Description** | Maximum length of 255 characters | -| **CSV File** | Accepted file size: up to 1 MB | -| **Lists per app** | An app can have up to 25 lists (excluding the default lists) | +## Quick Reference -### Advanced Settings + + + Maximum custom rules per app + + + Maximum custom lists per app + + + Maximum filters per rule + + + Maximum conditions per rule + + -* **AI Context Limit**: Up to 50 messages can be sent to OpenAI/Custom API for contextual analysis. -* **Flag Reasons Limit**: A maximum of 5 custom flag reasons can be configured per app. +--- -## Limitations +## Related Resources -* Make sure the SDK version you are using is 3.0 or higher. -* AI Image moderation currently supports & moderates JPEG and PNG image formats. -* AI video moderation currently supports & moderates MP4, MOV, and AVI formats. -* If a message is marked as delivered/read and previous messages include pending/disapproved ones, those will also be automatically marked as delivered/read, even though they haven't actually been delivered to the receiver. + + + Configure moderation rules + + + Manage keyword lists + + + Learn about the moderation system + + + Request higher limits + + diff --git a/moderation/flagged-messages.mdx b/moderation/flagged-messages.mdx index ce44a8fe..5aed3e4e 100644 --- a/moderation/flagged-messages.mdx +++ b/moderation/flagged-messages.mdx @@ -2,16 +2,31 @@ title: "Flagged Messages" --- -## Overview +Flagged Messages allows moderators to review messages that have been flagged for potentially violating moderation rules. Messages can be flagged automatically by the rule engine or manually by end users who find content inappropriate. -The Flagged Messages feature in CometChat's Moderation Service enables app owners and collaborators to review messages that have been flagged for potentially violating moderation rules. Messages can be flagged automatically by the rule engine based on predefined rules, or manually by end users who find certain content inappropriate or concerning. + +**Two-step moderation.** Unlike blocked messages which are hidden immediately, flagged messages remain visible until a moderator reviews and takes action (approve or block). + -When a message is flagged, it becomes visible in the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Flagged Messages**. Moderators can then review these flagged messages and take one of two actions: +--- + +## Quick Start + +Review flagged messages in under 2 minutes: -1. **Approve** - The message is deemed acceptable and the moderation status remains approved -2. **Block** - The message violates platform policies and the moderation status is changed to disapproved + + + Login to [CometChat Dashboard](https://app.cometchat.com) → Select your app → **Moderation** → **Flagged Messages** + + + Click on a flagged message to see details, context, and the reason it was flagged + + + Click **Approve** (message stays visible) or **Block** (message is hidden) + + -Once either action is taken, the message is automatically moved to the Reviewed list, which contains all messages that have been reviewed by moderators. +--- ## How It Works @@ -37,124 +52,132 @@ flowchart LR | 4. Moderator Action | Moderator reviews and either approves or blocks the message | | 5. Reviewed List | Message moves to the reviewed list with its final status | -## Dashboard vs REST API - -You can manage flagged messages through either the Dashboard or REST API: - -| Action | Dashboard | REST API | -|--------|-----------|----------| -| List flagged messages | **Moderation > Flagged Messages** | [List Flagged Messages API](/rest-api/moderation/list-flagged-messages) | -| Approve message | Click "Approve" button | [Approve/Block API](/rest-api/moderation/blockreview-flagged-message) | -| Block message | Click "Block" button | [Approve/Block API](/rest-api/moderation/blockreview-flagged-message) | -| Flag a message | - | [Flag Message API](/rest-api/moderation/flag-a-message) | -| Configure flag reasons | **Moderation > Advanced Settings** | [Reason APIs](/rest-api/moderation/create-reasons) | +--- ## Flagging Methods -### Manual Flagging by End Users - -End users can manually flag messages they find inappropriate or concerning by selecting from a predefined list of reasons. These flag reasons are configurable through the CometChat Dashboard, where you can either use the default options or create custom flagging reasons tailored to your platform's needs. - - - - - -Once configured, these reasons will appear in the user interface, allowing users to select the most appropriate reason when reporting a message. - -Messages can also be flagged programmatically via the [Flag Message API](/rest-api/moderation/flag-a-message). - - -The Report Message feature is available in CometChat UI Kits. Users can report messages directly from the message actions menu: - - - } href="/ui-kit/react/core-features#report-message" horizontal /> - } href="/ui-kit/react-native/core-features" horizontal /> - } href="/ui-kit/android/core-features" horizontal /> - } href="/ui-kit/ios/core-features" horizontal /> - } href="/ui-kit/flutter/core-features" horizontal /> - } href="/ui-kit/angular/core-features" horizontal /> - } href="/ui-kit/vue/overview" horizontal /> - - - - -You can implement message flagging directly using CometChat Chat SDKs: - - - } href="/sdk/javascript/flag-message" horizontal /> - } href="/sdk/react-native/flag-message" horizontal /> - } href="/sdk/android/flag-message" horizontal /> - } href="/sdk/ios/flag-message" horizontal /> - } href="/sdk/flutter/flag-message" horizontal /> - - - -### Automatic Flagging by Rule Engine - -Messages can be automatically flagged when they violate predefined moderation rules. When setting up moderation rules in the Dashboard, you can configure the action to "flag" messages that match specific criteria. This ensures that potentially problematic content is automatically identified and queued for review without requiring manual intervention from users. - -For example, if a message contains profane words, it would be automatically flagged. - - - - + + + End users can manually flag messages they find inappropriate by selecting from a predefined list of reasons. + + + + + + **Configure flag reasons:** Dashboard → **Moderation** → **Advanced Settings** + + + + + + + Messages are automatically flagged when they match moderation rules configured with the "Flag" action. + + + + + + **Set up auto-flagging:** Create a rule in [Rules Management](/moderation/rules-management) with Action set to "Flag" + + -### Configuring Flag Reasons +--- -You can customize the flagging reasons available to end users through the [CometChat Dashboard](https://app.cometchat.com) under **Moderation > Advanced Settings**. The platform provides a set of default flagging reasons that cover common moderation scenarios, or you can create custom reasons that align with your platform's specific community guidelines and policies. +## Enable Flagging in Your App - - - + + + The Report Message feature is available in CometChat UI Kits. Users can report messages directly from the message actions menu: + + + } href="/ui-kit/react/core-features#report-message" horizontal /> + } href="/ui-kit/react-native/core-features" horizontal /> + } href="/ui-kit/android/core-features" horizontal /> + } href="/ui-kit/ios/core-features" horizontal /> + } href="/ui-kit/flutter/core-features" horizontal /> + } href="/ui-kit/angular/core-features" horizontal /> + } href="/ui-kit/vue/overview" horizontal /> + + + + Implement message flagging directly using CometChat Chat SDKs: + + + } href="/sdk/javascript/flag-message" horizontal /> + } href="/sdk/react-native/flag-message" horizontal /> + } href="/sdk/android/flag-message" horizontal /> + } href="/sdk/ios/flag-message" horizontal /> + } href="/sdk/flutter/flag-message" horizontal /> + + + -Flag reasons can also be configured via the [Reason APIs](/rest-api/moderation/create-reasons). +--- ## Managing Flagged Messages ### List Flagged Messages -Retrieves the list of messages that have been flagged by the moderation system or manually by users. +View all messages pending review in the Flagged Messages tab. -**REST API:** [List Flagged Messages](/rest-api/moderation/list-flagged-messages) - ---- +### Approve Message -### Approve Flagged Message - -Approving a flagged message indicates that it has been reviewed and is considered acceptable according to platform guidelines. The message remains visible to all users. +Approving indicates the message is acceptable. It remains visible to all users and moves to the Reviewed list. -**REST API:** [Approve/Block Flagged Message](/rest-api/moderation/blockreview-flagged-message) - ---- - -### Block Flagged Message +### Block Message -Blocking a flagged message marks it as disapproved and moves it to the reviewed list. Blocked messages are hidden from the conversation and are no longer visible to users. +Blocking marks the message as disapproved. It's hidden from the conversation and moves to the Reviewed list. -**REST API:** [Approve/Block Flagged Message](/rest-api/moderation/blockreview-flagged-message) + +**Bulk actions supported.** Select multiple flagged messages and approve or block them in a single action. + + +--- -## Frequently Asked Questions +## FAQ - Blocked messages are hidden from the conversation and are no longer visible to users. The message is marked as disapproved and moved to the Reviewed list in the Dashboard. + Blocked messages are hidden from the conversation and no longer visible to users. The message is marked as disapproved and moved to the Reviewed list. By default, users are not notified when their message is blocked. The message simply becomes hidden from the conversation. - Yes, the Dashboard supports bulk actions. You can select multiple flagged messages and approve or block them in a single action. + Yes, the Dashboard supports bulk actions. Select multiple flagged messages and approve or block them in a single action. + + + Flagged messages are pending review and remain visible until a moderator takes action. Blocked messages are immediately hidden and don't require review. + +--- + +## Related Resources + + + + Configure rules to auto-flag messages + + + View immediately blocked content + + + Create keyword lists for flagging + + + Learn about the moderation system + + diff --git a/moderation/getting-started.mdx b/moderation/getting-started.mdx index b88f4245..7232311d 100644 --- a/moderation/getting-started.mdx +++ b/moderation/getting-started.mdx @@ -9,90 +9,85 @@ To maintain a safe, respectful, and engaging environment for your users, our pla With Moderation Integration, you can define flexible rules, receive real-time updates, and ensure your app meets community guidelines, legal standards, and brand values without manual intervention. - -If you’re using the CometChat UI Kit or SDK, you can skip steps 2 and 3. - +--- + +## Choose Your Integration Method + + + + **Zero code required** — Moderation is built into CometChat UI Kits. Simply configure rules in the Dashboard and the UI Kit handles everything automatically. + + + **Full control** — Use the CometChat SDK to handle moderation programmatically in your custom UI implementation. + + --- ## Integrate Moderation -Note: If you're using CometChat UI Kits or SDKs, you can skip steps 2 & 3. +**Using UI Kit?** You only need Step 1 - the UI Kit handles moderation automatically! - -

Define content moderation rules for your app's messaging system.

- - - -

Set up a webhook to receive real-time moderation events.

- -
- -

Use APIs to send and review flagged messages programmatically.

- -
+ + Define content moderation rules for your app's messaging system. + + + + If building a custom UI, implement moderation handling in your code. See [SDK Integration](#integrating-moderation-with-sdk) below. + + + Set up webhooks to receive real-time moderation events on your server. + + --- -## Key Components of Moderation Integration - - -**Step 1:** [Set up moderation rules](#setting-up-moderation-rules) - -**Step 2:** [Configure a moderation webhook](#configuring-a-moderation-webhook) - -**Step 3:** [Integrate and test the Moderation API](#integrating-and-testing-the-moderation-api) - ---- - ## Setting Up Moderation Rules Moderation rules act as filters to ensure that the messages exchanged within your app meet your safety and content guidelines. ### How It Works -- When a message, image, or video is submitted, it is automatically checked against the moderation rules you’ve configured. +- When a message, image, or video is submitted, it is automatically checked against the moderation rules you've configured. - These rules can detect offensive language, sensitive content, spam, scams, and more. - Based on your settings, content can be: - **Approved:** Delivered to the recipient. - **Disapproved:** Blocked and not delivered. - - **Flagged:** Delivered to the recipient, but flagged. + - **Flagged:** Delivered to the recipient, but flagged for review. ### Benefits - **Safety first:** Protect your users and brand from harmful or unwanted content. -- **Customizable:** Fine-tune moderation rules to suit your app’s unique needs. +- **Customizable:** Fine-tune moderation rules to suit your app's unique needs. - **Seamless experience:** Moderation happens in real time, keeping communication flowing smoothly. ### Creating Moderation Rules CometChat provides a set of **default moderation rules** designed to cover common use cases such as offensive language, spam, and inappropriate content. You can enable these rules to start moderating messages immediately, without any additional setup. -{/* ![Default moderation rules](/images/existing-rules.png) */} -If you have specific requirements, you can create **custom moderation rules** tailored to your app’s needs. Rules can be created in two ways: +If you have specific requirements, you can create **custom moderation rules** tailored to your app's needs: 1. **Using the CometChat Dashboard** — A simple, no-code interface for visually creating and managing moderation rules. - {/* ![Create rule screen](/images/create-rule.png) */} + -2. **Using the CometChat API** — Programmatically create and manage moderation rules for advanced or automated workflows. See the [Create Rule API documentation]({apiEndpoints.createRule.url}). + +2. **Using the CometChat API** — Programmatically create and manage moderation rules for advanced or automated workflows. See the [Rules Management](/moderation/rules-management) documentation. --- @@ -100,30 +95,18 @@ If you have specific requirements, you can create **custom moderation rules** ta To automate your moderation flow and receive updates in real time, configure a **moderation webhook**. This allows your system to react instantly when a message or media is moderated. + +Webhooks are optional if you're using the SDK's `onMessageModerated` listener for real-time updates. + + ### How It Works - Every time content is moderated, a webhook event is triggered and sent to the URL you specify. - Your application can then take action based on the moderation result. -### Prerequisites - -- Your webhook URL must be accessible over **HTTPS** to ensure secure data transmission. -- The URL should be publicly accessible from the internet. -- Ensure your endpoint supports the `HTTP POST` method. Event payloads will be delivered via `POST` requests in JSON format. -- Configure your endpoint to respond immediately to the CometChat server with a `200 OK` response. -- For security, set up **Basic Authentication** (username and password) for server-to-server communication. - -When your webhook URL is triggered, the HTTP header includes: - -```http -Authorization: Basic -``` - ### Handle Moderation Events -Ensure your webhook endpoint is ready to process moderation events. Refer to the [Moderation Events](/docs-beta/fundamentals/webhooks-overview#moderation-events) section for the full list. - -The key events to handle include: +The key webhook events to handle include: - `moderation_engine_approved` — Triggered when the engine automatically approves content. - `moderation_engine_blocked` — Triggered when the engine automatically blocks content. @@ -133,104 +116,379 @@ To receive these events, enable the relevant webhooks in the CometChat Dashboard > **Application → Webhooks → Create Webhook → Triggers → Moderation** -Select all three moderation triggers to ensure your app receives the necessary notifications. - -{/* ![Enable webhooks](/images/webhook-events.png) */} --- -## Integrating and Testing the Moderation API +## Integrating Moderation with SDK + +Once your moderation rules are configured in the Dashboard, integrate moderation into your application using the CometChat SDK. The SDK automatically handles moderation for all messages sent through CometChat. + + +**Using UI Kit?** Skip this section - the UI Kit handles everything automatically! + + +### Send a Message and Check Moderation Status + +When you send a message, it's automatically checked against your moderation rules. The message object contains a `moderationStatus` property: + + + + ```javascript + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMessage(textMessage).then( + (message) => { + const status = message.getModerationStatus(); + + switch (status) { + case CometChat.ModerationStatus.PENDING: + console.log("Message is under moderation review"); + break; + case CometChat.ModerationStatus.APPROVED: + console.log("Message approved and delivered"); + break; + case CometChat.ModerationStatus.DISAPPROVED: + console.log("Message blocked by moderation"); + break; + } + }, + (error) => { + console.log("Message sending failed:", error); + } + ); + ``` + + + ```kotlin + val textMessage = TextMessage( + receiverUID, + "Hello, how are you?", + CometChatConstants.RECEIVER_TYPE_USER + ) + + CometChat.sendMessage(textMessage, object : CometChat.CallbackListener() { + override fun onSuccess(message: TextMessage) { + when (message.moderationStatus) { + ModerationStatus.PENDING -> Log.d(TAG, "Message under review") + ModerationStatus.APPROVED -> Log.d(TAG, "Message approved") + ModerationStatus.DISAPPROVED -> Log.d(TAG, "Message blocked") + } + } + + override fun onError(e: CometChatException) { + Log.e(TAG, "Message sending failed: ${e.message}") + } + }) + ``` + + + ```swift + let textMessage = TextMessage( + receiverUid: receiverUID, + text: "Hello, how are you?", + receiverType: .user + ) + + CometChat.sendTextMessage(message: textMessage) { sentMessage in + if let message = sentMessage as? TextMessage { + switch message.getModerationStatus() { + case "pending": + print("Message under review") + case "approved": + print("Message approved") + case "disapproved": + print("Message blocked") + default: + break + } + } + } onError: { error in + print("Message sending failed: \(error?.errorDescription ?? "")") + } + ``` + + + ```javascript + const textMessage = new CometChat.TextMessage( + receiverUID, + "Hello, how are you?", + CometChat.RECEIVER_TYPE.USER + ); + + CometChat.sendMessage(textMessage).then( + (message) => { + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.PENDING) { + console.log("Message under review"); + } else if (status === CometChat.ModerationStatus.DISAPPROVED) { + console.log("Message blocked"); + } + }, + (error) => console.log("Failed:", error) + ); + ``` + + + ```dart + TextMessage textMessage = TextMessage( + text: "Hello, how are you?", + receiverUid: receiverUID, + receiverType: ReceiverTypeConstants.user, + ); + + CometChat.sendMessage( + textMessage, + onSuccess: (TextMessage message) { + switch (message.moderationStatus?.value) { + case ModerationStatusEnum.PENDING: + print("Message under review"); + break; + case ModerationStatusEnum.APPROVED: + print("Message approved"); + break; + case ModerationStatusEnum.DISAPPROVED: + print("Message blocked"); + break; + } + }, + onError: (CometChatException e) { + print("Message sending failed: ${e.message}"); + }, + ); + ``` + + + +### Listen for Moderation Results + +Register a message listener to receive real-time moderation updates when the moderation engine finishes processing: + + + + ```javascript + const listenerID = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageModerated: (message) => { + const status = message.getModerationStatus(); + const messageId = message.getId(); + + if (status === CometChat.ModerationStatus.APPROVED) { + console.log(`Message ${messageId} approved - show in UI`); + // Update UI to display the message + } else if (status === CometChat.ModerationStatus.DISAPPROVED) { + console.log(`Message ${messageId} blocked`); + // Hide message or show blocked placeholder + } + } + }) + ); + + // Remove listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + ```kotlin + val listenerID = "MODERATION_LISTENER" + + CometChat.addMessageListener(listenerID, object : CometChat.MessageListener() { + override fun onMessageModerated(message: BaseMessage) { + when (message.moderationStatus) { + ModerationStatus.APPROVED -> { + Log.d(TAG, "Message ${message.id} approved") + // Update UI to display the message + } + ModerationStatus.DISAPPROVED -> { + Log.d(TAG, "Message ${message.id} blocked") + // Hide message or show blocked placeholder + } + } + } + }) + + // Remove listener when done + // CometChat.removeMessageListener(listenerID) + ``` + + + ```swift + let listenerID = "MODERATION_LISTENER" + + CometChat.addMessageListener(listenerID, self) + + // Implement CometChatMessageDelegate + extension YourViewController: CometChatMessageDelegate { + func onMessageModerated(moderatedMessage: BaseMessage) { + if let message = moderatedMessage as? TextMessage { + switch message.getModerationStatus() { + case "approved": + print("Message \(message.id) approved") + // Update UI to display the message + case "disapproved": + print("Message \(message.id) blocked") + // Hide message or show blocked placeholder + default: + break + } + } + } + } + + // Remove listener when done + // CometChat.removeMessageListener(listenerID) + ``` + + + ```javascript + const listenerID = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + new CometChat.MessageListener({ + onMessageModerated: (message) => { + const status = message.getModerationStatus(); + + if (status === CometChat.ModerationStatus.APPROVED) { + // Update UI to display the message + } else if (status === CometChat.ModerationStatus.DISAPPROVED) { + // Hide message or show blocked placeholder + } + } + }) + ); + ``` + + + ```dart + const listenerID = "MODERATION_LISTENER"; + + CometChat.addMessageListener( + listenerID, + MessageListener( + onMessageModerated: (BaseMessage message) { + if (message.moderationStatus?.value == ModerationStatusEnum.APPROVED.value) { + print("Message ${message.id} approved"); + // Update UI to display the message + } else if (message.moderationStatus?.value == ModerationStatusEnum.DISAPPROVED.value) { + print("Message ${message.id} blocked"); + // Hide message or show blocked placeholder + } + }, + ), + ); + + // Remove listener when done + // CometChat.removeMessageListener(listenerID); + ``` + + + + +### Handle Blocked Messages in UI + +When a message is blocked (disapproved), handle it appropriately in your UI: + + + + ```javascript + function handleBlockedMessage(message) { + const messageId = message.getId(); + const senderUid = message.getSender().getUid(); + + // Option 1: Hide the message completely + removeMessageFromUI(messageId); + + // Option 2: Show a placeholder + showPlaceholder(messageId, "This message was blocked by moderation"); + + // Option 3: Notify the sender + if (senderUid === currentUserUID) { + showToast("Your message was blocked due to policy violation"); + } + } + ``` + + + ```kotlin + fun handleBlockedMessage(message: BaseMessage) { + val messageId = message.id + val senderUid = message.sender.uid + + // Option 1: Hide the message completely + removeMessageFromUI(messageId) + + // Option 2: Show a placeholder + showPlaceholder(messageId, "This message was blocked by moderation") + + // Option 3: Notify the sender + if (senderUid == currentUserUID) { + Toast.makeText(context, "Your message was blocked", Toast.LENGTH_SHORT).show() + } + } + ``` + + + ```swift + func handleBlockedMessage(_ message: BaseMessage) { + let messageId = message.id + let senderUid = message.sender?.uid + + // Option 1: Hide the message completely + removeMessageFromUI(messageId) + + // Option 2: Show a placeholder + showPlaceholder(messageId, text: "This message was blocked by moderation") + + // Option 3: Notify the sender + if senderUid == currentUserUID { + showAlert("Your message was blocked due to policy violation") + } + } + ``` + + + +### Moderation Status Reference + +| Status | Value | Description | +|--------|-------|-------------| +| Pending | `PENDING` | Message is being processed by moderation engine | +| Approved | `APPROVED` | Message passed moderation and is visible to recipients | +| Disapproved | `DISAPPROVED` | Message violated rules and was blocked | -Once your moderation rules and webhook are configured, integrate the **Moderation API** into your application to programmatically submit content and receive moderation results. - -### Steps to Integrate and Test - -1. **Submit content:** Use the API to send messages, images, or videos for moderation. -2. **Check responses:** Verify moderation status in real time. -3. **Handle outcomes:** Apply business logic based on approved, flagged, or disapproved responses. -4. **End-to-end testing:** Test both the API response and webhook delivery to ensure complete coverage. - -When you’re ready, you can render all moderation endpoints dynamically: - -### Send message - -This endpoint is used to submit a message for moderation before it is delivered to the recipient. The message is scanned against the moderation rules configured for the app. - -**URL:** -``` -https://api-explorer.cometchat.com/reference/chat-api-send-message-moderation -``` - -**Request Body:** -```json -{ - "category": "message", - "type": "text", - "data": { - "text": "Hi new user" - }, - "sender": "cometchat-uid-2", - "receiver": "cometchat-uid-1", - "receiverType": "user", - "sentAt": 1750335220 -} -``` - -### List messages -Retrieves a list of messages submitted for moderation, along with the current moderation status of each message as determined by your configured rules. - -**URL:** -``` -https://api-explorer.cometchat.com/reference/chat-api-list-message-moderation/ -``` - -### Get message -Retrieves the details of a specific message submitted for moderation, including its current moderation status as determined by your configured rules. - -**URL:** -``` -https://api-explorer.cometchat.com/reference/chat-api-get-message-moderation/ -``` - -### Update message -Edits an existing message. The moderation status is re-evaluated based on your configured rules. - -**URL:** -``` -https://api-explorer.cometchat.com/reference/chat-api-update-message-moderation/ -``` - -### Delete message -Deletes a previously submitted message along with its associated moderation data, in accordance with your configured rules. - -**URL:** -``` -https://api-explorer.cometchat.com/reference/chat-api-delete-message-moderation/ -``` +--- -### Approve message -Approves a previously blocked message, allowing it to be delivered to the recipient. +## REST API (Advanced) -**URL:** -``` -https://api-explorer.cometchat.com/reference/chat-api-approve-moderation-blocked-messages/ -``` +For server-side integrations or advanced use cases, you can also use the REST API directly: ---- +| Endpoint | Purpose | +|----------|---------| +| [Send Message](/rest-api/moderation) | Submit content for moderation | +| [List Messages](/rest-api/moderation) | Retrieve moderated messages with filters | +| [Approve Message](/rest-api/moderation) | Manually approve a blocked message | -| Endpoint | Purpose | -| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| **Send message for moderation**
`POST /moderation/messages` | Submits a new message for moderation. Triggers the engine, emits a webhook, and makes the message available via the get-message endpoint. | -| **Edit message for moderation**
`PUT /moderation/messages/:id` | Re-evaluates an edited message. If approved, the updates are accepted; if blocked, the message is withheld. | -| **Get message moderation status**
`GET /moderation/messages/:id`| Retrieves the moderation status, rule metadata, and action history of a message. | -| **List messages for moderation**
`GET /moderation/messages` | Lists all moderated messages with optional filters such as category, type, status, and receiver UID/GUID. | -| **Delete message from moderation**
`DELETE /moderation/messages/:id` | Deletes a moderated message. | + +For most use cases, the SDK integration above is recommended as it handles moderation automatically. + --- ## Summary -By combining well-defined moderation rules, automated webhooks, and robust API integration, you can build a safe, scalable, and user-friendly content moderation system tailored to your app’s values and audience expectations. +By combining well-defined moderation rules with SDK integration, you can build a safe and user-friendly content moderation system: + +- **UI Kit users**: Just configure rules in the Dashboard - everything else is automatic +- **SDK users**: Implement `onMessageModerated` listener to handle moderation results +- **REST API**: Available for server-side or advanced integrations diff --git a/moderation/lists-management.mdx b/moderation/lists-management.mdx index 992193ef..3d9b78ed 100644 --- a/moderation/lists-management.mdx +++ b/moderation/lists-management.mdx @@ -2,173 +2,219 @@ title: "Lists Management" --- -## Overview +Lists Management provides tools for creating and managing lists of keywords, regex patterns, or sentences that power your moderation rules. When detected in user-generated content, these lists trigger moderation actions like blocking or flagging messages. -The Lists Management endpoints in the Moderation Service API provide essential tools for creating and managing lists of keywords or regex patterns that are crucial for effective message moderation. These endpoints enable app owners and collaborators to define specific terms, phrases, or patterns that, when detected in user-generated content, trigger moderation actions. The next section provides a detailed elaboration of the capabilities offered. + +**Lists are reusable.** Create a list once and use it across multiple rules. Update the list in one place and all rules using it are automatically updated. + - - - - -To begin managing lists: - -* Login to your [CometChat dashboard](https://app.cometchat.com/login) and choose your app. -* Navigate to **Moderation** > **Settings** in the left-hand menu. -* Select the **Lists** tab. - -## Default Lists - -Default lists are predefined lists of words, patterns and sentences that are readily available for use on your platform. Here are the standard default lists available: - -### Profane Words - -Our default list is a comprehensive compilation of predefined profane words and phrases. This list is designed to enhance message moderation efforts by automatically identifying and flagging inappropriate language. - -### Platform Circumvention - -The Platform Cicurvention list contains a curated set of sentences and words designed to identify attempts to circumvent platform rules and policies. These phrases are used by the AI Platform Circumvention Rule to detect and prevent efforts aimed at bypassing restrictions, ensuring compliance and maintaining platform integrity. - -### Spam Detection - -The Default Spam Detection List identifies repetitive or irrelevant messages promoting products, services, or schemes without user consent. It helps filter out unwanted content, including bulk messages, phishing attempts, and fraudulent offers, ensuring a cleaner and more secure communication experience. - -### Scam Detection - -The Default Scam Detection List includes messages crafted to deceive users by creating a sense of urgency, promising false rewards, or impersonating trusted entities. These messages often aim to manipulate users into sharing personal information, making payments, or clicking on malicious links. The list helps identify and block scams, protecting users from fraud, phishing attempts, and other deceptive practices. - -### Fraud or Scam Indicators Prompt - -The Fraud or Scam Indicators list is designed to detect manipulated images used for fraudulent or deceptive activities. It helps flag fake documents, counterfeit products, and misleading visuals that could be used to scam users or spread misinformation. - -### Terrorism or Extremist Promotion Prompt - -The Terrorism or Extremist Promotion list identifies imagery that endorses terrorism, violent extremism, or radical ideologies. It helps prevent the spread of extremist propaganda, recruitment materials, and content that incites violence. - -### Minor Safety and Exploitation Prompt - -The Minor Safety and Exploitation list is used to detect sexualized or exploitative imagery of minors. It helps prevent child abuse, grooming, and the sharing of harmful content, ensuring compliance with child protection policies. - -### Privacy or Personal Data Prompt - -The Privacy or Personal Data list flags images that expose sensitive or private information, such as identification documents, financial details, or personal records. This helps prevent identity theft, unauthorized data leaks, and privacy violations. - -### Graphic Violence or Gore Prompt - -The Graphic Violence or Gore list identifies violent or gory imagery, including depictions of severe injuries, crime scenes, or graphic deaths. It helps limit exposure to disturbing content and ensures a safer viewing experience. - -### Explicit or Sexual Content Prompt - -The Explicit or Sexual Content list is designed to detect nudity, sexually explicit imagery, or highly suggestive content. It helps enforce platform guidelines by filtering out inappropriate material. - -### Hate or Harassment Prompt - -The Hate or Harassment list flags imagery containing hateful symbols, offensive gestures, or harassment. It helps identify and prevent content that promotes discrimination, hate speech, or targeted abuse. - -### Hate and Harassment Prompt - -The Hate and Harassment list detects messages that contain hate speech, threats, slurs, or harassment directed at individuals or groups. It helps create a respectful and safe online environment by preventing abusive behavior. - -### Explicit or Inappropriate Content Prompt +--- -The Explicit or Inappropriate Content list identifies text that includes explicit sexual descriptions, extreme violence, or other unsuitable material. It helps ensure compliance with content policies and maintains platform integrity. +## Quick Start -### Impersonation or Fraud Prompt +Create a custom keyword list in under 2 minutes: -The Impersonation or Fraud list detects deceptive attempts to impersonate individuals, businesses, or organizations. It helps prevent identity theft, scam attempts, and fraudulent activities. + + + Login to [CometChat Dashboard](https://app.cometchat.com) → Select your app → **Moderation** → **Settings** → **Lists** + + + Click **Add** → Enter a name, select category (word/pattern/sentence), and add your terms + + + Go to **Rules** → Create or edit a rule → Select your list in the Conditions section + + -### Non-Consensual Sexual Content or Exploitation Prompt + + + -The Non-Consensual Sexual Content or Exploitation list flags messages that depict or encourage non-consensual sexual acts, grooming, or coercion. It helps protect users from exploitation and ensures adherence to safety policies. +--- -### Privacy and Sensitive Info Prompt +## List Types + + + + Simple word matching. Use for: + - Profanity and offensive terms + - Brand names or competitors + - Industry-specific blocked terms + + **Example:** `badword, offensive, blocked` + + + Regular expression matching for complex patterns. Use for: + - Phone number formats + - Email patterns + - Custom data formats + + **Example:** `\b\d{3}[-.]?\d{3}[-.]?\d{4}\b` (US phone numbers) + + + AI-powered semantic matching. Use for: + - Scam message variations + - Platform circumvention attempts + - Context-aware blocking + + **Example:** "Send me your credit card details" will match similar phishing attempts + + -The Privacy and Sensitive Info list identifies messages that share personal or sensitive information without consent. It helps protect user privacy by preventing unauthorized data exposure. +--- -### Self-Harm or Suicidal Content Prompt +## Default Lists Summary + +Pre-configured lists ready to use with your rules: + + + + | List | Description | Use Case | + |------|-------------|----------| + | **Profane Words** | Common profanity and inappropriate language | General chat moderation | + | **Platform Circumvention** | Phrases attempting to bypass rules | Marketplace, dating apps | + | **Spam Detection** | Repetitive/promotional message patterns | High-traffic apps | + | **Scam Detection** | Deceptive messages and phishing attempts | Finance, marketplace | + | **Hate and Harassment Prompt** | Hate speech, threats, and slurs | Community platforms | + | **Explicit Content Prompt** | Sexual descriptions and violence | Family-friendly apps | + | **Privacy and Sensitive Info Prompt** | Personal data sharing | Healthcare, finance | + | **Self-Harm Content Prompt** | Self-harm and suicidal content | Mental health safety | + | **Spam and Scam Prompt** | Phishing and fraudulent schemes | All apps | + | **Violent Threats Prompt** | Violence and terrorism promotion | All apps | + | **Impersonation Prompt** | Identity fraud attempts | Business apps | + | **Non-Consensual Content Prompt** | Exploitation and grooming | Dating, social apps | + + + | List | Description | Use Case | + |------|-------------|----------| + | **Hate or Harassment Prompt** | Hateful symbols and offensive gestures | Community platforms | + | **Explicit or Sexual Content Prompt** | Nudity and sexually explicit imagery | Social apps | + | **Graphic Violence Prompt** | Violent imagery and gore | Family-friendly apps | + | **Privacy or Personal Data Prompt** | IDs, financial docs, personal records | Finance, healthcare | + | **Minor Safety Prompt** | Child exploitation content | All apps | + | **Fraud or Scam Indicators Prompt** | Fake documents and counterfeit images | Marketplace | + | **Terrorism Prompt** | Extremist propaganda and recruitment | All apps | + + -The Self-Harm or Suicidal Content list detects messages indicating self-harm, suicidal thoughts, or encouragement of self-injury. It helps enable early intervention and support mental health safety. +--- -### Spam and Scam Prompt +## When to Create Custom Lists + + + + Add terms specific to your industry that default lists don't cover: + - **Gaming:** Game-specific slurs, exploit terms + - **Finance:** Competitor names, prohibited investment terms + - **Healthcare:** Medical misinformation terms + + + Block mentions of: + - Competitor names + - Prohibited external links + - Trademark violations + + + Add localized profanity or slang that default English lists miss. + + + Create lists for your unique community guidelines: + - Prohibited topics + - Off-platform contact attempts + - Community-specific terms + + -The Spam and Scam list identifies spam messages, phishing attempts, and fraudulent schemes. It helps filter out unwanted content, including bulk messages and misleading offers, ensuring a cleaner and more secure communication environment. +--- -### Violent or Terroristic Threats Prompt +## Best Practices + + + + Use default lists first, then create custom lists only for gaps in coverage. + + + Scammers constantly change wording. Sentence similarity catches variations automatically. + + + Test regex patterns before deploying. A bad pattern can block legitimate content. + + + Check blocked messages monthly and update lists based on new patterns. + + + +### Tips for Effective Lists + +1. **Keep lists focused** - Create separate lists for different purposes (profanity vs. spam vs. competitors) +2. **Use CSV for bulk imports** - Upload large keyword lists via CSV instead of manual entry +3. **Combine list types** - Use keywords for exact matches + sentence similarity for variations +4. **Document your lists** - Add clear descriptions so team members understand each list's purpose -The Violent or Terroristic Threats list detects content that promotes violence, terrorism, or extremist actions. It helps prevent harmful speech, glorification of violence, and threats against individuals or groups. +--- ## Managing Lists ### Create List -Allows you to define new moderation lists specifying the words or patterns under which text or custom messages should be blocked. - -Creating a new list from the dashboard: - -1. Click the Add button within the Lists tab. - -2. Create the list by saving the following details: - - * Name: Descriptive name for the moderation list. - * ID: The unique identifier of the list. - * Category: Choose the type for list, either 'word', 'pattern' or 'sentence similarity'. - * Description: Detailed explanation of the list. - * Your Source type for lists could be either words, patterns or sentences, separated by a comma or a CSV file. +1. Click **Add** in the Lists tab +2. Configure: + - **Name**: Descriptive name for the list + - **ID**: Unique identifier + - **Category**: Word, Pattern, or Sentence Similarity + - **Description**: Purpose of the list + - **Source**: Enter terms manually (comma-separated) or upload CSV +3. Click **Save** -3. Save +### List All Lists -You can also set this up from your end using the [Create Moderation List REST API](https://api-explorer.cometchat.com/reference/create-rule-keyword). - -### Fetch All Lists - -Fetches the details of existing list lists. +All configured lists are displayed in the Lists tab with their name, category, and item count. -You can also set this up from your end using the [List Moderation Lists REST API](https://api-explorer.cometchat.com/reference/list-rule-keywords). - -### Get List - -Fetches the details of an existing list. You can set this up from your end using the [Get Moderation List REST API](https://api-explorer.cometchat.com/reference/get-rule-keyword). - ### Update List -Allows you to update existing lists, which includes modifying the list name, category, and individual words or patterns within the list. - -Updating a list from the dashboard: - -1. Click on "Edit" in the action menu of the List you want to update. - -2. Update the list by saving the following details: - - * Name: Descriptive name for the moderation list. - * Category: Choose the type for List, either 'word', 'pattern' or 'sentence similarity'. - * Description: Detailed explanation of the list. - * Your Source type for list could be either words, patterns or sentences separated by a comma or a CSV file. - -3. Save - -You can also set this up from your end using the [Update Moderation List REST API](https://api-explorer.cometchat.com/reference/update-rule-keyword). +1. Click **Edit** in the action menu +2. Modify the list settings or add/remove terms +3. Click **Save** ### Delete List -Allows for the removal of lists from the system that are no longer needed. - -Deleting a list from the dashboard: +Click **Delete** in the action menu and confirm. + + +Deleting a list will affect any rules using it. Check rule dependencies before deleting. + -* Click "Delete" in the action menu of the list you want to remove, then confirm. +--- -You can also set this up from your end using the [Delete Moderation List REST API](https://api-explorer.cometchat.com/reference/delete-rule-keyword). +## Related Resources + + + + Create rules that use your lists + + + View content blocked by your lists + + + Review flagged content + + + Learn about the moderation system + + diff --git a/moderation/reviewed-messages.mdx b/moderation/reviewed-messages.mdx index ee4a1e93..e9383893 100644 --- a/moderation/reviewed-messages.mdx +++ b/moderation/reviewed-messages.mdx @@ -2,14 +2,118 @@ title: "Reviewed Messages" --- -## Overview +Reviewed Messages is your audit trail for all moderation decisions. When a moderator takes action on a flagged or blocked message (approve, block, or mark as reviewed), it automatically moves here for record-keeping. -The Reviewed Messages endpoint in the Moderation Service API provides app owners and collaborators with access to messages that have been processed by moderators after being flagged/blocked. This endpoint contains the complete audit trail of moderation decisions made on previously flagged/blocked content. + +**Complete moderation history.** Use this dashboard to track moderator activity, audit decisions, and maintain compliance records. + -Once a moderator makes either decision, the message is automatically transferred from the Flagged/Blocked Messages list to the Reviewed Messages list. This reviewed list serves as a comprehensive record of all moderation decisions, providing transparency and accountability in your content moderation workflow. +--- + +## Quick Start + +Access your moderation history: + + + + Login to [CometChat Dashboard](https://app.cometchat.com) → Select your app → **Moderation** → **Reviewed Messages** + + + Use date range, status, or moderator filters to find specific decisions + + + Click on any message to see the original content, rule triggered, and moderator action taken + + -Reviewed messages list can also be fetched via API [List Reviewed Messages](/rest-api/moderation/list-reviewed-messages). +--- + +## How Messages Get Here + +```mermaid +flowchart LR + A[Flagged Message] -->|Approve| C[Reviewed Messages] + A -->|Block| C + B[Blocked Message] -->|Approve| C + B -->|Mark as Reviewed| C +``` + +| Source | Action Taken | Result | +|--------|--------------|--------| +| Flagged Message | Approved | Message visible, marked reviewed | +| Flagged Message | Blocked | Message hidden, marked reviewed | +| Blocked Message | Approved | Message unblocked, marked reviewed | +| Blocked Message | Mark as Reviewed | Message stays blocked, marked reviewed | + +--- + +## What You Can See + +Each reviewed message includes: + +| Field | Description | +|-------|-------------| +| **Message Content** | The original text, image, or media that was moderated | +| **Sender** | User who sent the message | +| **Rule Triggered** | Which moderation rule flagged/blocked the message | +| **Action Taken** | Approved, Blocked, or Marked as Reviewed | +| **Moderator** | Who made the decision | +| **Timestamp** | When the decision was made | + +--- + +## Use Cases + + + + Maintain records of all moderation decisions for regulatory compliance. + + + Track moderator activity and decision patterns. + + + Analyze which rules generate the most reviews to optimize your setup. + + + Reference historical decisions when users dispute moderation actions. + + + +--- + +## FAQ + + + + You cannot directly undo from the Reviewed Messages list. However, if a message was blocked, you can find it and approve it to make it visible again. + + + Reviewed messages are stored according to your data retention settings. Check your app settings for specific retention periods. + + + Yes, you can export reviewed messages for compliance or analysis purposes from the Dashboard. + + + +--- + +## Related Resources + + + + Messages pending review + + + Automatically blocked content + + + Configure moderation rules + + + Learn about the moderation system + + diff --git a/moderation/rules-management.mdx b/moderation/rules-management.mdx index 73706ca1..10829fd8 100644 --- a/moderation/rules-management.mdx +++ b/moderation/rules-management.mdx @@ -4,614 +4,479 @@ title: "Rules Management" ## Overview -The Rules Management endpoints in the Moderation Service API provide the functionality to define and manage moderation rules that help in identifying and handling inappropriate content based on a variety of conditions. These endpoints empower app owners and collaborators to create a customized message moderation strategy tailored to the specific needs of their platform. The next section provides a detailed elaboration of the capabilities offered. +Rules Management allows you to define and manage moderation rules that automatically detect and handle inappropriate content. Configure rules once in the Dashboard, and they're automatically applied to all messages sent through CometChat. - - - - -To begin managing rules: - -* Login to your [CometChat dashboard](https://app.cometchat.com/login) and choose your app. -* Navigate to **Moderation** > **Settings** in the left-hand menu. -* Select the **Rules** tab. - -## Default Rules - -Default rules are predefined sets of message moderation conditions that are readily available for use on your platform, and automatically applied to moderate messages when enabled. These default rules form the foundation of an effective message moderation strategy, combining automation with customizable options to ensure a safe, respectful, and compliant environment for platform users. Here are the standard default rules available: - -### Profanity Filter - -This feature automatically detects and manages text and custom messages containing offensive language, profanity, or derogatory remarks using a predefined list of offensive keywords to block inappropriate content. Ensuring user interactions maintain a respectful tone and comply with community standards, enhances overall platform decency. - -**Example** - -Before enabling the profanity filter, messages containing profane words are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### Contact Details Filter - -This feature detects and manages messages containing phone numbers by applying rules to prevent the sharing of private information that could compromise user privacy or security. It protects users from potential misuse of personal data and ensures compliance with data protection regulations. - -**Example** - -Before enabling the contact details filter, messages containing phone numbers are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### Email Filter - -This feature detects and manages messages containing email addresses by applying rules to prevent the sharing of private information that could compromise user privacy or security. It protects users from potential misuse of personal data and ensures compliance with data protection regulations. - -**Example** - -Before enabling the email filter, a message containing an email address is delivered to the receiver and can be seen on the receiver's chat screen. After enabling the filter, such messages are not delivered to the receiver, like in the example where the personal email isn't delivered to the receiver. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### AI-based Image Moderation - -This feature identifies and manages image-type messages containing sensitive, explicit, or prohibited content using advanced artificial intelligence algorithms for image recognition. Once detected, the system automatically blocks the images that violate platform guidelines, ensuring that such content is not displayed to users. This proactive approach safeguards users from exposure to harmful visual material, maintaining a safe and compliant environment on the platform. - -\**Example* - -Non-violating images are being delivered as seen in the example. Enabling this filter blocks violating images that are not delivered to the receiver, like in the example where the second image is indicated by a single tick in the message status on the sender's screen and isn't delivered to the receiver. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### AI-based Video Moderation - -This feature identifies and manages video-type messages containing sensitive, explicit, or prohibited content using advanced artificial intelligence algorithms for image recognition. Once detected, the system automatically blocks the images that violate platform guidelines, ensuring that such content is not displayed to users. This proactive approach safeguards users from exposure to harmful visual material, maintaining a safe and compliant environment on the platform. - -**Example** - -Before enabling the AI-based Video Moderation filter, a message containing violating videos is delivered to the receiver, like in the example where the first video can be seen on the receiver's chat screen. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status on the sender's chat screen. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### AI Message Toxicity - -The AI Message Toxicity Detection rule is a powerful, AI-driven tool designed to identify and flag toxic, harmful, or inappropriate language within user-generated messages. This feature analyzes text in real-time, detecting patterns of abusive speech, such as threats, harassment, hate speech, and other forms of offensive communication. By automatically blocking these messages based on predefined moderation rules, the tool helps prevent the spread of toxic content, fostering a safer and more respectful communication environment. This system empowers platform administrators to maintain community standards, allowing them to intervene or moderate flagged messages promptly. It also supports various languages and contexts, ensuring that the platform remains compliant with safety guidelines and user conduct policies. - -**Example** - -Before enabling the AI message toxicity rule, a message containing a sentence which violates AI message toxicity is delivered to the receiver and can be seen on the receiver's chat screen. After enabling the filter, such messages are not delivered to the receiver. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### AI Platform Circumvention - -The AI Platform Circumvention Rule employs a list of categories related to sentence similarity to identify and manage attempts by users to circumvent platform rules. This filter analyzes user-generated content for patterns and phrases that may indicate efforts to bypass established guidelines. By leveraging AI technology, it compares new submissions against a predefined set of sentence structures and categories to detect similarities that suggest rule violations. - -**Example** - -Before enabling the platform circumvention filter, a message containing a sentence which violates platform circumvention is delivered to the receiver and can be seen on the receiver's chat screen. After enabling the filter, such messages are not delivered to the receiver. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### AI Scam Detection - -The AI Scam Detection rule leverages advanced AI-powered text moderation techniques to identify and prevent scam-related messages in real-time. By analyzing message patterns and identifying specific language markers and behaviors commonly associated with scams, this rule ensures that fraudulent schemes are swiftly intercepted before reaching users. This proactive detection system scans for misleading content, phishing attempts, fake offers, and other tactics typically employed by scammers, thereby safeguarding users and maintaining the trust and security of the platform. It also continuously adapts to evolving scam strategies through machine learning, making it more effective over time. - -**Example** - -Before enabling the AI Scam Detection rule, a message containing a sentence which violates AI Scam Detection rule is delivered to the receiver and can be seen on the receiver's chat screen. After enabling the filter, such messages are not delivered to the receiver. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### AI Spam Detection - -AI Spam Detection uses sophisticated AI algorithms to automatically detect and filter out spam messages in real-time. By analyzing message content and patterns, it effectively identifies unwanted or irrelevant communications, reducing the risk of spam flooding your platform. This feature helps ensure a cleaner, more efficient messaging experience, allowing users to focus on genuine, meaningful interactions. - -**Example** - -Before enabling the AI Spam Detection rule, a message containing a sentence which violates AI Spam Detection rule is delivered to the receiver and can be seen on the receiver's chat screen. After enabling the filter, such messages are not delivered to the receiver. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### OpenAI (Message): Hate and Harassment Prompt (All Languages) - -This feature uses a predefined OpenAI moderation prompt to detect hateful or harassing language toward individuals or groups. By automatically identifying and blocking such content, it ensures a respectful and inclusive environment, fostering positive interactions among users. - -**Example** - -Before enabling the hate and harassment detection, messages containing hateful or harassing language are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Privacy and Sensitive Info Prompt (All Languages) - -This feature leverages OpenAI to detect messages that share personal or sensitive information without consent. It helps prevent unauthorized disclosure of private data, safeguarding user privacy and maintaining compliance with data protection standards. - -**Example** - -Before enabling the privacy and sensitive information detection, messages containing personal or sensitive information are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Explicit or Inappropriate Content Prompt (All Languages) - -This feature identifies and manages messages containing explicit sexual descriptions, graphic violence, or other unsuitable text using OpenAI moderation. It ensures that such content is automatically blocked, maintaining a safe and appropriate environment for all users. - -**Example** - -Before enabling the explicit or inappropriate content detection, messages containing explicit or inappropriate content are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Spam and Scam Prompt (All Languages) - -This feature uses OpenAI to detect and block spam messages, phishing attempts, and fraudulent schemes. By filtering out malicious or unwanted content, it enhances user trust and protects them from potential scams or harmful activities. - -**Example** - -Before enabling the spam and scam detection, messages containing spam or scam content are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Violent or Terroristic Threats Prompt (All Languages) - -This feature identifies content that encourages, promotes, or glorifies violence or extremism using OpenAI moderation. It ensures that such messages are automatically blocked, contributing to a safer and more secure platform for all users. + +**Using UI Kit or SDK?** Once you configure rules in the Dashboard, they are automatically applied to all messages. No additional code is required - the UI Kit and SDK handle moderation seamlessly. + -**Example** - -Before enabling the violent or terroristic threats detection, messages containing violent or terroristic content are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Non-Consensual Sexual Content or Exploitation Prompt (All Languages) - -This feature detects messages related to sexual exploitation, grooming, or non-consensual content using OpenAI moderation. It proactively blocks such content, protecting users from harmful interactions and maintaining a safe environment. - -**Example** - -Before enabling the non-consensual sexual content or exploitation detection, messages containing such content are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Impersonation or Fraud Prompt (All Languages) - -This feature identifies deceptive attempts to impersonate individuals or organizations using OpenAI moderation. By detecting and blocking such content, it prevents fraudulent activities and ensures the authenticity of user interactions. - -**Example** - -Before enabling the impersonation or fraud detection, messages containing impersonation or fraudulent content are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Message): Self-Harm or Suicidal Content Prompt (All Languages) - -This feature uses OpenAI to detect messages suggesting self-harm, suicidal thoughts, or related instructions. It helps identify and address potentially harmful content, providing a supportive environment and connecting users with appropriate resources when needed. - -**Example** - -Before enabling the self-harm or suicidal content detection, messages containing such content are delivered to the receiver, as indicated by double ticks in the message status. After enabling the filter, such messages are not delivered to the receiver, which is indicated by a single tick in the message status. - - - - - -The blocked messages are then visible on the dashboard for monitoring purposes. - - - - - -### OpenAI (Image): Hate or Harassment Prompt - -This feature uses a predefined OpenAI moderation prompt to detect hate symbols, extremist insignia, and harassing imagery in images. By automatically identifying and blocking such content, it ensures a respectful and safe environment for all users. - -**Example** - -Before enabling the hate or harassment detection for images, images containing hate symbols or harassing content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. - - - - - -The blocked images are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Image): Explicit or Sexual Content Prompt - -This feature leverages OpenAI to identify nudity, explicit sexual content, or suggestive imagery unsuitable for general audiences. It ensures that such images are automatically blocked, maintaining a safe and appropriate environment. - -**Example** - -Before enabling the explicit or sexual content detection, images containing explicit or suggestive content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. - - - - - -The blocked images are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Image): Graphic Violence or Gore Prompt - -This feature uses OpenAI to detect images of extreme violence, gore, or other disturbing content. It ensures that such images are automatically blocked, contributing to a safer and more secure platform. - -**Example** - -Before enabling the graphic violence or gore detection, images containing violent or disturbing content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. - - - - - -The blocked images are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Image): Privacy or Personal Data Prompt - -This feature identifies images containing personal or sensitive data, such as IDs, addresses, or financial documents, using OpenAI moderation. It helps prevent unauthorized sharing of private information, safeguarding user privacy. - -**Example** - -Before enabling the privacy or personal data detection, images containing sensitive information are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. - - - - - -The blocked images are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Image): Self-Harm or Suicidal Content Prompt - -This feature uses OpenAI to detect imagery suggesting self-harm, suicidal ideation, or content that promotes self-injury. It helps identify and address potentially harmful content, providing a supportive environment. - -**Example** - -Before enabling the self-harm or suicidal content detection, images containing such content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. - - - - - -The blocked images are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Image): Minor Safety and Exploitation Prompt - -This feature detects child sexual content, exploitative imagery of minors, or unsafe depictions of children using OpenAI moderation. It proactively blocks such content, protecting minors and maintaining a safe environment. - -**Example** - -Before enabling the minor safety and exploitation detection, images containing exploitative or unsafe content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. - - - - - -The blocked images are then visible on the dashboard for monitoring purposes. - - - - - -*** - -### OpenAI (Image): Fraud or Scam Indicators Prompt +--- -This feature flags manipulated or fraudulent images, such as fake IDs or doctored screenshots, using OpenAI moderation. It helps prevent fraudulent activities and ensures the authenticity of user interactions. +## Quick Start -**Example** +Enable moderation in under 2 minutes: -Before enabling the fraud or scam indicators detection, images containing fraudulent or manipulated content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. + + + Login to [CometChat Dashboard](https://app.cometchat.com) → Select your app → **Moderation** → **Settings** → **Rules** + + + Toggle on the rules you need (e.g., Profanity Filter, AI Image Moderation) + + + Send a test message that violates the rule - it should be blocked automatically + + - + -The blocked images are then visible on the dashboard for monitoring purposes. +--- - - - +## Available Rules Summary + + + + | Rule | Description | Use Case | + |------|-------------|----------| + | **Profanity Filter** | Blocks offensive language using keyword matching | General chat apps | + | **Contact Details Filter** | Blocks phone numbers | Marketplaces, dating apps | + | **Email Filter** | Blocks email addresses | Prevent off-platform contact | + | **AI Toxicity Detection** | AI-powered detection of toxic language | Community platforms | + | **AI Spam Detection** | Detects spam messages | High-traffic apps | + | **AI Scam Detection** | Identifies fraudulent messages | Marketplaces, finance apps | + | **AI Platform Circumvention** | Detects attempts to bypass rules | All apps | + + + | Rule | Description | Use Case | + |------|-------------|----------| + | **AI Image Moderation** | Blocks explicit/unsafe images | All apps with image sharing | + | **OpenAI Explicit Content** | Detects nudity and sexual content | Social apps, dating | + | **OpenAI Violence/Gore** | Blocks graphic violence | Family-friendly apps | + | **OpenAI Hate Symbols** | Detects hate imagery | Community platforms | + | **OpenAI Privacy Data** | Blocks images with personal data | Finance, healthcare | + + + | Rule | Description | Use Case | + |------|-------------|----------| + | **AI Video Moderation** | Blocks explicit/unsafe video content | Apps with video sharing | + + + | Rule | Type | Description | + |------|------|-------------| + | **Hate & Harassment** | Text/Image | Detects hateful or harassing content | + | **Explicit Content** | Text/Image | Blocks sexual or graphic content | + | **Privacy & Sensitive Info** | Text/Image | Protects personal data | + | **Spam & Scam** | Text | Identifies fraudulent schemes | + | **Violence & Terrorism** | Text/Image | Blocks violent extremism | + | **Self-Harm Content** | Text/Image | Detects self-harm references | + | **Impersonation & Fraud** | Text | Prevents identity fraud | + | **Minor Safety** | Image | Protects minors from exploitation | + + -*** +--- -### OpenAI (Image): Terrorism or Extremist Promotion Prompt +## Recommended Rules by Use Case + + + + **Essential:** + - Profanity Filter + - AI Toxicity Detection + - AI Image Moderation + - OpenAI Hate & Harassment + + **Recommended:** + - AI Spam Detection + - OpenAI Explicit Content + + + **Essential:** + - Contact Details Filter + - Email Filter + - AI Scam Detection + - AI Platform Circumvention + + **Recommended:** + - Profanity Filter + - AI Image Moderation + + + **Essential:** + - Contact Details Filter + - Email Filter + - AI Image Moderation + - OpenAI Explicit Content + + **Recommended:** + - AI Scam Detection + - OpenAI Privacy Data (Image) + + + **Essential:** + - Profanity Filter + - AI Toxicity Detection + - AI Spam Detection + + **Recommended:** + - OpenAI Hate & Harassment + - AI Image Moderation + + + **Essential:** + - OpenAI Privacy & Sensitive Info + - OpenAI Privacy Data (Image) + - AI Scam Detection + + **Recommended:** + - Profanity Filter + - Contact Details Filter + + -This feature detects extremist propaganda, terrorist symbols, or images promoting violent ideologies using OpenAI moderation. It ensures that such images are automatically blocked, contributing to a safer platform. +--- -**Example** +## Best Practices + + + + Enable default rules first, then customize based on your needs. Don't try to configure everything at once. + + + Test rules in a staging environment. Send test messages to verify rules work as expected. + + + Check the [Blocked Messages](/moderation/blocked-messages) dashboard regularly to catch false positives. + + + Review [Rule Revisions](#rule-revisions) to track changes and refine rules over time. + + + +### Tips for Effective Moderation + +1. **Layer your rules** - Use multiple rules together (e.g., Profanity Filter + AI Toxicity) for better coverage +2. **Adjust confidence levels** - Lower confidence = more aggressive blocking, higher = fewer false positives +3. **Use Flag action for borderline content** - Instead of blocking, flag messages for manual review +4. **Create custom keyword lists** - Add industry-specific terms to the [Lists Management](/moderation/lists-management) -Before enabling the terrorism or extremist promotion detection, images containing extremist or violent content are delivered to the receiver. After enabling the filter, such images are not delivered to the receiver. +--- - - - +## Default Rules -The blocked images are then visible on the dashboard for monitoring purposes. +Default rules are pre-configured and ready to use. Simply toggle them on in the Dashboard. + + + + + + Automatically detects and blocks messages containing offensive language, profanity, or derogatory remarks using a predefined list of offensive keywords. + + **Example:** Before enabling, profane messages are delivered (double ticks). After enabling, they're blocked (single tick). + + + + + + + Detects and blocks messages containing phone numbers to prevent sharing of private contact information. + + + + + + + Detects and blocks messages containing email addresses to prevent off-platform communication. + + + + + + + AI-powered detection of toxic, harmful, or inappropriate language including threats, harassment, and hate speech. Supports multiple languages. + + + + + + + Detects attempts by users to bypass platform rules using sentence similarity analysis. + + + + + + + Identifies scam-related messages including phishing attempts, fake offers, and fraudulent schemes. + + + + + + + Detects and filters spam messages by analyzing content patterns and identifying unwanted communications. + + + + + + + + + + + Uses AI to identify and block images containing sensitive, explicit, or prohibited content. + + + + + + + Detects hate symbols, extremist insignia, and harassing imagery. + + + + + + + Identifies nudity, explicit sexual content, or suggestive imagery. + + + + + + + Detects images of extreme violence, gore, or disturbing content. + + + + + + + Identifies images containing personal data like IDs, addresses, or financial documents. + + + + + + + Detects imagery suggesting self-harm or suicidal ideation. + + + + + + + Detects exploitative imagery of minors or unsafe depictions of children. + + + + + + + Flags manipulated or fraudulent images like fake IDs or doctored screenshots. + + + + + + + Detects extremist propaganda, terrorist symbols, or violent ideologies. + + + + + + + + + + + Uses AI to identify and block videos containing sensitive, explicit, or prohibited content. + + + + + + + + + + + + + + + Detects hateful or harassing language toward individuals or groups using OpenAI moderation. + + + + + + + Detects messages sharing personal or sensitive information without consent. + + + + + + + Identifies explicit sexual descriptions, graphic violence, or unsuitable text. + + + + + + + Detects spam messages, phishing attempts, and fraudulent schemes. + + + + + + + Identifies content promoting violence or extremism. + + + + + + + Detects sexual exploitation, grooming, or non-consensual content. + + + + + + + Identifies deceptive attempts to impersonate individuals or organizations. + + + + + + + Detects messages suggesting self-harm or suicidal thoughts. + + + + + + + + - - - +--- -## Rule Filters, Conditions and Actions +## Rule Configuration ### Filters -Filters allow you to narrow down messages based on the Sender or Receiver of a message. +Filters narrow down which messages are checked by a rule based on sender or receiver attributes: -For Senders, you can filter by specific properties like UID, Role, Name, and Tags, or see when the sender was created. Similarly, for Receivers, you can filter by properties such as Name, GUID, Tags, Group type or see when the receiver was created, and the Type of receiver (for example, a user or group). This enables targeted filtering based on user or group attributes within the conversation. +| Filter Type | Properties | +|-------------|------------| +| **Sender** | UID, Role, Name, Tags, Created date | +| **Receiver** | Name, GUID, Tags, Group type, Created date, Type (user/group) | ### Conditions -Conditions allow you to define criteria for blocking messages based on their type—text, image, video, or custom. +Conditions define what content triggers the rule: -You can select a keyword list, define a list of words or patterns, for text and custom messages. +| Content Type | Available Conditions | +|--------------|---------------------| +| **Text/Custom** | Keyword list, Word patterns, Toxicity, Sentiment, Sentence similarity | +| **Image/Video** | Violence, Gambling, Alcohol, Drugs, Nudity, Hate symbols, Unsafe content | -In addition to selecting specific words, patterns, or lists for text and custom messages, you can also choose filters based on Toxicity, Sentiment, or Sentence Similarity for more advanced moderation and content analysis. You can refine Toxicity filtering by selecting categories such as Identity Attack, Insult, Obscene, Mild Toxicity, or Severe Toxicity. For Sentiment, you can choose to filter messages based on positive or negative sentiment. In Sentence Similarity, you have the option to apply a default or custom list. Additionally, you can set a confidence percentage for each criterion to determine the threshold for blocking messages. - -For media messages you can select among categories like Violence, Gambling, Alcohol, Drugs and Tobacco, Rude gestures, Explicity nudity, Non-explicit nudity, Swimwear or underwear, Visually disturbing, Hate symbols or Any unsafe content. Additionally, you can set a confidence percentage for each criterion to determine the threshold for blocking messages. +You can set a **confidence percentage** for AI-based conditions to control sensitivity. ### Actions -Actions specify what happens when content matches the conditions. In addition to blocking the message by default, actions include options such as banning or kicking a user from a group and blocking a user. +Actions determine what happens when content matches the conditions: -## Configuring rules +| Action | Description | +|--------|-------------| +| **Block** | Message is not delivered (default) | +| **Flag** | Message is delivered but flagged for review | +| **Ban User** | User is banned from the group | +| **Kick User** | User is removed from the group | +| **Block User** | User is blocked platform-wide | -### Create Rule +--- + +## Managing Rules -Allows you to define new moderation rules specifying the conditions under which messages should be blocked. +### Create Rule -Creating a new rule from the dashboard: - -1. Click the Add button within the Rules tab. - -2. Configure the Rule by saving the following details: - - * Name: Name for the moderation rule. - * Rule ID: The unique identifier of the rule. - * Description: Detailed explanation of the rule's purpose. - * Filter: List of filters that must be met for the rule to trigger. - * Condition: List of conditions that must be met for the rule to trigger. - * Action: Choose from a set of actions to be taken when a violation is detected. - -3. Save - -4. Enable the Rule to start moderating! - -You can also set this up from your end using the [Create Moderation Rule REST API](https://api-explorer.cometchat.com/reference/create-rule). +1. Click **Add** in the Rules tab +2. Configure: + - **Name**: Descriptive name for the rule + - **Rule ID**: Unique identifier + - **Description**: Purpose of the rule + - **Filter**: Who the rule applies to + - **Condition**: What triggers the rule + - **Action**: What happens when triggered +3. Click **Save** +4. **Enable** the rule to start moderating ### List Rules -Fetches the details of the existing list of rules. +All configured rules are displayed in the Rules tab with their name, status, and actions. -You can also set this up from your end using the [List Moderation Rules REST API](https://api-explorer.cometchat.com/reference/list-rules). - -### Get Rule - -Fetches the details of a rule. You can set this up from your end using the [Get Moderation Rule REST API](https://api-explorer.cometchat.com/reference/get-rule). - ### Update Rule -Enables modifications to existing rules. This includes changing conditions, updating actions, or refining parameters to improve accuracy. +1. Click **Edit** in the action menu +2. Modify the rule settings +3. Click **Save** -Updating a rule from the dashboard: - -1. Click on "Edit" in the action menu of the rule you want to update. - -2. Update the Rule by saving the following details: - - * Name: Descriptive name for the moderation rule. - * Description: Detailed explanation of the rule's purpose. - * Filter: List of filters that must be met for the rule to trigger. - * Condition: List of conditions that must be met for the rule to trigger. - * Action: Choose from a set of actions to be taken when a violation is detected. - -3. Save - -You can also set this up from your end using the [Update Moderation Rule REST API](https://api-explorer.cometchat.com/reference/update-rule). - ### Delete Rule -Permits the deletion of outdated or unnecessary rules from the system. This helps in maintaining an efficient and relevant set of moderation guidelines. +Click **Delete** in the action menu and confirm. -Deleting a rule from the dashboard: - -* Click "Delete" in the action menu of the rule you want to remove, then confirm. - -You can also set this up from your end using the [Delete Moderation Rule REST API](https://api-explorer.cometchat.com/reference/delete-rule). - ### Rule Revisions -The ability to fetch all revisions of a rule in a moderation system allows app owners and collaborators to retrieve a comprehensive history of updates and changes made to specific moderation rules over time. This feature provides detailed insights into how rules have been adjusted and refined to better manage and moderate content on the platform. +Track the history of changes made to a rule: + +1. Click **View** in the action menu +2. Navigate to **Rule History** -Viewing the rule revisions on the dashboard: - -1. Click "View" in the action menu of the rule for which you wish to see revisions. -2. Navigate to the Rule History section. +--- -You can also set this up from your end using the [Get Moderation Rule Revisions REST API](https://api-explorer.cometchat.com/reference/list-rule-revisions). +## Related Resources + + + + Create custom keyword lists for your rules + + + View and manage blocked content + + + Review flagged content + + + Handle moderation in custom UI + + diff --git a/ui-kit/android/core-features.mdx b/ui-kit/android/core-features.mdx index ab972822..a4701b2e 100644 --- a/ui-kit/android/core-features.mdx +++ b/ui-kit/android/core-features.mdx @@ -155,6 +155,10 @@ Learn more about how flagged messages are handled, reviewed, and moderated in th CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + + + Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. diff --git a/ui-kit/flutter/core-features.mdx b/ui-kit/flutter/core-features.mdx index df32595c..8c1e87d7 100644 --- a/ui-kit/flutter/core-features.mdx +++ b/ui-kit/flutter/core-features.mdx @@ -126,6 +126,10 @@ Learn more about how flagged messages are handled, reviewed, and moderated in th CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + + + Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. diff --git a/ui-kit/ios/core-features.mdx b/ui-kit/ios/core-features.mdx index 5a89de83..ce0d2f50 100644 --- a/ui-kit/ios/core-features.mdx +++ b/ui-kit/ios/core-features.mdx @@ -179,6 +179,10 @@ Learn more about how flagged messages are handled, reviewed, and moderated in th CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + + + Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. diff --git a/ui-kit/react-native/core-features.mdx b/ui-kit/react-native/core-features.mdx index 9ba8e2e1..2e29a6b2 100644 --- a/ui-kit/react-native/core-features.mdx +++ b/ui-kit/react-native/core-features.mdx @@ -153,6 +153,10 @@ Learn more about how flagged messages are handled, reviewed, and moderated in th CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + + + Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. diff --git a/ui-kit/react/core-features.mdx b/ui-kit/react/core-features.mdx index 6f7c19e2..e1f2051d 100644 --- a/ui-kit/react/core-features.mdx +++ b/ui-kit/react/core-features.mdx @@ -159,6 +159,10 @@ The Threaded Conversations feature enables users to respond directly to a specif CometChat's Message Moderation feature helps maintain a safe and respectful chat environment by automatically filtering and managing inappropriate content. Messages can be automatically blocked or flagged based on predefined rules, ensuring harmful content is handled before it reaches users. + + + + Learn more about setting up moderation rules and managing content in the [Moderation](/moderation/overview) documentation. From 08788166c3aa07c348828d37e6fccec887e7641d Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Thu, 15 Jan 2026 21:54:42 +0530 Subject: [PATCH 6/9] docs(moderation): enhance dark mode support and simplify getting-started guide - Add dark mode styling to secondary action buttons with dark:border-gray-600, dark:text-gray-300, and dark:hover:bg-gray-700 classes - Update hover states for better visual consistency across light and dark themes - Remove REST API section to streamline documentation and reduce redundancy - Simplify summary section to focus on primary integration paths (UI Kit and SDK) - Improve visual hierarchy and user experience in the getting-started documentation --- moderation/getting-started.mdx | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/moderation/getting-started.mdx b/moderation/getting-started.mdx index 7232311d..ae71e642 100644 --- a/moderation/getting-started.mdx +++ b/moderation/getting-started.mdx @@ -35,7 +35,7 @@ With Moderation Integration, you can define flexible rules, receive real-time up Define content moderation rules for your app's messaging system. @@ -45,7 +45,7 @@ With Moderation Integration, you can define flexible rules, receive real-time up Set up webhooks to receive real-time moderation events on your server. @@ -469,26 +469,9 @@ When a message is blocked (disapproved), handle it appropriately in your UI: --- -## REST API (Advanced) - -For server-side integrations or advanced use cases, you can also use the REST API directly: - -| Endpoint | Purpose | -|----------|---------| -| [Send Message](/rest-api/moderation) | Submit content for moderation | -| [List Messages](/rest-api/moderation) | Retrieve moderated messages with filters | -| [Approve Message](/rest-api/moderation) | Manually approve a blocked message | - - -For most use cases, the SDK integration above is recommended as it handles moderation automatically. - - ---- - ## Summary By combining well-defined moderation rules with SDK integration, you can build a safe and user-friendly content moderation system: - **UI Kit users**: Just configure rules in the Dashboard - everything else is automatic - **SDK users**: Implement `onMessageModerated` listener to handle moderation results -- **REST API**: Available for server-side or advanced integrations From 9f798065ca124f8f734cd302fc6e533fa26fff89 Mon Sep 17 00:00:00 2001 From: Swapnil Godambe Date: Fri, 16 Jan 2026 20:09:06 +0530 Subject: [PATCH 7/9] Update docs.json --- docs.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs.json b/docs.json index 0174f316..efba4917 100644 --- a/docs.json +++ b/docs.json @@ -5689,6 +5689,14 @@ { "source": "/ai-chatbots/bots", "destination": "/ai-chatbots/ai-bots/bots" + }, + { + "source": "/sdk/android/setup-calling", + "destination": "/sdk/android/calling-setup" + }, + { + "source": "/sdk/ios/calling-integration", + "destination": "/sdk/ios/calling-integration" } ], "integrations": { From 9ce9d2c41e2c407323301b0e7537187733196369 Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Mon, 19 Jan 2026 19:49:40 +0530 Subject: [PATCH 8/9] docs(moderation): consolidate legacy extensions into single reference page - Consolidate 10 legacy moderation extension pages into unified legacy-extensions.mdx - Remove individual legacy extension documentation files (slow-mode, xss-filter, report-user, report-message, data-masking-filter, profanity-filter, image-moderation, sentiment-analysis, in-flight-message-moderation, virus-malware-scanner) - Remove webhooks-overview.mdx and reorganize moderation navigation structure - Update docs.json to reflect new moderation section hierarchy with Resources group - Add comprehensive redirect rules in docs.json for all legacy extension URLs to legacy-extensions page - Simplify Home product configuration by removing unnecessary tabs structure - Fix footer styling across multiple pages (ai-agents, calls, chat-call, chat) with marginBottom adjustment - Update .gitignore to exclude entire .kiro/ directory instead of specific file - Streamline moderation documentation navigation and improve maintainability --- .gitignore | 3 +- ai-agents.mdx | 2 +- calls.mdx | 2 +- chat-call.mdx | 2 +- chat.mdx | 2 +- docs.json | 85 +++-- fundamentals/extensions-overview.mdx | 11 +- fundamentals/moderation-extensions.mdx | 16 +- home.mdx | 53 +-- index.mdx | 98 ++--- moderation/custom/custom-api-overview.mdx | 55 ++- moderation/custom/custom-api.mdx | 138 +++++-- moderation/legacy-extensions.mdx | 348 ++++++++++++++++++ moderation/legacy/data-masking-filter.mdx | 151 -------- moderation/legacy/image-moderation.mdx | 207 ----------- .../legacy/in-flight-message-moderation.mdx | 57 --- moderation/legacy/profanity-filter.mdx | 155 -------- moderation/legacy/report-message.mdx | 131 ------- moderation/legacy/report-user.mdx | 147 -------- moderation/legacy/sentiment-analysis.mdx | 198 ---------- moderation/legacy/slow-mode.mdx | 271 -------------- moderation/legacy/virus-malware-scanner.mdx | 201 ---------- moderation/legacy/xss-filter.mdx | 72 ---- moderation/webhooks-overview.mdx | 4 - sdk/android/2.0/extensions.mdx | 8 +- sdk/ios/2.0/extensions.mdx | 8 +- ui-kit/android/extensions.mdx | 4 +- ui-kit/android/v4/extensions.mdx | 12 +- ui-kit/angular/extensions.mdx | 12 +- ui-kit/flutter/v4/extensions.mdx | 12 +- ui-kit/ios/extensions.mdx | 12 +- ui-kit/ios/v4/extensions.mdx | 12 +- ui-kit/react-native/v4/extensions.mdx | 12 +- ui-kit/react/v4/extensions.mdx | 12 +- 34 files changed, 642 insertions(+), 1871 deletions(-) create mode 100644 moderation/legacy-extensions.mdx delete mode 100644 moderation/legacy/data-masking-filter.mdx delete mode 100644 moderation/legacy/image-moderation.mdx delete mode 100644 moderation/legacy/in-flight-message-moderation.mdx delete mode 100644 moderation/legacy/profanity-filter.mdx delete mode 100644 moderation/legacy/report-message.mdx delete mode 100644 moderation/legacy/report-user.mdx delete mode 100644 moderation/legacy/sentiment-analysis.mdx delete mode 100644 moderation/legacy/slow-mode.mdx delete mode 100644 moderation/legacy/virus-malware-scanner.mdx delete mode 100644 moderation/legacy/xss-filter.mdx delete mode 100644 moderation/webhooks-overview.mdx diff --git a/.gitignore b/.gitignore index ea37644a..96adadbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .DS_Store - -.kiro/settings/mcp.json +.kiro/ diff --git a/ai-agents.mdx b/ai-agents.mdx index 73c00745..686eb805 100644 --- a/ai-agents.mdx +++ b/ai-agents.mdx @@ -131,7 +131,7 @@ Because CometChat AI Agents are model-agnostic, you can swap providers or upgrad {/* Footer */} -
+
2025 © CometChat diff --git a/calls.mdx b/calls.mdx index a7d5afa1..6ade1a19 100644 --- a/calls.mdx +++ b/calls.mdx @@ -283,7 +283,7 @@ import { CardGroup, Card, Icon, Badge, Steps, Columns, AccordionGroup, Accordion
{/* Footer */} -
+
2025 © CometChat diff --git a/chat-call.mdx b/chat-call.mdx index a1386dc9..3c59d0af 100644 --- a/chat-call.mdx +++ b/chat-call.mdx @@ -383,7 +383,7 @@ import { CardGroup, Card, Icon, Badge, Steps, Columns, AccordionGroup, Accordion {/* Footer */} -
+
2025 © CometChat diff --git a/chat.mdx b/chat.mdx index e9e88e94..1836a0df 100644 --- a/chat.mdx +++ b/chat.mdx @@ -444,7 +444,7 @@ import { CardGroup, Card, Icon, Badge, Steps, Columns, AccordionGroup, Accordion
{/* Footer */} -
+
2025 © CometChat diff --git a/docs.json b/docs.json index efba4917..3c9181a7 100644 --- a/docs.json +++ b/docs.json @@ -32,13 +32,8 @@ "products": [ { "product": "Home", - "tabs": [ - { - "tab": "Home", - "pages": [ - "index" - ] - } + "pages": [ + "index" ] }, { @@ -5011,21 +5006,11 @@ "moderation/custom/custom-api" ] }, - "moderation/webhooks-overview", - "moderation/api-explorer", { - "group": "Legacy Moderation (Extensions)", + "group": "Resources", "pages": [ - "moderation/legacy/slow-mode", - "moderation/legacy/report-user", - "moderation/legacy/report-message", - "moderation/legacy/data-masking-filter", - "moderation/legacy/profanity-filter", - "moderation/legacy/image-moderation", - "moderation/legacy/sentiment-analysis", - "moderation/legacy/in-flight-message-moderation", - "moderation/legacy/virus-malware-scanner", - "moderation/legacy/xss-filter" + "moderation/api-explorer", + "moderation/legacy-extensions" ] } ] @@ -5384,43 +5369,83 @@ }, { "source": "/extensions/slow-mode", - "destination": "/moderation/slow-mode" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/xss-filter", - "destination": "/moderation/xss-filter" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/report-user", - "destination": "/moderation/report-user" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/report-message", - "destination": "/moderation/report-message" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/data-masking-filter", - "destination": "/moderation/data-masking-filter" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/profanity-filter", - "destination": "/moderation/profanity-filter" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/image-moderation", - "destination": "/moderation/image-moderation" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/sentiment-analysis", - "destination": "/moderation/sentiment-analysis" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/in-flight-message-moderation", - "destination": "/moderation/in-flight-message-moderation" + "destination": "/moderation/legacy-extensions" }, { "source": "/extensions/virus-malware-scanner", - "destination": "/moderation/virus-malware-scanner" + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/slow-mode", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/xss-filter", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/report-user", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/report-message", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/data-masking-filter", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/profanity-filter", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/image-moderation", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/sentiment-analysis", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/in-flight-message-moderation", + "destination": "/moderation/legacy-extensions" + }, + { + "source": "/moderation/virus-malware-scanner", + "destination": "/moderation/legacy-extensions" }, { "source": "/ui-kit/react/v6", diff --git a/fundamentals/extensions-overview.mdx b/fundamentals/extensions-overview.mdx index 00914458..d6e58d1d 100644 --- a/fundamentals/extensions-overview.mdx +++ b/fundamentals/extensions-overview.mdx @@ -65,16 +65,7 @@ Extensions that help alert users of new messages. *Recommended for all apps.* *Extensions that help you to build a safe messaging environment.* *Recommended for live streaming and event apps.* -[Slow mode](/moderation/slow-mode)\ -[Report user](/moderation/report-user)\ -[Report message](/moderation/report-message)\ -[In-flight Message Moderation](/moderation/in-flight-message-moderation)\ -[Image Moderation](/moderation/image-moderation)\ -[Virus and Malware Scanner](/moderation/virus-malware-scanner)\ -[Data Masking Filter](/moderation/data-masking-filter)\ -[Profanity Filter](/moderation/profanity-filter)\ -[Sentiment Analysis](/moderation/sentiment-analysis)\ -[XSS Filter](/moderation/xss-filter) +[Legacy Moderation Extensions](/moderation/legacy-extensions) ### Security diff --git a/fundamentals/moderation-extensions.mdx b/fundamentals/moderation-extensions.mdx index f02017ea..4314fc67 100644 --- a/fundamentals/moderation-extensions.mdx +++ b/fundamentals/moderation-extensions.mdx @@ -4,18 +4,8 @@ title: "Moderation" CometChat Moderation features come in two variants: -1. The mordern rule based [Moderation](/moderation/overview) platform. +1. The modern rule based [Moderation](/moderation/overview) platform. -2. The [Legacy Moderation Extensions](/moderation/slow-mode) based on CometChat Extensions. +2. The [Legacy Moderation Extensions](/moderation/legacy-extensions) based on CometChat Extensions. - * [Slow Mode (Deprecated)](/moderation/slow-mode) - * [Report User (Legacy)](/moderation/report-user) - * [Report Message (Legacy)](/moderation/report-message) - * [Data Masking Filter (Legacy)](/moderation/data-masking-filter) - * [Profanity Filter (Legacy)](/moderation/profanity-filter) - * [Image Moderation (Legacy)](/moderation/image-moderation) - * [In-flight Message Moderation (Legacy)](/moderation/in-flight-message-moderation) - * [Virus and Malware Scanner (Legacy)](/moderation/virus-malware-scanner) - * [XSS Filter (Deprecated)](/moderation/xss-filter) - -For the best experience, we recommend to use the rule based [Moderation](/moderation/overview) platform. Please visit the above mentioned links for more details. +For the best experience, we recommend using the rule based [Moderation](/moderation/overview) platform. diff --git a/home.mdx b/home.mdx index 05eae3ba..0293bf62 100644 --- a/home.mdx +++ b/home.mdx @@ -5,57 +5,6 @@ description: "Technical documentation & Implementation guides to add In-app Mess canonical: "https://cometchat.com/docs" --- -export function openSearch() { - document.getElementById('search-bar-entry').click(); -} - -
- - -
-
-
- Get Started -
-

Seamlessly integrate real-time chat, voice, and video functionalities.

-
- -
-
-
-
-
+
diff --git a/index.mdx b/index.mdx index 3d3e0c41..8565bbf9 100644 --- a/index.mdx +++ b/index.mdx @@ -5,66 +5,31 @@ description: "Technical documentation & Implementation guides to add In-app Mess canonical: "https://cometchat.com/docs" --- -export function openSearch() { - document.getElementById('search-bar-entry').click(); -} +import { Columns } from 'mintlify'; -
+{/* Hero Section */} +
+
-
-
-
- Get Started +
+ +
+

CometChat

+

+ Seamlessly integrate real-time chat, voice, and video functionalities. +

-

Seamlessly integrate real-time chat, voice, and video functionalities.

-
-
-
+
-
- -Using Cursor, VS Code, Claude, Lovable, or any MCP-enabled tool? Add our CometChat Docs MCP so your AI always pulls the latest CometChat documentation. -

[Add CometChat Docs MCP](/mcp-server)
-
{/** Products Section */} @@ -109,7 +74,7 @@ export function openSearch() { } + icon={Chat and Calling} iconType="solid" href="/chat-call" > @@ -118,7 +83,7 @@ export function openSearch() { } + icon={AI Agents} iconType="solid" href="/ai-agents" > @@ -127,7 +92,7 @@ export function openSearch() { } + icon={AI Moderation} iconType="solid" href="/moderation/overview" > @@ -136,7 +101,7 @@ export function openSearch() { } + icon={Notifications} iconType="solid" href="/notifications/overview" > @@ -145,7 +110,7 @@ export function openSearch() { } + icon={Insights} iconType="solid" href="/insights" > @@ -212,13 +177,16 @@ export function openSearch() { > Stay informed of any service interruptions. - - -
- - + Add CometChat Docs MCP to your AI tools for instant documentation access. + + + +
-
+
diff --git a/moderation/custom/custom-api-overview.mdx b/moderation/custom/custom-api-overview.mdx index b3660af9..c65397ab 100644 --- a/moderation/custom/custom-api-overview.mdx +++ b/moderation/custom/custom-api-overview.mdx @@ -2,14 +2,53 @@ title: "Overview" --- -CometChat offers AI-powered message moderation to help maintain a safe and respectful chat environment. You can choose between two moderation options: +CometChat allows you to integrate your own moderation logic using a **Custom API**. This "bring your own moderation" approach lets you use any third-party service (OpenAI Moderation, Perspective API, etc.) or your own AI model while CometChat handles message interception and action enforcement. -### **Custom API Moderation** +## How It Works -If you prefer to use a third-party moderation service or your own AI model, CometChat enables integration via a **Custom Moderation API**. With this option, you can: -- **Set Up a Webhook** – Configure an endpoint where messages will be sent for moderation. -- **Customize Authentication** – Add security layers like basic authentication. -- **Contextual Moderation** – Define how many previous messages from the conversation should be included in the webhook request for better analysis. -- **Process Moderation Decisions** – CometChat processes the webhook response and applies moderation actions accordingly. +```mermaid +sequenceDiagram + participant User + participant CometChat + participant Your Webhook + + User->>CometChat: Sends message + CometChat->>Your Webhook: POST message + context + Your Webhook->>Your Webhook: Apply moderation logic + Your Webhook->>CometChat: Return decision + CometChat->>CometChat: Apply configured action + CometChat->>User: Message delivered or blocked +``` -This moderation provide flexibility to enhance user safety and compliance within your chat platform. +1. **User sends a message** in your chat application +2. **CometChat intercepts** the message and calls your webhook endpoint +3. **Your webhook processes** the message using your custom moderation logic +4. **Your webhook responds** with a decision (violation detected or not) +5. **CometChat applies the action** you configured (block, flag, allow, etc.) + +## Getting Started + + + + Create a webhook that receives messages and returns moderation decisions. You can use any third-party moderation service or your own AI model. + + + Set up your webhook URL, authentication, and moderation rules in the CometChat Dashboard. + + Step-by-step guide to configure your custom moderation API + + + + Set up webhooks to receive notifications when messages are approved or blocked by your moderation logic. + + Learn about moderation webhook events + + + + +## Key Features + +- **Contextual Moderation** – Include previous messages from the conversation for better analysis +- **Error Handling** – Configure fallback behavior when your API is unavailable +- **Flexible Rules** – Apply custom moderation to text or image content +- **Real-time Processing** – Moderation decisions are applied before message delivery diff --git a/moderation/custom/custom-api.mdx b/moderation/custom/custom-api.mdx index a6456d2e..291d49fe 100644 --- a/moderation/custom/custom-api.mdx +++ b/moderation/custom/custom-api.mdx @@ -2,63 +2,67 @@ title: "Custom API Moderation" --- -CometChat allows you to integrate your own moderation logic using a **Custom API**. With this feature, you can define a webhook URL in the **List Configuration**, where CometChat will send messages for moderation along with relevant context from the conversation (if provided in settings). - -## **How It Works** - -1. When a user sends a message, CometChat retrieves the webhook URL from the configured **List**. -2. The message, along with previous conversation messages (if a context window is set in settings), is sent to the webhook. -3. The webhook (your external API) processes the data using your custom moderation logic. -4. The webhook responds with a structured decision containing details about the moderation outcome. -5. CometChat processes the response and applies the moderation decision in real-time. - -This approach gives you complete control over moderation, allowing you to implement **custom filtering, AI-based analysis, or any other logic** on your own servers. +CometChat allows you to integrate your own moderation logic using a **Custom API**. With this feature, you can define a webhook URL where CometChat will send messages for moderation along with relevant context from the conversation. ## Integration ### Step 1: Configure Custom API Settings 1. **Login to the CometChat Dashboard** - - * Navigate to [CometChat Dashboard](https://app.cometchat.com) and select your app. + - Navigate to [CometChat Dashboard](https://app.cometchat.com) and select your app. 2. **Navigate to Moderation Settings** - - * Go to **Moderation → Settings** in the left-hand menu. + - Go to **Moderation → Settings** in the left-hand menu. 3. **Open Custom API Settings Tab** - - * Click on the **Custom API** tab within the Moderation Settings. + - Click on the **Custom API** tab within the Moderation Settings. 4. **Fill in the Custom API Configuration** - * **Set Action on API Error** + - **Webhook URL** + - Enter the endpoint URL where CometChat will send messages for moderation. - * Define how the system should respond if the Custom API is unavailable (e.g., "Allow message" or "Block message"). + - **Authentication (Optional)** + - Enable Basic Authentication to secure your webhook endpoint. + - Provide a username and password that CometChat will include in the `Authorization` header. - * **Set Context Window** + - **Set Action on API Error** + - Define how the system should respond if the Custom API is unavailable: + - **Allow message** – Messages are delivered even if moderation fails. + - **Block message** – Messages are blocked when moderation is unavailable. - * Specify the number of previous messages in a conversation that will be used for context. + - **Set Context Window** + - Specify the number of previous messages in a conversation to include for context (0-10). 5. **Click Save Settings** -### Step 2: Enable Custom API Moderation +### Step 2: Create a Moderation Rule 1. Navigate to **Moderation → Rules**. 2. Click **"Create New Rule"**. 3. Select **Custom API** as the moderation type. -4. The rule you create should be of type **"Text Contains"** or **"Image Contains"**. -5. Save the rule. +4. Choose the rule type: + - **Text Contains** – For text message moderation + - **Image Contains** – For image message moderation +5. Configure the action to take when content is flagged (block, flag for review, etc.). +6. Save the rule. -## Payload Sent to Webhook +## Webhook Request -When a message is sent, CometChat invokes your webhook with a payload that includes: +### Headers -* he latest message (the one just sent) — provided in full detail (entire message object) +When CometChat calls your webhook, it includes the following headers: -* The previous messages — provided as plain text only, for context (based on the context window setting) +| Header | Description | +|--------|-------------| +| `Content-Type` | `application/json` | +| `Authorization` | Basic auth credentials (if configured) | -This structure allows you to apply moderation logic to the current message while considering its surrounding context. +### Payload + +The payload includes: +- The latest message (the one just sent) — provided in full detail (entire message object) +- The previous messages — provided as plain text only, for context (based on the context window setting) ```json { @@ -115,21 +119,83 @@ This structure allows you to apply moderation logic to the current message while } }, "sentAt": 1747717214, - "updatedAt": 1747717214, + "updatedAt": 1747717214 } } ] } ``` -## Webhook Response Format +## Webhook Response + +Your webhook must return a JSON response indicating the moderation decision. + +### When content violates rules + +```json +{ + "isMatchingCondition": true, + "confidence": 0.95, + "reason": "Contains hate speech" +} +``` + +### When content is safe + +```json +{ + "isMatchingCondition": false, + "confidence": 0.98, + "reason": "" +} +``` + +### Response Fields -The webhook should return a response in the following format: +| Field | Type | Description | +|-------|------|-------------| +| `isMatchingCondition` | boolean | `true` if the message violates the rule, `false` if safe | +| `confidence` | number | Confidence score of the decision (0.0 - 1.0) | +| `reason` | string | Reason for flagging (can be empty for safe content) | + +## Example Webhook Implementation + +Here's a simple Node.js/Express example: ```javascript - { - isMatchingCondition: true, // True if the message violates the rule - confidence: 0.95, // Confidence score of the decision - reason: "Contains hate speech" // Reason for flagging +const express = require('express'); +const app = express(); + +app.use(express.json()); + +app.post('/moderate', (req, res) => { + const { contextMessages } = req.body; + + // Get the latest message (last item in array) + const latestEntry = contextMessages[contextMessages.length - 1]; + const senderId = Object.keys(latestEntry)[0]; + const messageData = latestEntry[senderId]; + + // Extract text content + const text = typeof messageData === 'string' + ? messageData + : messageData.data?.text || ''; + + // Your moderation logic here + const isViolation = containsBadContent(text); + + res.json({ + isMatchingCondition: isViolation, + confidence: 0.95, + reason: isViolation ? 'Content policy violation' : '' + }); +}); + +function containsBadContent(text) { + // Implement your moderation logic + // Could call OpenAI Moderation API, Perspective API, etc. + return false; } + +app.listen(3000); ``` diff --git a/moderation/legacy-extensions.mdx b/moderation/legacy-extensions.mdx new file mode 100644 index 00000000..b60a3692 --- /dev/null +++ b/moderation/legacy-extensions.mdx @@ -0,0 +1,348 @@ +--- +title: "Legacy Moderation Extensions" +sidebarTitle: "Legacy Extensions" +--- + + +These extensions are considered legacy and are scheduled for deprecation. They are no longer recommended for new integrations and will not receive feature updates or enhancements. + +For new projects, use [Custom API Moderation](/moderation/custom/custom-api-overview) or [OpenAI Moderation](/moderation/open-ai/openai-overview). + + +## Slow Mode + +Slow down messages in groups to make them legible during high-traffic events. + +When enabled in a group, participants can only send messages after configured intervals. Admins and moderators are not restricted. + +**Enable Slow Mode** + +```js +CometChat.callExtension('slow-mode', 'POST', 'v1/configure', { + "guid": "cometchat-guid-1", + "slowDownTimeInMS": 660000 +}).then(response => { + // Success +}).catch(error => { + // Error +}); +``` + +**Disable Slow Mode** + +```js +CometChat.callExtension('slow-mode', 'DELETE', 'v1/configure', { + "guid": "cometchat-guid-1" +}).then(response => { + // Success +}).catch(error => { + // Error +}); +``` + +**Fetch Slow Mode Details** + +```js +const guid = "cometchat-guid-1"; +CometChat.callExtension('slow-mode', 'GET', `v1/fetch-configuration?guid=${guid}`, null) + .then(response => { + // { isSlowed, slowDownTimeInMS, lastMessageSentAtTimestamp } + }); +``` + +--- + +## Report User + +Enables users to report other users for offensive or suspicious behavior. + +**Settings** + +1. Go to **Extensions** → Enable **Report User** +2. Configure moderation criteria (max reports before notification) +3. Set up webhook URL for reports + +**Report a User** + +```js +CometChat.callExtension('report-user', 'POST', 'v1/report', { + "uid": "cometchat-uid-3", + "reason": "Misbehaving", + "guid": "cometchat-guid-1" // Optional: only for group reports +}).then(response => { + // { success: true } +}); +``` + +**View Reports** + +Open the Extension's settings page and click "View Reports" to take action (Kick, Ban, Block, or Ignore). + +--- + +## Report Message + +Enable users to report messages in conversations. + +**Report a Message** + +```js +CometChat.callExtension('report-message', 'POST', 'v1/report', { + "msgId": 123, + "reason": "Contains profanity" +}).then(response => { + // { success: true } +}); +``` + +**View Reports** + +Open the Extension's settings page and click "View Reports" to Delete or Ignore reported messages. + +--- + +## Data Masking Filter + +Hide phone numbers, email addresses, and other sensitive information in messages. + +**Settings** + +1. Enable the extension +2. Configure default masks (Emails, SSN, US phone numbers) +3. Add custom regex patterns for additional masking + +**Response Format** + +```json +{ + "@injected": { + "extensions": { + "data-masking": { + "data": { + "sensitive_data": "yes", + "message_masked": "My number is ***** & my email id is ****" + } + } + } + } +} +``` + +**Implementation** + +```js +var metadata = message.getMetadata(); +if (metadata != null) { + var injectedObject = metadata["@injected"]; + if (injectedObject?.extensions?.["data-masking"]) { + var dataMaskingObject = injectedObject.extensions["data-masking"]["data"]; + var message_masked = dataMaskingObject["message_masked"]; + } +} +``` + +--- + +## Profanity Filter + +Mask or hide profanity in messages using a customizable blacklist. + +**Settings** + +1. Enable the extension +2. Optionally enable "Drop messages with Profanity" +3. Add comma-separated list of words to filter (supports emojis) + +**Response Format** + +```json +{ + "@injected": { + "extensions": { + "profanity-filter": { + "profanity": "yes", + "message_clean": "This is ****" + } + } + } +} +``` + +**Implementation** + +```js +var metadata = message.getMetadata(); +if (metadata != null) { + var injectedObject = metadata["@injected"]; + if (injectedObject?.extensions?.["profanity-filter"]) { + var profanityFilterObject = injectedObject.extensions["profanity-filter"]; + var cleanMessage = profanityFilterObject["message_clean"]; + } +} +``` + +--- + +## Image Moderation + +AI-powered image moderation to detect unsafe content. + +Images are classified into: +- Explicit Nudity +- Suggestive Nudity +- Violence +- Visually Disturbing + +**Response Format** + +```json +{ + "@injected": { + "extensions": { + "image-moderation": { + "unsafe": "yes", + "confidence": "99", + "category": "explicit_nudity" + } + } + } +} +``` + +A confidence value less than 50 is likely a false-positive. + +**Implementation** + +```js +const metadata = message.getMetadata(); +if (metadata != null) { + const injectedObject = metadata["@injected"]; + if (injectedObject?.extensions?.["image-moderation"]) { + const { attachments } = injectedObject.extensions["image-moderation"]; + for (const attachment of attachments) { + if (!attachment.error) { + const { unsafe } = attachment.data.verdict; + } + } + } +} +``` + +--- + +## Sentiment Analysis + +Understand the tone or sentiment of messages. + +Messages are classified as: Positive, Neutral, Negative, or Mixed. + +Supported languages: German, English, Spanish, Italian, Portuguese, French, Japanese, Korean, Hindi, Arabic, Chinese (simplified & traditional) + +**Response Format** + +```json +{ + "@injected": { + "extensions": { + "sentiment-analysis": { + "sentiment": "positive", + "sentiment_score": { + "positive": 95, + "neutral": 4, + "negative": 0, + "mixed": 0 + } + } + } + } +} +``` + +--- + +## In-Flight Message Moderation + +Manually moderate messages before delivery. + +**Settings** + +Configure moderation criteria: +- Moderate all messages, one-on-one only, or group only +- Moderate messages from specific users (UIDs) +- Moderate messages to specific users or groups + +**Actions** + +From the Dashboard, you can: +- **Approve**: Send the message to the receiver +- **Reject**: Delete the message +- **Kick**: Remove user from group (can rejoin) +- **Ban**: Ban user from group (cannot rejoin) + +--- + +## Virus & Malware Scanner + +Scan uploaded files for malicious content using [Scanii](https://scanii.com). + +**Prerequisites** + +Create a Scanii account and get your API Key and Secret. + +**Response Format** + +```json +{ + "@injected": { + "extensions": { + "virus-malware-scanner": { + "attachments": [{ + "data": { + "url": "https://media.com/file.mp3", + "verdict": { + "scan_results": [] + } + }, + "error": null + }] + } + } + } +} +``` + +An empty `scan_results` array means the file is safe. + +--- + +## XSS Filter + +Sanitize messages to prevent cross-site scripting attacks. Applicable only for Web SDK. + +**Response Format** + +```json +{ + "@injected": { + "extensions": { + "xss-filter": { + "hasXSS": "yes", + "sanitized_message": "" + } + } + } +} +``` + +**Implementation** + +```js +var metadata = message.getMetadata(); +if (metadata != null) { + var injectedObject = metadata["@injected"]; + if (injectedObject?.extensions?.["xss-filter"]) { + var xssFilterObject = injectedObject.extensions["xss-filter"]; + var sanitized_message = xssFilterObject["sanitized_message"]; + } +} +``` diff --git a/moderation/legacy/data-masking-filter.mdx b/moderation/legacy/data-masking-filter.mdx deleted file mode 100644 index 8bae55ac..00000000 --- a/moderation/legacy/data-masking-filter.mdx +++ /dev/null @@ -1,151 +0,0 @@ ---- -title: "Data Masking Filter (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -The Data Masking Extension allows you to hide phone numbers, email address and other sensitive information in messages. You as a developer, can add regular expressions for matching & masking. - -## Extension settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. - -2. Go to the Extensions section and enable the Data Masking Filter extension. - -3. Open the Settings for this extension and configure the following: - - 1. Drop Message: If enabled, any message with sensitive information will be dropped. - 2. Default Masks: Masks for Emails, Social Security Numbers (SSN), US phone numbers are built in. - 3. Custom Masks: Add more regex that will act as masks for some form of sensitive information. - -4. Save the extension settings. - - - -Refer [this](https://www.w3schools.com/jsref/jsref_obj_regexp.asp) for more details on Regular Expressions. - - - -## How does it work? - -Once the Extension is enabled for your App and the Extension Settings are done, the recipients will receive metadata with the masked message. Here is a sample response: - - - -```json -"@injected": { - "extensions": { - "data-masking": { - "data": { - "sensitive_data": "yes", - "message_masked": "My number is ***** & my email id is ****" - } - } - } -} -``` - - - - - -If the data-masking key is missing, it means that the extension is either not enabled or has timed out. - -## Implementation - -At the recipients' end, from the message object, you can fetch the metadata by calling the getMetadata() method. Using this metadata, you can fetch the masked message. - - - -```js -var metadata = message.getMetadata(); -if (metadata != null) { - var injectedObject = metadata["@injected"]; - if (injectedObject != null && injectedObject.hasOwnProperty("extensions")) { - var extensionsObject = injectedObject["extensions"]; - if ( - extensionsObject != null && - extensionsObject.hasOwnProperty("data-masking") - ) { - var dataMaskingFilterObject = extensionsObject["data-masking"]["data"]; - var sensitive_data = dataMaskingFilterObject["sensitive_data"]; - var message_masked = dataMaskingFilterObject["message_masked"]; - } - } -} -``` - - - - -```java -JSONObject metadata = message.getMetadata(); -if (metadata != null) { - JSONObject injectedObject = metadata.getJSONObject("@injected"); - if (injectedObject != null && injectedObject.has("extensions")) { - JSONObject extensionsObject = injectedObject.getJSONObject("extensions"); - if (extensionsObject != null && extensionsObject.has("data-masking")) - { - JSONObject dataMaskingObject = extensionsObject.getJSONObject("data-masking"); - JSONObject data = dataMaskingObject.getJSONObject("data"); - String sensitive_data = data.getString("sensitive_data"); - String message_masked = data.getString("message_masked"); - } - } -} -``` - - - - -```kotlin -if (metadata != null) { - if (metadata.has("@injected")) { - val injectedJSONObject = metadata.getJSONObject("@injected") - if (injectedJSONObject != null && injectedJSONObject.has("extensions")) { - val extensionsObject = injectedJSONObject.getJSONObject("extensions") - - if (extensionsObject != null && extensionsObject.has("data-masking")) { - val dataMaskingDetails = extensionsObject.getJSONObject("data") - val dataMaskingObject = dataMaskingDetails.getJSONObject("data") - val sensitive_data = dataMaskingObject.getString("sensitive_data") - val message_masked = dataMaskingObject.getString("message_masked")) - } - } - } -} -``` - - - - -```swift -let textMessage = message as? TextMessage -var metadata : [String : Any]? = textMessage.metaData -if metadata != nil { - - var injectedObject : [String : Any]? = (metadata?["@injected"] as? [String : Any])! - - if injectedObject != nil && (injectedObject!["extensions"] != nil){ - - var extensionsObject : [String : Any]? = injectedObject?["extensions"] as? [String : Any] - - if extensionsObject != nil && extensionsObject?["data-masking"] != nil { - var dataMasking = extensionsObject?["data-masking"] as! [String : Any] - var dataMaskingDetails = dataMasking?["data"] as! [String : Any] - let sensitive_data = dataMaskingDetails["sensitive_data"] as! String - let message_masked = dataMaskingDetails["message_masked"] as! String - } - } -} -``` - - - - diff --git a/moderation/legacy/image-moderation.mdx b/moderation/legacy/image-moderation.mdx deleted file mode 100644 index aceabb0f..00000000 --- a/moderation/legacy/image-moderation.mdx +++ /dev/null @@ -1,207 +0,0 @@ ---- -title: "Image Moderation (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -AI-powered image moderation to detect unsafe content. - -## Extension settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. -2. Go to the Extensions section and enable the Image Moderation extension. -3. Open up the Settings and choose to Drop messages with NSFW images. - -## How does it work? - -After analyzing, it classifies the image into four categories: - -1. Explicit Nudity -2. Suggestive Nudity -3. Violence -4. Visually Disturbing. - -Along with that, you will receive the confidence, on a scale of 0 to 100. - - - -```json -"@injected": { - "extensions": { - "image-moderation": { - "unsafe": "yes/no", - "confidence": "99", - "category": "explicit_nudity/suggestive/violence/visually_disturbing", - "attachments": [ - { - "data": { - "name": "1584307225_38928710_1d3e5acc1b009e1c4ce239bedc2851f9.jpeg", - "extension": "jpeg", - "size": 402852, - "mimeType": "image/png", - "url": "https://media.com/1594986359_2067554844_9.png", - "verdict": { - "unsafe": "yes/no", - "confidence": "99", - "category": "explicit_nudity/suggestive/violence/visually_disturbing", - } - }, - "error": null, - }, - { - "data": { - "name": "1584307225_38928710_1d3e5acc1b009e1c4ce239bedc2851f9.jpeg", - "extension": "jpeg", - "size": 402852, - "mimeType": "image/png", - "url": "https://media.com/1594986359_2067554844_9.png", - "verdict": null, - }, - "error": { - "code": "ERROR_CODE", - "message": "Error Message", - "devMessage": "Error message", - "source": "ext-api" - } - } - ] - } - } -} -``` - - - - - -A value for `confidence` that is less than 50 is likely to be a false-positive. So we recommend moderating only if `confidence` is higher than 50. - -If the image-moderation key is missing, it means that either the extension is not enabled or has timed out. - - - -The `unsafe`, confidence & category keys to the outside of `attachments` are the result for the first attachment from the `attachments` array. These have been retained for backward compatibility only.\ -You can iterate over `attachments` array for better implementation. - - - -## Implementation - -You can then either show a warning or drop the image message. - - - - - -At the recipients' end, from the `message` object, you can fetch the metadata by calling the `getMetadata()` method. Using this metadata, you can fetch information whether the image is safe or unsafe. - - - -```js -const metadata = message.getMetadata(); -if (metadata != null) { - const injectedObject = metadata["@injected"]; - if (injectedObject != null && injectedObject.hasOwnProperty("extensions")) { - const extensionsObject = injectedObject["extensions"]; - if ( - extensionsObject != null && - extensionsObject.hasOwnProperty("image-moderation") - ) { - const { attachments } = extensionsObject["image-moderation"]; - for (const attachment of attachments) { - if (!attachment.error) { - const { unsafe } = attachment.data.verdict; - // Check the other parameters as required. - } - } - } - } -} -``` - - - - -```java -JSONObject metadata = message.getMetadata(); -if (metadata != null) { - JSONObject injectedObject = metadata.getJSONObject("@injected"); - if (injectedObject != null && injectedObject.has("extensions")) { - JSONObject extensionsObject = injectedObject.getJSONObject("extensions"); - if (extensionsObject != null && extensionsObject.has("image-moderation")) - { - JSONObject tg = extensionsObject.getJSONObject("image-moderation"); - JSONArray attachments = tg.getJSONArray("attachments"); - - for (int i = 0; i < attachments.length(); i++) { - JSONObject attachment = attachments.getJSONObject(i); - JSONObject error = attachment.getJSONObject("error"); - if (error == null) { - JSONObject data = attachment.getJSONObject("data"); - JSONObject verdict = data.getJSONObject("verdict"); - String unsafe = thumbnails.getString("unsafe"); - // Check the other parameters as required. - } - } - } - } -} -``` - - - - -```swift -if let metaData = message?.metaData , let injected = metaData["@injected"] as? [String : Any], let extensions =injected["extensions"] as? [String : Any], let attachments = extensions["image-moderation"] as? [[String : Any]] { - - for attachment in attachments { - - if let data = attachment["data"] as? [String:Any] , let verdict = data["verdict"] as? [String:any] { - // Check for the parameters as required. - if let unsafe = URL(string: verdict["unsafe"] as? String) { -// Use the url accordingly. - } - - // check for attachment.error if "verdict" is null - } -} -} -``` - - - - -```kotlin -if (metadata != null) { - if (metadata.has("@injected")) { - val injected = metadata.getJSONObject("@injected") - if (injected != null && injected.has("extensions")) { - val extensions = injectedJSONObject.getJSONObject("extensions") - if (extensions != null && extensions.has("image-moderation")) { - val tg = extensions.getJSONObject("image-moderation") - val attachments = tg.getJSONArray("attachments") - for (i in 0 until attachments.length()) { - val attachment = attachments.getJSONObject(i) - val error = attachment.getJSONObject("error") - if (error == null) { - val data = attachment.getJSONObject("data") - val verdict = data.getJSONObject("verdict") - val unsafe = verdict.getString("unsafe") - // use other parameters are required. - } - } - } - } - } -} -``` - - - - diff --git a/moderation/legacy/in-flight-message-moderation.mdx b/moderation/legacy/in-flight-message-moderation.mdx deleted file mode 100644 index 6dd1a27b..00000000 --- a/moderation/legacy/in-flight-message-moderation.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: "In Flight Message Moderation (Legacy)" -sidebarTitle: "In-flight Message Moderation (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -In-flight message Moderation extension allows you to moderate messages manually. - -## Settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. - -2. Go to the Extensions section and enable the In-flight moderation extension. - -3. Open the Settings for this extension and set the following: - - 1. Moderation Criteria - - 1. Moderate all the messages - 2. Moderate only one-on-one messages - 3. Moderate only Group messages - - 2. Moderate messages sent BY certain users (Comma-separated UIDs). - - 3. Moderate messages sent TO ceratin users (Comma-separated UIDs). - - 4. Moderate messages sent TO a certain groups (Comma-separated GUIDs). - -## How does it work? - -Once the extension is enabled and the settings are saved, navigate to the In-flight Message Moderation section of the Dashboard to manually moderate messages: - - - - - -All the messages that match the moderation criteria will get listed from oldest to newest. You can perform the following actions for a particular message: - -1. **Approve:** The message gets sent to the Receiver and disappears from the list. -2. **Reject:** The message gets deleted and is not sent to the intended receiver. -3. **Kick:** Available for Group conversations. A notorious user gets kicked out of the group. They can rejoin the group. -4. **Ban:** Available for Group conversations. A notorious user gets banned from the group. They cannot rejoin later unless they are unbanned. - -Apart from the above actions, you can also quickly access the Settings for the Extension. You can toggle Auto-refresh Messages and also toggle the Switch to Enable/Disable the Moderation. - - - -If you disable the Extension, only the new messages will flow without being routed through the In-flight Message Moderation Section. However, the existing messages that you see in the section will have to be Approved in order to be received by the intended recipient. - - diff --git a/moderation/legacy/profanity-filter.mdx b/moderation/legacy/profanity-filter.mdx deleted file mode 100644 index 4c62c768..00000000 --- a/moderation/legacy/profanity-filter.mdx +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: "Profanity Filter (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -The Profanity Filter Extension helps you to mask or hide profanity in a message. We check for words from a blacklist (which you can customize) and then mask them. - -## Extension settings - -1. Login to the [CometChat](https://app.cometchat.com/login) and select your app. -2. Go to the Extensions section and enable the Profanity Filter extension. -3. Open Settings and choose to Drop messages with Profanity. -4. Also, you can provide the comma separated list of words that you would like to filter. - -### Support for filtering emojis - -Apart from words, we have also added support for filtering Profane emojis along with words. The only thing that you need to keep in mind is, certain emojis have skin tones or other variations associated with them. - -As part of the comma separated values, all the variations need to be covered. - -**For eg:** In case of finger pointing left, you need to add: 👈🏿,👈🏾,👈🏽,👈🏼,👈🏻,👈. Please note that the **yellow variant** has to be entered at the end of the list. - -Refer [https://emojipedia.org/](https://emojipedia.org/) for details. - -## How does it work? - -The recipients will receive the normal message in the text field of the message object. Also, there will be a clean/filtered version of the message in the metadata section as shown below: - - - -```json -"@injected": { - "extensions": { - "profanity-filter": { - "profanity": "yes", - "message_clean": "This is ****" - } - } -} -``` - - - - - -If the profanity-filter key is missing, it means that the extension is either not enabled or has timed out. - -If there is some error inside the profanity-filter object, the list of bad words is probably empty. Save the settings with bad words to get the desired results. - -## Implementation - -By checking if `profanity` is set to `yes`, you can also consider showing a warning before reading the message. - -From the extension settings, you can also choose to drop the message altogether. - -At the recipients' end, from the `message` object, you can fetch the metadata by calling the `getMetadata()` method. Using this metadata, you can fetch the masked message. - - - -```js -var metadata = message.getMetadata(); -if (metadata != null) { - var injectedObject = metadata["@injected"]; - if (injectedObject != null && injectedObject.hasOwnProperty("extensions")) { - var extensionsObject = injectedObject["extensions"]; - if ( - extensionsObject != null && - extensionsObject.hasOwnProperty("profanity-filter") - ) { - var profanityFilterObject = extensionsObject["profanity-filter"]; - var profanity = profanityFilterObject["profanity"]; - var cleanMessage = profanityFilterObject["message_clean"]; - } - } -} -``` - - - - -```java -JSONObject metadata = message.getMetadata(); -if (metadata != null) { - JSONObject injectedObject = metadata.getJSONObject("@injected"); - if (injectedObject != null && injectedObject.has("extensions")) { - JSONObject extensionsObject = injectedObject.getJSONObject("extensions"); - if (extensionsObject != null && extensionsObject.has("profanity-filter")) - { - JSONObject profanityFilterObject = extensionsObject.getJSONObject("profanity-filter"); - String profanity = profanityFilterObject.getString("profanity"); - String cleanMessage = profanityFilterObject.getString("message_clean"); - - } - } -} -``` - - - - -```kotlin -if (metadata != null) { - if (metadata.has("@injected")) { - val injectedJSONObject = metadata.getJSONObject("@injected") - if (injectedJSONObject != null && injectedJSONObject.has("extensions")) { - val extensionsObject = injectedJSONObject.getJSONObject("extensions") - - if (extensionsObject != null && extensionsObject.has("profanity-filter")) { - val profanityFilterObject = extensionsObject.getJSONObject("profanity-filter") - val dataObject = profanityFilterObject.getJSONObject("data") - if (dataObject.has("profanity")) - val profanity = dataObject.getString("profanity") - if (dataObject.has("message_clean")) - val message_clean= dataObject.getString("message_clean")) - } - } - } - } -``` - - - - -```swift -let textMessage = message as? TextMessage -var metadata : [String : Any]? = textMessage.metaData -if metadata != nil { - - var injectedObject : [String : Any]? = (metadata?["@injected"] as? [String : Any])! - - if injectedObject != nil && (injectedObject!["extensions"] != nil){ - - var extensionsObject : [String : Any]? = injectedObject?["extensions"] as? [String : Any] - - if extensionsObject != nil && extensionsObject?["profanity-filter"] != nil { - - var profanityFilterObject = extensionsObject?["profanity-filter"] as! [String : Any] - - let profanity = profanityFilterObject["profanity"] as! String - let cleanMessage = profanityFilterObject["language_translated"] as! String - } - } -} -``` - - - - diff --git a/moderation/legacy/report-message.mdx b/moderation/legacy/report-message.mdx deleted file mode 100644 index 293a92f5..00000000 --- a/moderation/legacy/report-message.mdx +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: "Report Message (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -Enable your users to report messages in a group. - - - - - -**Extension settings** - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. - -2. Go to the Extensions section and enable the Report messages extension. - -3. Open the settings for this extension. - -4. The settings page has the following: - - * **Moderation criteria:** The max number of reports after which you want to be notified. - * **Moderation actions:** Get the list of reports on the configured Webhook URL. - - - - - -## How does it work? - -The extension has the following functionalities: - -1. Allowing end-users to report messages. -2. Allowing admins to login to the dashboard to take action on the reports. - -### 1. Reporting a message - -Messages can be reported in either group conversations or one-on-one conversations. - -In the context menu of a message, you can have a "Report" button. Clicking it should open up a modal asking for the reason. - -Here's the description of the parameters that need to be passed to the extension: - -| Parameters | Value | Description | -| ---------- | ------- | --------------------------------------------- | -| msgId | Integer | The ID of the message that has to be reported | -| reason | String | The reason for reporting the message. | - -Once you have the message to be reported along with the reason, make use of the `callExtension` method provided by the SDK to submit the report: - - - -```js -CometChat.callExtension('report-message', 'POST', 'v1/report', { - "msgId": 123, - "reason": "Contains profanity" -}).then(response => { - // { success: true } -}) -.catch(error => { - // Error occurred -}); -``` - - - - -```java -import org.json.simple.JSONObject; - -JSONObject body=new JSONObject(); - -body.put("msgId", 123); -body.put("reason", "Contains profanity"); - -CometChat.callExtension("report-message", "POST", "/v1/report", body, - new CometChat.CallbackListener < JSONObject > () { - @Override - public void onSuccess(JSONObject jsonObject) { - //On Success - } - @Override - public void onError(CometChatException e) { - //On Failure - } -}); -``` - - - - -```swift -CometChat.callExtension(slug: "report-message", type: .post, endPoint: "v1/report", body: [ - "msgId": 123, - "reason":"Contains profanity" -] as [String : Any], onSuccess: { (response) in - // Success - }) { (error) in - // Error occured - } -``` - - - - - -### 2. View reports and take action - - - - - -In order to list and take action on the reported users: - -1. Open up the Extension's settings page - -2. Click "View Reports" link. This will load all the reports. - -3. The following actions can be taken for users reported in Group: - - 1. Delete => Reported message will be deleted. - 2. Ignore => The report is ignored. - -4. To load new reports, click on the Refresh button. diff --git a/moderation/legacy/report-user.mdx b/moderation/legacy/report-user.mdx deleted file mode 100644 index 9bef8170..00000000 --- a/moderation/legacy/report-user.mdx +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: "Report User (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -Enables your users to report users who use offensive or suspicious messages in the chat. - - - - - -## Extension settings - -1. Login to CometChat and select your app. - -2. Go to the Extensions section and enable the Report user extension. - -3. Open the settings for this extension. - -4. The settings page has the following: - - * **Moderation criteria:** The max number of reports after which you want to be notified. - * **Moderation actions**: Get the list of reports on the configured Webhook URL. - - - - - -## How does it work? - -The extension has the following functionalities: - -1. Allowing end-users to report other users. -2. Allowing admins to login to the Dashboard to take action on the reports. - -### 1. Reporting a user - -Users can be reported in either group conversations or one-on-one conversations. - -By clicking on the user's avatar, you can show an item in the context menu called "Report". Clicking on the "Report" button should open up a modal asking for the reason. - -Here's the description of the parameters that need to be passed to the extension: - -| Parameters | Value | Description | -| ---------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ | -| uid | String | The UID of the user that needs to be reported | -| reason | String | Reason for reporting. This should be max 150 characters. | -| guid | String | The GUID of the group in which the user is being reported.If the user is being reported in a one-on-one conversation, this can be skipped. | - -Once you have the user to be reported along with the reason, make use of the callExtension method provided by the SDK to submit the report: - - - -```js -CometChat.callExtension('report-user', 'POST', 'v1/report', { - "uid": "cometchat-uid-3", - "reason": "Misbehaving", - // "guid": "cometchat-guid-1" // Used only when reporting the user in a group -}).then(response => { - // { success: true } -}) -.catch(error => { - // Error occurred -}); -``` - - - - -```java -import org.json.simple.JSONObject; - -JSONObject body=new JSONObject(); - -body.put("uid", "cometchat-uid-3"); -body.put("reason", "Misbehaving"); -// body.put("guid", "cometchat-guid-1"); // Used only when reporting the user in a group - -CometChat.callExtension("report-user", "POST", "/v1/report", body, - new CometChat.CallbackListener < JSONObject > () { - @Override - public void onSuccess(JSONObject jsonObject) { - //On Success - } - @Override - public void onError(CometChatException e) { - //On Failure - } -}); -``` - - - - -```swift -CometChat.callExtension(slug: "report-user", type: .post, endPoint: "v1/report", body: [ - "uid": "cometchat-uid-3", - "reason":"Misbehaving", - "guid":"cometchat-guid-1" // Used only when reporting the user in a group -] as [String : Any], onSuccess: { (response) in - // Success - }) { (error) in - // Error occured - } -``` - - - - - -### 2. View reports and take action on a reported user - - - - - -In order to list and take an action on the reported users: - -1. Open up the Extension's settings page - -2. Click "View Reports" link. This will load all the reports. - -3. Select the criteria from the dropdown: - - 1. One-on-one conversations => Lists the users who have been reported in One-on-one conversations. - 2. Group conversations => List the users who have been reported in a Group. - 3. All reports => Lists all the reports. - -4. The following actions can be taken for users reported in Group: - - 1. Kick => Reported user is kicked out of the group. - 2. Ban => Reported user is banned from the group. - 3. Ignore => The report is ignored. - -5. The following actions can be take for users reported in one-on-one conversations: - - 1. Block => The reported user is blocked on behalf of the reporter. - 2. Ignore => The report is ignored. - -6. To load new reports, click on the Refresh button. diff --git a/moderation/legacy/sentiment-analysis.mdx b/moderation/legacy/sentiment-analysis.mdx deleted file mode 100644 index 2959e66d..00000000 --- a/moderation/legacy/sentiment-analysis.mdx +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: "Sentiment Analysis (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -The Sentiment Analysis extension helps you to understand the tone or sentiment of a message. - -## Extension settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. -2. Go to the Extensions section and enable the Sentiment Analysis extension. -3. Open up Settings and choose to Drop messages with Negative sentiments. - -## How does it work? - -A message can be classified into 4 categories: - -1. Positive -2. Neutral -3. Negative -4. Mixed - -Along with these categories, we specify the confidence for that category, on a scale of 0 to 100. - -The sentiment about the message can be found in the metadata object as shown below: - - - -```json -"@injected": { - "extensions": { - "sentiment-analysis": { - "sentiment": "positive", - "sentiment_score": { - "positive": 95, - "neutral": 4, - "negative": 0, - "mixed": 0 - } - } - } -} -``` - - - - - -If the sentiment-analysis key is missing, then either the extension is not enabled or has timed out. - -Sentiment analysis extension is compatible with the languages listed below - -| Supported languages | -| ----------------------------- | -| German (de) | -| English (en) | -| Spanish (es) | -| Italian (it) | -| Portuguese (pt) | -| French (fr) | -| Japanese (ja) | -| Korean (ko) | -| Hindi (hi) | -| Arabic (ar) | -| Chinese (simplified) (zh) | -| Chinese (traditional) (zh-TW) | - -## Implementation - -Using this information, you can show either a warning or drop the message completely. Here is how Twitter shows a message: - - - - - -At the recipients' end, from the `message` object, you can fetch the metadata by calling the `getMetadata()` method. Using this metadata, you can fetch the sentiment of the message. - - - -```js -var metadata = message.getMetadata(); -if (metadata != null) { - var injectedObject = metadata["@injected"]; - if (injectedObject != null && injectedObject.hasOwnProperty("extensions")) { - var extensionsObject = injectedObject["extensions"]; - if ( - extensionsObject != null && - extensionsObject.hasOwnProperty("sentiment-analysis") - ) { - var sentimentAnalysisObject = extensionsObject["sentiment-analysis"]; - var sentiment = sentimentAnalysisObject["sentiment"]; - if (sentimentAnalysisObject.hasOwnProperty("sentiment_score")) { - var positive = sentimentAnalysisObject["positive"]; - var neutral = sentimentAnalysisObject["neutral"]; - var negative = sentimentAnalysisObject["negative"]; - var mixed = sentimentAnalysisObject["mixed"]; - } - } - } -} -``` - - - - -```java -JSONObject metadata = message.getMetadata(); -if (metadata != null) { - JSONObject injectedObject = metadata.getJSONObject("@injected"); - if (injectedObject != null && injectedObject.has("extensions")) { - JSONObject extensionsObject = injectedObject.getJSONObject("extensions"); - if (extensionsObject != null && extensionsObject.has("sentiment-analysis")) - { - JSONObject sentimentAnalysisObject = extensionsObject.getJSONObject("sentiment-analysis"); - String sentiment = sentimentAnalysisObject.getString("sentiment"); - if(sentimentAnalysisObject.has("sentiment_score")){ - int positive = sentimentAnalysisObject.getInt("positive"); - int neutral = sentimentAnalysisObject.getInt("neutral"); - int negative = sentimentAnalysisObject.getInt("negative"); - int mixed = sentimentAnalysisObject.getInt("mixed"); - } - - } - } -} -``` - - - - -```kotlin -if (metadata != null) { - if (metadata.has("@injected")) { - val injectedJSONObject = metadata.getJSONObject("@injected") - if (injectedJSONObject != null && injectedJSONObject.has("extensions")) { - val extensionsObject = injectedJSONObject.getJSONObject("extensions") - if (extensionsObject.has("sentiment-analysis")) { - - val sentimentObject = extensionsObject.getJSONObject("sentiment-analysis") - val sentiment= sentimentObject.getString("sentiment") - if (sentimentObject.has("sentiment_score")) { - if (sentimentObject.has("positive")) - val positive=sentimentObject.getInt("positive") - if (sentimentObject.has("neutral")) - val neutral= sentimentObject.getInt("neutral") - if (sentimentObject.has("negative")) - val negative= sentimentObject.getInt("negative") - if (sentimentObject.has("mixed")) - val mixed= sentimentObject.getInt("mixed") - } - } - } - } - } -``` - - - - -```swift -let textMessage = message as? TextMessage -var metadata : [String : Any]? = message.metaData -if metadata != nil { - - var injectedObject : [String : Any]? = (metadata?["@injected"] as? [String : Any])! - - if injectedObject != nil && (injectedObject!["extensions"] != nil){ - - var extensionsObject : [String : Any]? = injectedObject?["extensions"] as? [String : Any] - - if extensionsObject != nil && extensionsObject?["sentiment-analysis"] != nil { - - var sentimentAnalysisObject = extensionsObject?["sentiment-analysis"] as! [String : Any] - - let sentiment = sentimentAnalysisObject["sentiment"] as! String - - if sentimentAnalysisObject["sentiment_score"] { - - let positive = imageModerationObject["positive"] as! Int - let neutral = imageModerationObject["neutral"] as! Int - let negative = imageModerationObject["negative"] as! Int - let mixed = imageModerationObject["mixed"] as! Int - } - } - } -} -``` - - - - diff --git a/moderation/legacy/slow-mode.mdx b/moderation/legacy/slow-mode.mdx deleted file mode 100644 index f282f1e5..00000000 --- a/moderation/legacy/slow-mode.mdx +++ /dev/null @@ -1,271 +0,0 @@ ---- -title: "Slow Mode (Deprecated)" ---- - - - -Deprecated: This extension is no longer maintained and will not receive further updates. - - - -Slow down messages to make them legible! - - - - - -## Extension settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. -2. Go to the Extensions section and enable the Slow mode extension. - -## How does Slow mode work? - -Slow mode extension works great in groups with a large number of participants. Especially, during a live event with a potential for a flood of messages being sent every second. When the extension is enabled and enforced in a group, it allows the participants to send messages only after a certain intervals. This helps to keep chats readable for everyone during large events. - -The extension has the following 4 parts: - -1. Enabling the slow mode for a group -2. Disabling the slow mode for a group -3. Enforcing slow mode for participants -4. Fetching the slow mode details - -### Enabling slow mode - -Slow mode can be enabled only by the group admins or moderators. Participants cannot enable the slow mode. - -Once slow mode is enabled in a group, the information is shared with its members in real-time as a custom message. With this, it can be enforced immediately. - -You need to implement the `onCustomMessageReceived` listener in order to receive the Slow mode related messages. The message sent has the category of `custom` and type `extension_slow-mode`. - -Following are the inputs required to enable slow mode in a particular group: - -| Parameter | Type | Description | -| ------------------ | ------ | ------------------------------------------------------------------------------------------------------------------- | -| `guid` | string | The group's ID in which the slow mode needs to be enabled. | -| `slowDownTimeInMS` | int | The time in milliseconds for which the participants have to wait before being able to send the consecutive message. | - -You can make use of the `callExtension` method exposed by CometChat SDKs to enable slow mode as an admin/moderator. - - - -```js -CometChat.callExtension('slow-mode', 'POST', 'v1/configure', { - "guid": "cometchat-guid-1", - "slowDownTimeInMS": 660000, -}).then(response => { - // Success true -}) -.catch(error => { - // Error occured -}); -``` - - - - -```java -import org.json.simple.JSONObject; - -JSONObject body=new JSONObject(); - -body.put("guid", "cometchat-guid-1"); -body.put("slowDownTimeInMS", 660000); - -CometChat.callExtension("slow-mode", "POST", "/v1/configure", body, - new CometChat.CallbackListener < JSONObject > () { - @Override - public void onSuccess(JSONObject jsonObject) { - //On Success - } - @Override - public void onError(CometChatException e) { - //On Failure - } -}); -``` - - - - -```swift -CometChat.callExtension(slug: "slow-mode", type: .post, endPoint: "v1/configure", body: ["guid": "cometchat-guid-1" ,"slowDownTimeInMS": 660000] as [String : Any], onSuccess: { (response) in - // Success - }) { (error) in - // Error occured - } -``` - - - - - -### Disabling slow mode - -Slow mode can be disabled only by the group admins or moderators. Participants cannot disable the slow mode. - -Once slow mode is disabled in a group, the information is shared with its members in real-time as a custom message. With this, it can be turned off for that group immediately. - -Following are the inputs required to enable slow mode in a particular group: - -| Parameter | Type | Description | -| --------- | ------ | ----------------------------------------------------------- | -| `guid` | string | The group's ID in which the slow mode needs to be disabled. | - -You have to implement the `onCustomMessageReceived` listener in order to receive the Slow mode related messages. The message sent has the category of `custom` and type `extension_slow-mode`. - -You can make use of the `callExtension` method exposed by CometChat SDKs to disable slow mode as an admin/moderator. - - - -```js -CometChat.callExtension('slow-mode', 'DELETE', 'v1/configure', { - "guid": "cometchat-guid-1" -}).then(response => { - // Success true -}) -.catch(error => { - // Error occured -}); -``` - - - - -```java -import org.json.simple.JSONObject; - -JSONObject body=new JSONObject(); - -body.put("guid", "cometchat-guid-1"); - -CometChat.callExtension("slow-mode", "DELETE", "/v1/configure", body, - new CometChat.CallbackListener < JSONObject > () { - @Override - public void onSuccess(JSONObject jsonObject) { - //On Success - } - @Override - public void onError(CometChatException e) { - //On Failure - } -}); -``` - - - - -```swift -CometChat.callExtension(slug: "slow-mode", type: .delete, endPoint: "v1/configure", body: nil, onSuccess: { (response) in - // Success - }) { (error) in - // Error occured - } -``` - - - - - -### Enforcing slow mode - -This is handled by the extension for groups that have slow mode enabled as mentioned below: - -#### 1. For participants of a group - -If the moderator or admin of a group has enabled slow mode with the time of 1 min, then the participants will have to wait for 1 minute after sending a message. Once the participant has waited for 1 min, he/she then becomes eligible to send out the next message. - -If there's an attempt by the participants to send a message before the interval has expired for them, the message gets blocked by the extension. - -#### 2. For admins and moderators - -The extension does not restrict moderators and admins of a group. Slow mode is enforced only for the participants. - - -Groups without admins/moderators - -Groups that are created from the dashboard do not have an admin or moderator. Hence, care needs to be taken to add a member to such groups and change their scope to either moderator or admin. - - - -#### 3. Change in member scope - -If a participant is made an admin or moderator of a group, the slow mode is no longer applicable for him/her. - -Similarly, if an admin or moderator of a group is demoted to a participant, the slow mode will be applicable immediately to him/her as mentioned above. - -### Fetching slow mode details - -As mentioned above, the details about the enabling or disabling the slow mode are shared in real-time with the members as a custom message. But, it might happen that a few members are offline or are added later on to the group. Hence, it is important to make the same details available to them for a consistent experience. - -You can make use of the `callExtension` method exposed by the CometChat SDKs to fetch the details about slow mode as a member of a group. - - - -```js -const guid = "cometchat-guid-1"; -CometChat.callExtension('slow-mode', 'GET', `v1/fetch-configuration?guid=${guid}`, null).then(response => { - // Configuration for the mentioned group -}) -.catch(error => { - // Error occured -}); -``` - - - - -```java -CometChat.callExtension("slow-mode", "GET", "/v1/fetch-configuration?guid=cometchat-guid-1", null, - new CometChat.CallbackListener < JSONObject > () { - @Override - public void onSuccess(JSONObject jsonObject) { - //On Success - } - @Override - public void onError(CometChatException e) { - //On Failure - } -}); -``` - - - - -```swift -CometChat.callExtension(slug: "slow-mode", type: .get, endPoint: "v1/fetch-configuration?guid=cometchat-guid-1", body: nil, onSuccess: { (response) in - // Success - }) { (error) in - // Error occured - } -``` - - - - - -The response has the following format: - -| Parameters | Type | Description | -| ---------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `isSlowed` | boolean | Whether the slow mode is enabled in the mentioned group.If false, the following fields are not present in the response. | -| `slowDownTimeInMS` | int | The time interval for which a participant has to wait for sending messages. | -| `lastMessageSentAtTimestamp` | timestamp | The timestamp at which the last message was sent by the logged in user in the mentioned group.If the scope of the logged in user is Admin or Moderator in the mentioned group, this field is not included in the response. | - -## Implementation - -#### 1. For admins and moderators - -When a group chat is opened, and the scope of the logged-in user is either an admin or a moderator of that group, he/she should be able to toggle slow mode for that group. - -When a group has multiple admins/moderators, and one of the admins enables (or disables) the slow mode for a group, the UI for other admins/moderators should update and show the control to disable (or enable) the slow mode. This can be achieved in real-time due to the custom message that is sent. - -Whenever, an admin or a moderator in a group switches conversations to a different group, use the fetch-configuration call to check for the above mentioned details. It may happen, that the logged in user is admin/moderator for one group but a participant in another. - -#### 2. For participants of a group - -When a group chat is opened, and the scope of the logged-in user is participant, he/she should be able to send messages only after the the configured intervals. - -You can enforce the blocking behaviour by disabling the message composer or the send button on the UI. It will get enabled only once the participant has waited for the defined amount of slow-down time. - -While the participant is waiting, a timer can be displayed to indicate the amount of time left after which they can send the next message. diff --git a/moderation/legacy/virus-malware-scanner.mdx b/moderation/legacy/virus-malware-scanner.mdx deleted file mode 100644 index aa67257b..00000000 --- a/moderation/legacy/virus-malware-scanner.mdx +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: "Virus And Malware Scanner (Legacy)" ---- - - - -**Legacy Notice**: This extension is considered legacy and is scheduled for deprecation in the near future. It is no longer recommended for new integrations. - -Please note: Legacy extensions are no longer actively maintained and will not receive feature updates or enhancements. - - - -The Virus & Malware Scanner Extension allows the developer to scan files uploaded by users so that a warning can be added for malicious content. - -## Before you begin - -This Extension uses a third-party API service - [Scanii](https://scanii.com) - to scan media messages. Create an account with Scanii API Service and get your pair of **API Key** and **Secret**. - -## Extension settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. -2. Go to the Extensions section and enable the Virus and Malware Scanner extension. -3. Open the Settings for this extension. -4. Enter Scanii API Key and Scanii Secret and click on save. - -## How does it work? - -Once the Extension is enabled for your App and the Extension Settings are saved, the recipients will receive metadata with an array of results. - -The Virus Scan results will be updated later for the message and hence you need to implement the `onMessageEdited` listener. Please check the **Edit a Message** page under the Messaging section of each SDK for more details. - -This can be used to show warning messages: - - - -```json -{ - "@injected": { - "extensions": { - "virus-malware-scanner": { - "attachments": [ - { - "data": { - "url": "https://media.com/1646056756_400568974.mp3", - "name": "a2.mp3", - "size": 1519658, - "verdict": { - "scan_results": [], - }, - "mimeType": "audio/mpeg", - "extension": "mp3", - }, - "error": null, - }, - { - "data": { - "url": "https://media.com/1646056756_400568933.mp3", - "name": "a1.mp3", - "size": 1519658, - "mimeType": "audio/mpeg", - "extension": "mp3", - "verdict": null - }, - "error": { - "code": "ERROR_CODE", - "message": "Error Message", - "devMessage": "Error message", - "source": "ext-api" - } - } - ], - "scan_results": [], - }, - }, - }, -} -``` - - - - - -If the scan\_results is an empty array, it means the message is safe. - -If the virus-malware-scanner key is missing, then either the extension is not enabled or your Scanii credits are over. - - - -The `scan_results`, to the outside of `attachments` are the result for the first attachment from the `attachments` array. This has been retained for backward compatibility only.\ -You can iterate over `attachments` array for better implementation. - - - -## Implementation - -At the recipients' end, from the message object, you can fetch the metadata by calling the getMetadata() method. Using this metadata, you can fetch the Rich Media Embed. - - - -```js -const metadata = message.getMetadata(); -if (metadata != null) { - const injectedObject = metadata["@injected"]; - if (injectedObject != null && injectedObject.hasOwnProperty("extensions")) { - const extensionsObject = injectedObject["extensions"]; - if ( - extensionsObject != null && - extensionsObject.hasOwnProperty("virus-malware-scanner") - ) { - const { attachments } = extensionsObject["virus-malware-scanner"]; - for (const attachment of attachments) { - if (!attachment.error) { - const { scan_results } = attachment.data.verdict; - // Check the other parameters as required. - } - } - } - } -} -``` - - - - -```java -JSONObject metadata = message.getMetadata(); -if (metadata != null) { - JSONObject injectedObject = metadata.getJSONObject("@injected"); - if (injectedObject != null && injectedObject.has("extensions")) { - JSONObject extensionsObject = injectedObject.getJSONObject("extensions"); - if (extensionsObject != null && extensionsObject.has("virus-malware-scanner")) - { - JSONObject tg = extensionsObject.getJSONObject("virus-malware-scanner"); - JSONArray attachments = tg.getJSONArray("attachments"); - - for (int i = 0; i < attachments.length(); i++) { - JSONObject attachment = attachments.getJSONObject(i); - JSONObject error = attachment.getJSONObject("error"); - if (error == null) { - JSONObject data = attachment.getJSONObject("data"); - JSONObject verdict = data.getJSONObject("verdict"); - String unsafe = thumbnails.getString("scan_results"); - // Check the other parameters as required. - } - } - } - } -} -``` - - - - -```kotlin -if (metadata != null) { - if (metadata.has("@injected")) { - val injected = metadata.getJSONObject("@injected") - if (injected != null && injected.has("extensions")) { - val extensions = injectedJSONObject.getJSONObject("extensions") - if (extensions != null && extensions.has("virus-malware-scanner")) { - val tg = extensions.getJSONObject("virus-malware-scanner") - val attachments = tg.getJSONArray("attachments") - for (i in 0 until attachments.length()) { - val attachment = attachments.getJSONObject(i) - val error = attachment.getJSONObject("error") - if (error == null) { - val data = attachment.getJSONObject("data") - val verdict = data.getJSONObject("verdict") - val unsafe = verdict.getString("scan_results") - // use other parameters are required. - } - } - } - } - } -} -``` - - - - -```swift -if let metaData = message?.metaData , let injected = metaData["@injected"] as? [String : Any], let extensions =injected["extensions"] as? [String : Any], let attachments = extensions["virus-malware-scanner"] as? [[String : Any]] { - - for attachment in attachments { - - if let data = attachment["data"] as? [String:Any] , let verdict = data["verdict"] as? [String:any] { - // Check for the parameters as required. - if let unsafe = URL(string: verdict["scan_results"] as? String) { -// Use the url accordingly. - } - - // check for attachment.error if "verdict" is null - } -} -} -``` - - - - diff --git a/moderation/legacy/xss-filter.mdx b/moderation/legacy/xss-filter.mdx deleted file mode 100644 index 1d074e10..00000000 --- a/moderation/legacy/xss-filter.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: "XSS Filter (Deprecated)" ---- - - - -Deprecated: This extension is no longer maintained and will not receive further updates. - - - -A client-side script can be injected into the message which can lead to an attack. The XSS Filter Extension helps you to sanitize the messages. - -This is applicable only for the Web SDK. - -## Extension settings - -1. Login to [CometChat](https://app.cometchat.com/login) and select your app. -2. Go to the Extensions section and enable the XSS Filter extension. -3. Open up the Settings and choose to Drop messages with XSS Scripts. - -## How does it work? - -Once the extension has been enabled from the Dashboard, recipients will receive metadata with the sanitized text. - -Here is a sample response: - - - -```json -"@injected": { - "extensions": { - "xss-filter": { - "hasXSS": "yes"|"no", - "sanitized_message": "" - } - } -} -``` - - - - - -If the xss-filter key is missing, it means that the extension is either not enabled or has timed out. - -## Implementation - -At the recipients' end, from the message object, you can fetch the metadata by calling the getMetadata() method. Using this metadata, you can fetch the sanitized message. - - - -```js -var metadata = message.getMetadata(); -if (metadata != null) { - var injectedObject = metadata["@injected"]; - if (injectedObject != null && injectedObject.hasOwnProperty("extensions")) { - var extensionsObject = injectedObject["extensions"]; - if (extensionsObject != null && - extensionsObject.hasOwnProperty("xss-filter")){ - var xssFilterObject = extensionsObject["xss-filter"]; - var hasXSS = xssFilterObject["hasXSS"]; - var sanitized_message = xssFilterObject["sanitized_message"]; - } - } -} -``` - - - - - -As mentioned earlier, the XSS is only possible for the web. So, the mobile platforms do not require you to fetch the sanitized message. diff --git a/moderation/webhooks-overview.mdx b/moderation/webhooks-overview.mdx deleted file mode 100644 index cb1273e9..00000000 --- a/moderation/webhooks-overview.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Webhook Overview" -url: "/fundamentals/webhooks-overview" ---- \ No newline at end of file diff --git a/sdk/android/2.0/extensions.mdx b/sdk/android/2.0/extensions.mdx index ed254094..68e86c55 100644 --- a/sdk/android/2.0/extensions.mdx +++ b/sdk/android/2.0/extensions.mdx @@ -49,10 +49,4 @@ Extensions that help increase user engagement. *Recommended for advanced apps.* *Extensions that help you to build a safe messaging environment.* *Recommended for live streaming and event apps.* -[Data Masking Filter](/moderation/data-masking-filter)\ -[Profanity Filter](/moderation/profanity-filter)\ -[Image Moderation](/moderation/image-moderation)\ -[Sentiment Analysis](/moderation/sentiment-analysis)\ -[In-flight Message Moderation](/moderation/in-flight-message-moderation)\ -[Virus and Malware Scanner](/moderation/virus-malware-scanner)\ -[XSS Filter](/moderation/xss-filter) +[Legacy Moderation Extensions](/moderation/legacy-extensions) diff --git a/sdk/ios/2.0/extensions.mdx b/sdk/ios/2.0/extensions.mdx index bfb9c4ee..e68c97c5 100644 --- a/sdk/ios/2.0/extensions.mdx +++ b/sdk/ios/2.0/extensions.mdx @@ -49,10 +49,4 @@ Extensions that help increase user engagement. *Recommended for advanced apps.* \_Extensions that help you to build a safe messaging environment.\_*Recommended for live streaming and event apps.* -[Data Masking Filter](/moderation/data-masking-filter)\ -[Profanity Filter](/moderation/profanity-filter)\ -[Image Moderation](/moderation/image-moderation)\ -[Sentiment Analysis](/moderation/sentiment-analysis)\ -[In-flight Message Moderation](/moderation/in-flight-message-moderation)\ -[Virus and Malware Scanner](/moderation/virus-malware-scanner)\ -[XSS Filter](/moderation/xss-filter) +[Legacy Moderation Extensions](/moderation/legacy-extensions) diff --git a/ui-kit/android/extensions.mdx b/ui-kit/android/extensions.mdx index 1ab5880b..6333a963 100644 --- a/ui-kit/android/extensions.mdx +++ b/ui-kit/android/extensions.mdx @@ -78,9 +78,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. ### Thumbnail Generation diff --git a/ui-kit/android/v4/extensions.mdx b/ui-kit/android/v4/extensions.mdx index 319cb4a6..96017abb 100644 --- a/ui-kit/android/v4/extensions.mdx +++ b/ui-kit/android/v4/extensions.mdx @@ -88,9 +88,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/v4/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/v4/message-list) component of UI Kits. @@ -98,9 +98,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/v4/message-list) component of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/v4/message-list) component of UI Kits. @@ -108,9 +108,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/v4/message-list) component of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/v4/message-list) component of UI Kits. diff --git a/ui-kit/angular/extensions.mdx b/ui-kit/angular/extensions.mdx index 0301a765..89c89485 100644 --- a/ui-kit/angular/extensions.mdx +++ b/ui-kit/angular/extensions.mdx @@ -88,9 +88,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/angular/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/angular/message-list) component of UI Kits. @@ -98,9 +98,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/angular/message-list) component of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/angular/message-list) component of UI Kits. @@ -108,9 +108,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/angular/message-list) component of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/angular/message-list) component of UI Kits. diff --git a/ui-kit/flutter/v4/extensions.mdx b/ui-kit/flutter/v4/extensions.mdx index acadb56d..76b43d8b 100644 --- a/ui-kit/flutter/v4/extensions.mdx +++ b/ui-kit/flutter/v4/extensions.mdx @@ -151,9 +151,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Widget](/ui-kit/flutter/v4/message-list) widget of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Widget](/ui-kit/flutter/v4/message-list) widget of UI Kits. @@ -170,9 +170,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Widget](/ui-kit/flutter/v4/message-list) widget of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Widget](/ui-kit/flutter/v4/message-list) widget of UI Kits. @@ -189,9 +189,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Widget](/ui-kit/flutter/v4/message-list) widget of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Widget](/ui-kit/flutter/v4/message-list) widget of UI Kits. diff --git a/ui-kit/ios/extensions.mdx b/ui-kit/ios/extensions.mdx index 62f7186c..fef6939e 100644 --- a/ui-kit/ios/extensions.mdx +++ b/ui-kit/ios/extensions.mdx @@ -88,9 +88,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. @@ -98,9 +98,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. @@ -108,9 +108,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/message-list) component of UI Kits. diff --git a/ui-kit/ios/v4/extensions.mdx b/ui-kit/ios/v4/extensions.mdx index 47df0433..d5f46e4a 100644 --- a/ui-kit/ios/v4/extensions.mdx +++ b/ui-kit/ios/v4/extensions.mdx @@ -84,9 +84,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/v4/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/v4/message-list) component of UI Kits. @@ -94,9 +94,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/v4/message-list) component of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/v4/message-list) component of UI Kits. @@ -104,9 +104,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/v4/message-list) component of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/ios/v4/message-list) component of UI Kits. diff --git a/ui-kit/react-native/v4/extensions.mdx b/ui-kit/react-native/v4/extensions.mdx index 30eeda2d..3fb56313 100644 --- a/ui-kit/react-native/v4/extensions.mdx +++ b/ui-kit/react-native/v4/extensions.mdx @@ -151,9 +151,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. @@ -170,9 +170,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. @@ -189,9 +189,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/android/message-list) component of UI Kits. diff --git a/ui-kit/react/v4/extensions.mdx b/ui-kit/react/v4/extensions.mdx index 9f6c39aa..cfbe3971 100644 --- a/ui-kit/react/v4/extensions.mdx +++ b/ui-kit/react/v4/extensions.mdx @@ -90,9 +90,9 @@ Once you have successfully activated the [Link Preview Extension](/fundamentals/ ### Profanity Filter -The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Profanity Filter Extension](/moderation/profanity-filter). +The Profanity Filter extension helps in maintaining the chat decorum by censoring obscene and inappropriate words in the messages. For a comprehensive understanding and guide on implementing and using the Profanity Filter Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Profanity Filter Extension](/moderation/profanity-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/react/v4/message-list) component of UI Kits. +Once you have successfully activated the Profanity Filter Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/react/v4/message-list) component of UI Kits. @@ -100,9 +100,9 @@ Once you have successfully activated the [Profanity Filter Extension](/moderatio ### Data Masking -The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Data Masking Extension](/moderation/data-masking-filter). +The Data Masking extension helps secure sensitive data by masking information like credit card numbers and phone numbers in a chat message. For a comprehensive understanding and guide on implementing and using the Data Masking Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/react/v4/message-list) component of UI Kits. +Once you have successfully activated the Data Masking Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/react/v4/message-list) component of UI Kits. @@ -110,9 +110,9 @@ Once you have successfully activated the [Data Masking Extension](/moderation/da ### Image Moderation -The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Image Moderation Extension](/moderation/image-moderation). +The Image Moderation extension uses machine learning to detect and filter out inappropriate or explicit images shared in the chat. For a comprehensive understanding and guide on implementing and using the Image Moderation Extension, refer to our specific guide on the [Legacy Extensions](/moderation/legacy-extensions). -Once you have successfully activated the [Data Masking Extension](/moderation/data-masking-filter) from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/react/v4/message-list) component of UI Kits. +Once you have successfully activated the Image Moderation Extension from your CometChat Dashboard, the feature will automatically be incorporated into the Message Bubble of [MessageList Component](/ui-kit/react/v4/message-list) component of UI Kits. From fd5ede45bf078aba111b543a5fac0db7c851dc3c Mon Sep 17 00:00:00 2001 From: Jitvar Patil Date: Mon, 19 Jan 2026 22:44:50 +0530 Subject: [PATCH 9/9] docs(moderation): update API explorer title and clarify SDK integration step - Change API Explorer page title from "API Explorer" to "AI Moderation APIs" for clarity - Update SDK integration step description to clarify it's optional when using UI Kits - Improve getting-started guide to better communicate when custom implementation is needed --- moderation/api-explorer.mdx | 2 +- moderation/getting-started.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moderation/api-explorer.mdx b/moderation/api-explorer.mdx index e71a39fc..351d82b8 100644 --- a/moderation/api-explorer.mdx +++ b/moderation/api-explorer.mdx @@ -1,4 +1,4 @@ --- -title: "API Explorer" +title: "AI Moderation APIs" url: "/rest-api/moderation" --- \ No newline at end of file diff --git a/moderation/getting-started.mdx b/moderation/getting-started.mdx index ae71e642..7631e6ed 100644 --- a/moderation/getting-started.mdx +++ b/moderation/getting-started.mdx @@ -38,7 +38,7 @@ With Moderation Integration, you can define flexible rules, receive real-time up Go to Rules Docs
- + If building a custom UI, implement moderation handling in your code. See [SDK Integration](#integrating-moderation-with-sdk) below.