cometchat-ios-features — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cometchat-ios-features (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Ground truth:CometChatUIKitSwift ~> 5+packages/registry/v6/features/catalog.json. (Official docs linked below.) Verify symbols against the installed package/source before relying on them.
Canonical public feature-availability matrix: Features & Extensions Guide — the authoritative source for which integration method (UI Kit / UI Kit Builder / Widget Builder / SDK) supports each feature + dashboard setup + whether code is required. It outranks the local `catalog.json` snapshot on conflict; consult it (WebFetch or docs MCP) for any availability decision.
This skill documents all features available in CometChat iOS UI Kit v5 — voice/video calls, reactions, polls, stickers, AI features, and extensions. Use this to understand what's available and how to enable/configure each feature.
Classify the feature by the product's 5-category "work needed" model before enabling: Core (zero-setup) — out of the box (typing, reactions) · Builder-enabled — Dashboard API + UI Kit Builder toggle (polls) · Config-only — Dashboard API, automatic (link preview) · Config + settings — Dashboard API + extra settings/keys, no code (smart replies) · SDK-integrated — Dashboard API + custom client code (Bitly). Key rule: only SDK-integrated features need client code, and the implementation lives in the docs — cometchat features info <id> --json shows what's needed (auto_wired_in_uikit: false ⇒ the toggle alone won't render it; fetch + adapt the doc code, don't hand-roll). Don't assume "enabled = visible" for dashboard extensions.
Honest-automation boundary: standard extensions (polls, stickers, link-preview, message-translation, etc.) are enabled with a real dashboard API call via cometchat apply-feature <id> --app-id <your-app-id> — never tell the user to toggle them manually. But third-party dashboard-only features (Giphy, Stipop, Tenor, Chatwoot, Intercom, Disappearing Messages, Message Shortcuts) return manual-action-required: they need your third-party credentials and cannot be automated — state that. Call recording is a paid plan add-on (contact CometChat support; no toggle/CLI) — never claim it was enabled (see §1 Voice & Video Calls).
Add the CometChat Calls SDK to your project:
CocoaPods:
pod 'CometChatCallsSDK', '~> 5.0'Swift Package Manager:
https://github.com/cometchat/calls-sdk-iosAdd to Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required for video calls</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for voice and video calls</string>In Xcode → Target → Signing & Capabilities → Background Modes:
Add call buttons to your message header:
let messageHeader = CometChatMessageHeader()
messageHeader.set(user: user)
// Call buttons are shown by default when CometChatCallsSDK is available
// To hide them:
messageHeader.hideVideoCallButton = true
messageHeader.hideVoiceCallButton = true// CometChatCallButtons requires explicit width/height at init — no zero-arg init.
let callButtons = CometChatCallButtons(width: 80, height: 32)
callButtons.set(user: user)
// Or for group calls
callButtons.set(group: group)
// Customize
callButtons.hideVideoCallButton = false
callButtons.hideVoiceCallButton = falseimport CometChatSDK
// Voice call to user
let call = Call(receiverId: user.uid ?? "", callType: .audio, receiverType: .user)
CometChat.initiateCall(call: call) { call in
print("Call initiated: \(call?.sessionID ?? "")")
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}
// Video call to user
let videoCall = Call(receiverId: user.uid ?? "", callType: .video, receiverType: .user)
CometChat.initiateCall(call: videoCall) { call in
print("Video call initiated")
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}
// Group call
let groupCall = Call(receiverId: group.guid ?? "", callType: .video, receiverType: .group)
CometChat.initiateCall(call: groupCall) { call in
print("Group call initiated")
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}CometChat UI Kit automatically handles incoming calls when properly configured. The CometChatIncomingCall view controller is presented automatically.
For custom handling:
import CometChatSDK
class CallListener: CometChatCallDelegate {
func onIncomingCallReceived(incomingCall: Call?, error: CometChatException?) {
guard let call = incomingCall else { return }
DispatchQueue.main.async {
let incomingCallVC = CometChatIncomingCall()
incomingCallVC.set(call: call)
incomingCallVC.modalPresentationStyle = .fullScreen
// Present from root view controller
UIApplication.shared.windows.first?.rootViewController?.present(
incomingCallVC,
animated: true
)
}
}
func onOutgoingCallAccepted(acceptedCall: Call?, error: CometChatException?) {
print("Call accepted")
}
func onOutgoingCallRejected(rejectedCall: Call?, error: CometChatException?) {
print("Call rejected")
}
func onIncomingCallCancelled(canceledCall: Call?, error: CometChatException?) {
print("Call cancelled")
}
}
// Register listener
CometChat.addCallListener("call-listener", CallListener())Customize call behavior:
#if canImport(CometChatCallsSDK)
import CometChatCallsSDK
let callSettings = CallSettingsBuilder()
.setIsAudioOnly(false) // Video call
.setDefaultAudioMode("SPEAKER") // "SPEAKER" or "EARPIECE"
.setShowSwitchToVideoCall(true) // Allow switching to video
// Button visibility uses inverted setXxxButtonDisable(Bool), NOT setShowXxxButton:
.setEndCallButtonDisable(false)
.setMuteAudioButtonDisable(false)
.setPauseVideoButtonDisable(false)
.setSwitchCameraButtonDisable(false)
.setAudioModeButtonDisable(false)
.setStartAudioMuted(false) // not setStartWithAudioMuted
.setStartVideoMuted(false) // not setStartWithVideoMuted
.build()
let outgoingCall = CometChatOutgoingCall()
outgoingCall.set(call: call)
outgoingCall.set(callSettingsBuilder: callSettings)
#endifDisplay call history:
let callLogs = CometChatCallLogs()
callLogs.set(onItemClick: { callLog in
// Handle call log tap - maybe initiate a new call
// (the closure receives the tapped call log as `Any`)
print("Call log tapped: \(callLog)")
})
navigationController?.pushViewController(callLogs, animated: true)Reactions are enabled by default in CometChat UI Kit v5.
let messageList = CometChatMessageList()
messageList.set(user: user)
// Hide reaction option from message menu
messageList.hideReactionOption = trueclass ReactionListener: CometChatMessageEventListener {
// ReactionEvent.reaction is a `Reaction?` OBJECT, not a String. The
// emoji/uid/messageId live on that nested Reaction; the event itself
// carries parentMessageId/conversationId/receiverId (there is NO `message`
// or `reactedBy` property on ReactionEvent).
func onMessageReactionAdded(reactionEvent: ReactionEvent) {
print("Reaction added: \(reactionEvent.reaction?.reaction ?? "")")
print("By user: \(reactionEvent.reaction?.uid ?? "")")
print("On message: \(reactionEvent.reaction?.messageId ?? 0)")
}
func onMessageReactionRemoved(reactionEvent: ReactionEvent) {
print("Reaction removed: \(reactionEvent.reaction?.reaction ?? "")")
}
}
CometChatMessageEvents.addListener("reaction-listener", ReactionListener())// Configure available reactions
let messageList = CometChatMessageList()
// The reaction set is configured through the data source
// See cometchat-ios-customization skill for DataSource customizationPolls allow users to create and vote on questions.
cometchat apply-feature polls --app-id <your-app-id>Once enabled, the poll creation option appears in the attachment menu.
import CometChatSDK
// Create poll data
let pollData: [String: Any] = [
"question": "What's your favorite programming language?",
"options": ["Swift", "Kotlin", "JavaScript", "Python"]
]
// Create custom message with poll type
// CustomMessage has no customType: init — pass the type via the trailing type: label
let pollMessage = CustomMessage(
receiverUid: user.uid ?? "",
receiverType: .user,
customData: pollData,
type: "extension_poll"
)
CometChat.sendCustomMessage(message: pollMessage) { message in
print("Poll sent: \(message.id)")
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}// Polls render via the `CometChatPollsBubble` view (note the plural — there is no
// `CometChatPollBubble`). Its `style` is an INSTANCE property of type `PollBubbleStyle`
// (NOT a static), so you cannot assign `CometChatPollsBubble.style.x = …`.
// To restyle the poll bubble, build a `PollBubbleStyle`, then apply it inside a custom
// message template's bubble view (see cometchat-ios-customization → message templates):
let pollStyle = PollBubbleStyle()
pollStyle.backgroundColor = .secondarySystemBackground
// …set the PollBubbleStyle properties you need, then pass the styled
// CometChatPollsBubble instance from your template's bubbleView closure.Stickers provide a fun way to express emotions.
cometchat apply-feature stickers --app-id <your-app-id>Once enabled, the sticker button appears in the message composer.
let messageComposer = CometChatMessageComposer()
messageComposer.set(user: user)
messageComposer.hideStickersButton = trueSticker packs are managed through the CometChat Dashboard:
CometChat provides AI-powered features for enhanced chat experiences.
iOS projects don't run cometchat apply (no .cometchat/state.json), so call the CLI in stateless mode with --app-id. AI features need an OpenAI key the first time:
cometchat apply-feature smart-replies --app-id <your-app-id> --openai-key sk-...
cometchat apply-feature conversation-summary --app-id <your-app-id>
cometchat apply-feature conversation-starter --app-id <your-app-id>The OpenAI key is stored on the app once. Subsequent ai-feature applies don't need --openai-key repeated. Requires cometchat auth login once per machine.
Get an OpenAI key at https://platform.openai.com/api-keys.
Suggests conversation starters for new chats:
let conversationStarter = CometChatAIConversationStarter()
// Set AI message options
conversationStarter.set(aiMessageOptions: [
"How can I help you today?",
"What brings you here?",
"Tell me about your project"
])
// Handle selection
conversationStarter.onMessageClicked { selectedReply in
print("Selected: \(selectedReply)")
// Send the selected message
}
// Show loading state
conversationStarter.showLoadingView()
// Hide loading state
conversationStarter.hideLoadingView()
// Show error state
conversationStarter.show(error: true)Suggests quick replies based on conversation context:
// Smart replies are automatically shown in the message composer
// when enabled in the dashboard
// To customize the smart replies view:
let messageComposer = CometChatMessageComposer()
messageComposer.set(user: user)
// Smart replies appear above the composer when availableGenerates a summary of the conversation:
// Conversation summary is available through the AI extension
// Enable in CometChat Dashboard → AI → Conversation Summary
// The summary can be accessed through the message header menu
// or programmatically:
// Get conversation summary
CometChat.getConversationSummary(
receiverId: user.uid ?? "",
receiverType: .user
) { summary in
print("Summary: \(summary)")
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}Create AI-powered chat bots:
// AI Bots are configured in CometChat Dashboard
// They appear as regular users in the chat
// To start a conversation with an AI bot:
let botUID = "ai-assistant" // Your bot's UID from dashboard
CometChat.getUser(UID: botUID) { bot in
guard let bot = bot else { return }
let messagesVC = MessagesVC() // your own VC composing CometChatMessageHeader + List + Composer
messagesVC.set(user: bot)
// Present the messages view
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}CometChatAIAssistantBubble.style.backgroundColor = .secondarySystemBackground
CometChatAIAssistantBubble.style.textColor = .label
CometChatAIAssistantBubble.style.textFont = CometChatTypography.Body.regular
CometChatAIAssistantBubble.style.borderColor = .separator
CometChatAIAssistantBubble.style.borderWidth = 1
CometChatAIAssistantBubble.style.cornerRadius = CometChatCornerStyle(cornerRadius: 12)Automatically generates previews for URLs shared in messages.
Link preview is enabled by default.
// Link previews are handled automatically
// No additional configuration needed// Customize link preview appearance
// Link previews use the standard message bubble stylingTranslate messages to different languages.
cometchat apply-feature message-translation --app-id <your-app-id>// Translation option appears in message menu when enabled
// Users can tap "Translate" to see the translated version
// Programmatic translation: there is NO `CometChat.translateMessage(...)`
// method. Message translation is an extension — invoke it via callExtension
// against the message-translation slug:
CometChat.callExtension(
slug: "message-translation",
type: .post,
endPoint: "v2/translate",
body: [
"msgId": textMessage.id,
"text": textMessage.text,
"languages": ["es"] // target languages
]
) { response in
// response is [String: Any]? — read the translated text from the
// extension payload (see the message-translation extension docs).
print("Translation response: \(response ?? [:])")
} onError: { error in
print("Error: \(error?.errorDescription ?? "")")
}Real-time whiteboard for drawing and collaboration:
# Enable Collaborative Whiteboard via CLI:
cometchat apply-feature collaborative-whiteboard --app-id <your-app-id>// Whiteboard option appears in attachment menu
// Opens a shared whiteboard sessionReal-time document editing:
# Enable Collaborative Document via CLI:
cometchat apply-feature collaborative-document --app-id <your-app-id>// Document option appears in attachment menu
// Opens a shared document sessionShow when users are typing.
let messageComposer = CometChatMessageComposer()
messageComposer.set(user: user)
// Disable sending typing events
messageComposer.disableTypingEvents = true
// Typing indicators in message list
let messageList = CometChatMessageList()
messageList.set(user: user)
// Typing indicators are shown automaticallyclass TypingListener: CometChatMessageDelegate {
func onTypingStarted(_ typingIndicator: TypingIndicator) {
print("\(typingIndicator.sender?.name ?? "") is typing...")
}
func onTypingEnded(_ typingIndicator: TypingIndicator) {
print("\(typingIndicator.sender?.name ?? "") stopped typing")
}
}
CometChat.addMessageListener("typing-listener", TypingListener())Show message delivery and read status.
let messageList = CometChatMessageList()
messageList.set(user: user)
// Hide read receipts
messageList.hideReceipts = true
// In conversations list
let conversations = CometChatConversations()
conversations.hideReceipts = trueReply to specific messages in threads.
let messageList = CometChatMessageList()
messageList.set(user: user)
// Hide thread reply option
messageList.hideReplyInThreadOption = true// Thread replies are handled automatically
// Tapping "Reply in thread" opens the thread view
// Programmatic thread access:
messageList.onThreadRepliesClick = { message, template in
// Custom thread handling
print("Thread for message: \(message.id)")
}Record and send voice messages.
let messageComposer = CometChatMessageComposer()
messageComposer.set(user: user)
// Hide voice recording button
messageComposer.hideVoiceRecordingButton = trueAdd to Info.plist:
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for voice messages</string>Send animated reactions that appear on screen. Live reactions are enabled by default and handled automatically by the SDK.
class LiveReactionListener: CometChatMessageEventListener {
func ccLiveReaction(reaction: TransientMessage) {
print("Live reaction received: \(reaction.data)")
// Show animation on screen
}
}
CometChatMessageEvents.addListener("live-reaction-listener", LiveReactionListener())Filter inappropriate content and mask sensitive data.
Automatically generates thumbnails for images and videos.
| Feature | Requires SDK | Dashboard Config | Default |
|---|---|---|---|
| Voice/Video Calls | CometChatCallsSDK | No | Enabled* |
| Reactions | No | No | Enabled |
| Polls | No | Yes | Enabled |
| Stickers | No | Yes | Enabled |
| AI Features | No | Yes | Disabled |
| Link Preview | No | Yes | Enabled |
| Translation | No | Yes | Disabled |
| Whiteboard | No | Yes | Disabled |
| Collaborative Doc | No | Yes | Disabled |
| Typing Indicators | No | No | Enabled |
| Read Receipts | No | No | Enabled |
| Threaded Messages | No | No | Enabled |
| Voice Recording | No | No | Enabled |
| Live Reactions | No | No | Enabled |
| Profanity Filter | No | Yes | Disabled |
*Calls require CometChatCallsSDK to be installed
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.