Ground truth:
@cometchat/calls-sdk-react-native@5+ catalogrn-calls-v5.json(58 symbols) +features.rn-v5.json→voice-video-calls. Docs:/ui-kit/react-native/calling-integration·call-features·call-buttons·call-logs·incoming-call·outgoing-call.
Companion skills (read first)
cometchat-react-native-core— install, provider chain, init→login→render. Assumed, not repeated here.
Use this skill when
- "add voice/video calling" · "incoming call screen" · "calls aren't ringing" · "call logs"
Prerequisites & install
⚠️ React Native has its OWN calls SDK. @cometchat/calls-sdk-javascript is the web package and
will not work here.
bashnpm install @cometchat/calls-sdk-react-native@5 # 6 REQUIRED peer deps — the SDK's declared peerDependencies. Versions are pinned; do NOT float them. npm install @react-native-async-storage/async-storage@^2.1.2 react-native-background-timer@^2.4.1 \ react-native-performance@^5.1.2 react-native-svg@^15.12.0 react-native-url-polyfill@2.0.0 \ react-native-webrtc@124.0.7 # ⚠️ react-native-performance MUST stay 5.x — 6.x is published, and a floated `^6` makes every later # `npm install` in the app fail with ERESOLVE. react-native-url-polyfill + react-native-performance # are BUNDLE-critical: the UIKit does a module-scope require() of the calls SDK, so Metro resolves # them even for a chat-only build — omit either and the bundle fails with "Unable to resolve module". # (NOT react-native-community/netinfo or react-native-callstats — those are not declared peers.) cd ios && pod install && cd .. # bare RN; Expo: npx expo run:ios
Enabling calls — there is no flag
Installing the package IS the switch. The kit does a try { require("@cometchat/calls-sdk-react-native") }
at startup; if it resolves, calling is enabled automatically.
React's setCallingEnabled(true) does not exist in this kit — do not emit it. There is likewise no
opt-out on the initFromSettings golden path — the CometChatSettings file/object has no calling field,
and CometChatUIKit.initFromSettings() never reads one. disableCalling: true exists only as a field
on the UIKitSettings object you pass to the legacy CometChatUIKit.init(uiKitSettings) — so to disable
calling while the package stays installed you must switch to that init() entry point (or simply not
install the calls SDK).
Consequence worth knowing: a half-finished install (package added, pods not run) can leave calling "enabled" in JS while the native side is missing — which surfaces as a crash on first call rather than a clear error at startup.
Native floors — below these it will not build
| Platform | Requirement | Where |
|---|---|---|
| Android | minSdkVersion 24 | android/app/build.gradle |
| iOS | IPHONEOS_DEPLOYMENT_TARGET 13.0 | Xcode target or a Podfile post_install |
Permissions — camera and microphone
Bare RN — ios/<App>/Info.plist:
xml<key>NSCameraUsageDescription</key><string>Camera access for video calls</string> <key>NSMicrophoneUsageDescription</key><string>Microphone access for voice/video calls</string>
Android: CAMERA · RECORD_AUDIO · MODIFY_AUDIO_SETTINGS · BLUETOOTH_CONNECT (Android 12+, Bluetooth audio routing) in AndroidManifest.xml.
Expo — the same values go in app.json (ios.infoPlist, android.permissions), then rebuild.
Never hand-edit the generated native projects.
Components (from catalogs/rn-v5.json)
| Component | Purpose |
|---|---|
CometChatCallButtons | audio/video triggers — the message header shows these by default |
CometChatIncomingCall | the ring screen — mount once above the navigator |
CometChatOutgoingCall | the dialling screen |
CometChatOngoingCall | the in-call surface (no React equivalent) |
CometChatCallLogs | call history list |
CometChatIncomingCall mounted inside one screen means calls only arrive while that screen is open —
the commonest "calls don't ring" cause after a missing permission.
The table above is not enough to copy — wire it:
tsx// App.tsx — IncomingCall sits ABOVE the navigator so a call rings on any screen. function App() { const incomingCall = useRef<CometChat.Call | null>(null); const [callReceived, setCallReceived] = useState(false); useEffect(() => { const listenerId = "APP_CALL_LISTENER"; CometChat.addCallListener( listenerId, new CometChat.CallListener({ onIncomingCallReceived: (call) => { incomingCall.current = call; setCallReceived(true); }, onOutgoingCallRejected: () => setCallReceived(false), onIncomingCallCancelled: () => setCallReceived(false), }), ); return () => CometChat.removeCallListener(listenerId); // or it fires after unmount }, []); return ( <GestureHandlerRootView style={{ flex: 1 }}> <NavigationContainer>{/* … */}</NavigationContainer> {callReceived && incomingCall.current ? ( <CometChatIncomingCall call={incomingCall.current} onDecline={() => { incomingCall.current = null; setCallReceived(false); }} /> ) : null} </GestureHandlerRootView> ); }
tsx// Call triggers — the message header renders these by default; mount them yourself only // when you build a custom header. onError is the ONLY callback: success is an event // (ccOutgoingCall), not a promise. <CometChatCallButtons user={user} group={group} onError={(e) => console.error(e)} /> // Dialling screen — driven by the Call object you created. {call && <CometChatOutgoingCall call={call} />} // Call history list. Detail screens do NOT ship (see below). <CometChatCallLogs onItemPress={(log) => openCallDetail(log)} />
tsx// The in-call surface. sessionID comes from the accepted Call; callSettingsBuilder is a // CometChatCalls builder, NOT a chat-SDK one. <CometChatOngoingCall sessionID={sessionId} callSettingsBuilder={callSettings} onError={(e) => console.error(e)} />
DOCS GAP (RN-G15 — narrowed upstream, verified 2026-09-09):
CometChatOngoingCallis exported by the RN kit and is now listed on/ui-kit/react-native/call-features(the Components row), but it still has no dedicated props page — only Incoming / Outgoing / Buttons / Logs get their own pages. The fence above is a STOPGAP built from the kit's own types — replace it once a props page ships. Flagged for the docs team; do not conclude the component is unavailable on RN.
Call logs: the list ships, the detail screens do not
Kit v5 removed CometChatCallLogDetails / History / Participants / Recordings. For a custom detail
view, fetch the history yourself with the Calls-SDK CallLogRequestBuilder — a static on
CometChatCalls, reachable only from @cometchat/calls-sdk-react-native:
ts// Call history — CometChatCalls.CallLogRequestBuilder from the CALLS SDK. // There is NO CallLogRequestBuilder on the Chat SDK (@cometchat/chat-sdk-react-native). import { CometChat } from "@cometchat/chat-sdk-react-native"; import { CometChatCalls } from "@cometchat/calls-sdk-react-native"; // fetchNext() REJECTS without an auth token ("`Auth Token` is required") — no fallback. Pass the // logged-in user's token, exactly as the kit's own CometChatCallLogs does. const authToken = (await CometChat.getLoggedinUser())?.getAuthToken() ?? ""; const req = new CometChatCalls.CallLogRequestBuilder().setLimit(30).setAuthToken(authToken).build(); const logs = await req.fetchNext(); // Transcript opt-in — same builder + token. setHasTranscriptions(true) filters to transcribed calls // AND makes the server attach each call's transcripts to the log. const treq = new CometChatCalls.CallLogRequestBuilder().setLimit(30).setAuthToken(authToken).setHasTranscriptions(true).build();
RN-G9 (verified 2026-09-10 vs
@cometchat/calls-sdk-react-native@5):CallLogRequestBuilderis a static onCometChatCalls(calls SDK) —new CometChatCalls.CallLogRequestBuilder(). It does not exist on the Chat SDK: there is noCometChat.CallLogRequestBuilderin@cometchat/chat-sdk-react-native(any version). Use the Calls-SDK builder for history, always with.setAuthToken(...)(without itfetchNext()rejects — verified in@cometchat/calls-sdk-react-native@5.0.5); addsetHasTranscriptions(true)only when you need transcripts. It is reachable as a static on the module, not as a bare named import.
Verification requires a real device
Simulators and emulators cannot capture camera or microphone. A green simulator run proves the screens render, not that a call connects. Media, permissions and ringing must be checked on hardware.
Common pitfalls
- Installing the web calls SDK — wrong package.
- Emitting
setCallingEnabled(true)— does not exist; installation is the switch. CometChatIncomingCallinside a screen — calls only ring there.- Skipping
pod install/ rebuild — crash on first call, not at startup. - Below the version floors — build failure, not a runtime message.
- Signing off from a simulator — no media capture.
Verify it works
- Every emitted symbol is in
catalogs/rn-v5.jsonorcatalogs/rn-calls-v5.json. npm run verify:fences:rn-v5is green.- On two real devices: call connects both ways, permission prompts appear on first use, the incoming screen shows while the app is on any tab, and the call log records the call.

