Skip to main content

Documentation Index

Fetch the complete documentation index at: https://learn.social.plus/llms.txt

Use this file to discover all available pages before exploring further.

Flag and Unflag Messages

Empower your community with robust content moderation through message flagging capabilities, enabling users to report inappropriate content and administrators to maintain platform safety.

Flag Messages

Report inappropriate content with specific reasons

Unflag Messages

Remove flags from previously reported messages

Flag Status Check

Verify if a message has been flagged by the user

Admin Console

Review and manage flagged content

Architecture Overview

Flag Reasons

social.plus SDK provides comprehensive flagging options to categorize different types of inappropriate content.
Flag ReasonDescriptionUse Case
CommunityGuidelinesAgainst community guidelinesGeneral policy violations
HarassmentOrBullyingHarassment or bullyingTargeted abuse, threats
SelfHarmOrSuicideSelf-harm or suicideDangerous content, crisis situations
ViolenceOrThreateningContentViolence or threatening contentPhysical threats, violent imagery
SellingRestrictedItemsSelling restricted itemsIllegal goods, prohibited sales
SexualContentOrNuditySexual content or nudityInappropriate adult content
SpamOrScamsSpam or scamsUnwanted promotional content
FalseInformationFalse informationMisinformation, fake news
OthersCustom reason (Max 300 chars)Any other violation type
Flag reasons are available on iOS, Android, and TypeScript platforms. JavaScript and Flutter use basic flagging without specific reasons.

Flag Messages

Report inappropriate messages to help maintain community safety and compliance with platform guidelines.

Implementation Examples

import AmitySDK

class MessageFlagManager {
    private let messageRepository: AmityMessageRepository
    
    init() {
        self.messageRepository = AmityMessageRepository()
    }
    
    func flagMessage(
        messageId: String,
        reason: AmityContentFlagReason
    ) async {
        do {
            try await messageRepository.flagMessage(withId: messageId, reason: reason)
            print("Message \(messageId) flagged successfully with reason: \(reason.description)")
        } catch {
            print("Failed to flag message \(messageId): \(error.localizedDescription)")
        }
    }
    
    // Convenience method for common flag reasons
    func flagForHarassment(messageId: String) async {
        await flagMessage(messageId: messageId, reason: .harassmentOrBullying)
    }
    
    func flagForSpam(messageId: String) async {
        await flagMessage(messageId: messageId, reason: .spamOrScams)
    }
    
    func flagWithCustomReason(messageId: String, reason: String) async {
        let trimmedReason = String(reason.prefix(300)) // Limit to 300 chars
        await flagMessage(messageId: messageId, reason: .others(trimmedReason))
    }
}

Unflag Messages

Remove flags from previously reported messages when they are no longer considered inappropriate or were flagged by mistake.
Users can unflag messages they previously flagged. This provides flexibility for accidental flags or changed perspectives on content.

Unflag Implementation Examples

extension MessageFlagManager {
    func unflagMessage(messageId: String) {
        messageRepository.unflag(messageId: messageId) { [weak self] result in
            switch result {
            case .success:
                self?.handleUnflagSuccess(messageId: messageId)
            case .failure(let error):
                self?.handleUnflagError(error: error, messageId: messageId)
            }
        }
    }
    
    private func handleUnflagSuccess(messageId: String) {
        print("Message \(messageId) unflagged successfully")
        
        DispatchQueue.main.async {
            // Update UI to show unflagged state
            self.showUnflagSuccessMessage()
            self.updateMessageUI(messageId: messageId, isFlagged: false)
        }
    }
    
    private func handleUnflagError(error: AmityError, messageId: String) {
        print("Failed to unflag message \(messageId): \(error.localizedDescription)")
        
        DispatchQueue.main.async {
            // Show error message to user
            self.showErrorAlert(
                title: "Unflag Failed",
                message: "Unable to unflag this message. Please try again."
            )
        }
    }
    
    // Check and toggle flag status
    func toggleMessageFlag(messageId: String) {
        checkIfMessageIsFlagged(messageId: messageId) { [weak self] isFlagged in
            if isFlagged {
                self?.unflagMessage(messageId: messageId)
            } else {
                // Show flag options to user
                self?.showFlagOptionsDialog(messageId: messageId)
            }
        }
    }
}

Check Flag Status

Verify whether a message has been flagged by the current user to provide appropriate UI states and prevent duplicate flags.
The isFlaggedByMe method only returns the flag status for the current user, not the overall flag status from all users.

Flag Status Implementation Examples

extension MessageFlagManager {
    func checkIfMessageIsFlagged(
        messageId: String,
        completion: @escaping (Bool) -> Void
    ) {
        messageRepository.isFlaggedByMe(messageId: messageId) { result in
            switch result {
            case .success(let isFlagged):
                completion(isFlagged)
            case .failure(let error):
                print("Failed to check flag status for message \(messageId): \(error)")
                completion(false) // Default to false on error
            }
        }
    }
    
    // Async/await version for iOS 13+
    @available(iOS 13.0, *)
    func checkIfMessageIsFlagged(messageId: String) async -> Bool {
        return await withCheckedContinuation { continuation in
            checkIfMessageIsFlagged(messageId: messageId) { isFlagged in
                continuation.resume(returning: isFlagged)
            }
        }
    }
    
    // Update UI based on flag status
    func updateMessageFlagUI(messageId: String) {
        checkIfMessageIsFlagged(messageId: messageId) { [weak self] isFlagged in
            DispatchQueue.main.async {
                self?.updateMessageUI(messageId: messageId, isFlagged: isFlagged)
            }
        }
    }
    
    // Batch check multiple messages
    func checkMultipleMessagesFlagStatus(
        messageIds: [String],
        completion: @escaping ([String: Bool]) -> Void
    ) {
        let dispatchGroup = DispatchGroup()
        var flagStatuses: [String: Bool] = [:]
        
        for messageId in messageIds {
            dispatchGroup.enter()
            checkIfMessageIsFlagged(messageId: messageId) { isFlagged in
                flagStatuses[messageId] = isFlagged
                dispatchGroup.leave()
            }
        }
        
        dispatchGroup.notify(queue: .main) {
            completion(flagStatuses)
        }
    }
}

Admin Integration

Flagged messages appear in the admin console for review and moderation actions by administrators.
  • Flag Review: View all flagged messages with flag reasons
  • Content Moderation: Delete or approve flagged content
  • Flag Management: Revoke flags that don’t violate policies
  • User Actions: Take action against users who violate guidelines
  • Analytics: Track flagging patterns and moderation metrics
  1. User flags message with specific reason
  2. Admin receives notification of flagged content
  3. Admin reviews message and context
  4. Admin makes decision: Delete content or revoke flag
  5. User receives feedback (optional) about moderation decision
  6. System logs action for audit trail

Best Practices

  • Clear Flag Options: Provide intuitive flag reason categories
  • Confirmation Dialogs: Confirm flag actions to prevent accidents
  • Visual Feedback: Show clear indication of flagged status
  • Educational Content: Help users understand flag policies
// Example flag confirmation dialog
function showFlagConfirmation(messageId, reason) {
    return new Promise((resolve) => {
        const modal = document.createElement('div');
        modal.innerHTML = `
            <div class="flag-confirmation-modal">
                <h3>Flag this message?</h3>
                <p>Reason: ${reason}</p>
                <p>This will report the message to moderators for review.</p>
                <button onclick="resolve(true)">Confirm</button>
                <button onclick="resolve(false)">Cancel</button>
            </div>
        `;
        document.body.appendChild(modal);
    });
}
  • Batch Operations: Process multiple flag status checks together
  • Caching: Cache flag statuses to reduce API calls
  • Lazy Loading: Load flag status only when needed
  • Debounced Updates: Prevent rapid flag/unflag operations
class FlagStatusCache {
    private cache = new Map<string, CacheEntry>();
    private readonly TTL = 5 * 60 * 1000; // 5 minutes
    
    async getFlagStatus(messageId: string): Promise<boolean> {
        const cached = this.cache.get(messageId);
        
        if (cached && Date.now() - cached.timestamp < this.TTL) {
            return cached.value;
        }
        
        const status = await this.fetchFlagStatus(messageId);
        this.cache.set(messageId, {
            value: status,
            timestamp: Date.now()
        });
        
        return status;
    }
}
  • Network Failures: Implement retry logic with backoff
  • Permission Errors: Handle unauthorized flag attempts gracefully
  • Rate Limiting: Respect API rate limits and queue requests
  • User Feedback: Provide clear error messages and recovery options
func handleFlagError(_ error: Error) {
    let nsError = error as NSError
    guard let errorCode = AmityErrorCode(rawValue: nsError.code) else {
        showErrorMessage("Unable to flag message. Please try again.")
        return
    }
    switch errorCode {
    case .connectionError:
        showRetryOption("Network error. Please check your connection.")
    case .permissionDenied:
        showErrorMessage("You don't have permission to flag this message.")
    case .rateLimit:
        showErrorMessage("Too many requests. Please try again later.")
    default:
        showErrorMessage("Unable to flag message. Please try again.")
    }
}
  • Abuse Prevention: Implement rate limiting for flag operations
  • Spam Detection: Monitor for users who flag excessively
  • Content Validation: Validate flag reasons on client and server
  • Audit Logging: Maintain logs of all flag operations
class FlagSecurityManager {
    private userFlagCount = new Map<string, number>();
    private readonly MAX_FLAGS_PER_HOUR = 10;
    private readonly FLAG_WINDOW = 60 * 60 * 1000; // 1 hour
    
    canUserFlag(userId: string): boolean {
        const count = this.userFlagCount.get(userId) || 0;
        return count < this.MAX_FLAGS_PER_HOUR;
    }
    
    recordFlag(userId: string): void {
        const count = this.userFlagCount.get(userId) || 0;
        this.userFlagCount.set(userId, count + 1);
        
        // Reset counter after window
        setTimeout(() => {
            this.userFlagCount.delete(userId);
        }, this.FLAG_WINDOW);
    }
}

Advanced Features

Bulk Flag Operations

Handle multiple messages simultaneously

Flag Analytics

Track flagging patterns and metrics

Custom Flag Reasons

Implement domain-specific flag categories

Automated Moderation

Integrate with AI-powered content filtering

Bulk Flag Operations

class BulkFlagManager {
    async flagMultipleMessages(
        requests: Array<{ messageId: string; reason: Amity.ContentFlagReason; customReason?: string }>
    ): Promise<BulkFlagResult> {
        const results = await Promise.allSettled(
            requests.map(request => this.flagMessage(request))
        );
        
        const successful = results.filter(r => r.status === 'fulfilled').length;
        const failed = results.filter(r => r.status === 'rejected').length;
        
        return {
            total: requests.length,
            successful,
            failed,
            results: results.map((result, index) => ({
                messageId: requests[index].messageId,
                success: result.status === 'fulfilled',
                error: result.status === 'rejected' ? result.reason : undefined
            }))
        };
    }
}

Content Moderation

Comprehensive content moderation strategies

Member Management

Manage roles, bans, and mutes

Content Moderation

Review and moderate flagged messages

Real-time Events

Event-driven moderation notifications