{"id":"62ca2737-d397-482b-bde9-ef4c9d826d55","shortId":"SBgy9j","kind":"skill","title":"cometchat-native-push","tagline":"Push notifications for React Native CometChat — APNs + FCM setup, dashboard provider configuration, client registration, token lifecycle, foreground display, background wake, tap-to-deep-link, and the Expo Go / APNs-environment traps that silently break production.","description":"## Purpose\n\nTeaches Claude how to add push notifications to a CometChat React Native integration — end-to-end, from Apple Developer / Google Cloud setup through CometChat dashboard provider configuration, client token registration, foreground/background handling, and tap-to-deep-link.\n\n**Push is non-negotiable for production chat.** Without it, a backgrounded app never wakes when a message arrives. The user doesn't see the message, doesn't re-open the app, and stops using chat. This is THE feature that separates \"works in demo\" from \"works in production.\"\n\nGround truth: `examples/SampleAppWithPushNotifications/` in `@cometchat/chat-uikit-react-native@5.3.3`, `docs/sdk/react-native/push-notification-setup.mdx`, and `https://www.cometchat.com/docs/notifications/push-integration`.\n\n---\n\n## 1. The moving pieces\n\nPush spans four systems that must all agree:\n\n```\n┌─────────────┐    ┌─────────────┐    ┌──────────────┐    ┌────────┐\n│ Apple /     │    │ CometChat   │    │ CometChat    │    │ RN     │\n│ Google      │ →  │ Dashboard   │ →  │ server       │ →  │ client │\n│ (APNs/FCM)  │    │ (providers) │    │ (via SDK)    │    │ (app)  │\n└─────────────┘    └─────────────┘    └──────────────┘    └────────┘\n p8 key / JSON     Uploaded creds    Webhook on message   Displays notif\n```\n\nWhen user A sends a message to user B:\n1. CometChat server receives the message\n2. Looks up B's registered push tokens (client did this at login)\n3. Sends a push via APNs (iOS) or FCM (Android) using the credentials the dashboard holds\n4. B's device receives it, OS wakes the app (or fires foreground handler)\n5. Notification displays; tap → app navigates to the conversation\n\nAll five steps must work. A broken step is almost always silent — no log, no error, just no notification. Debugging requires checking each layer.\n\n---\n\n## 2. Expo Go CANNOT receive push notifications\n\n**This is the #1 support ticket from Expo users.** Expo Go is a prebuilt shell app without your custom native modules — it has no APNs entitlement, no FCM configuration, no way to receive your app's push.\n\n**For push, Expo projects require a development build:**\n```bash\nnpx expo install expo-dev-client\nnpx expo prebuild --clean   # generates ios/ + android/ with native configuration\neas build --profile development --platform ios       # or android\n```\n\nOpen the resulting `.ipa` / `.apk` and run `npx expo start --dev-client`. This is the only Expo setup that can receive push.\n\nIf a user reports \"I set everything up but no notifications arrive\" and they're running Expo Go, that's the answer — no code fix will help.\n\n---\n\n## 3. APNs setup (iOS)\n\n### 3a. Create an APNs Auth Key (p8)\n\nApple's two options for signing push — certificate (`.p12`) or auth key (`.p8`). Use `.p8`. It never expires, one key works for all your apps, and CometChat accepts the simpler key format.\n\n1. https://developer.apple.com/account → **Certificates, Identifiers & Profiles** → **Keys** → \"+\"\n2. Name it (e.g., \"CometChat APNs\"), check **Apple Push Notifications service (APNs)**, Continue, Register\n3. **Download the `.p8` file** (one-time — Apple never lets you download it again)\n4. Copy the **Key ID** (10-char alphanumeric, shown on the key page)\n5. From the membership page, copy your **Team ID** (10-char alphanumeric, top-right)\n6. Collect your app's **Bundle ID** (from `ios/<Name>.xcodeproj` → Targets → General)\n\nYou'll paste all four into the CometChat dashboard in §5.\n\n### 3b. Enable Push Notifications capability in Xcode\n\n```\nOpen ios/<Name>.xcworkspace\nSelect the project → Signing & Capabilities tab\nClick \"+ Capability\" → \"Push Notifications\"\nClick \"+ Capability\" → \"Background Modes\"\n  In Background Modes, check:\n    - Remote notifications\n    - Voice over IP (only if integrating CometChat calls)\n```\n\nThis writes `aps-environment` (development or production) into the entitlements file. Wrong environment is the #1 silent-failure in §10.\n\n### 3c. Two environments — the TestFlight / App Store trap\n\nAPNs has two parallel networks:\n- **Development** (`aps-environment: development`) — Xcode dev builds. Uses dev key paths.\n- **Production** (`aps-environment: production`) — TestFlight, App Store, Ad-Hoc. Uses prod key paths.\n\nThe p8 auth key you generated in 3a works for **both** environments. But CometChat has to know which environment the token came from. If you upload the p8 only as \"Development\" in the dashboard, TestFlight builds silently fail — a token arrives from production APNs but the dashboard has no matching credentials.\n\n**Fix:** upload the same p8 twice in the CometChat dashboard — once as Development provider, once as Production provider. Then register with the matching provider ID at runtime (§7).\n\n---\n\n## 4. FCM setup (Android)\n\n### 4a. Create a Firebase project + service account\n\n1. https://console.firebase.google.com → **Add project** → name it, continue through setup\n2. **Project Settings** (gear icon) → **Service accounts** tab\n3. **Generate new private key** → downloads a `.json` file with your server credentials\n\nThis JSON file is what CometChat's dashboard needs.\n\n### 4b. Add Android app to Firebase + download google-services.json\n\n1. Project Overview → **Add app** → Android\n2. Enter your app's **package name** (from `android/app/build.gradle` → `applicationId`)\n3. Download `google-services.json`\n4. Place it at `android/app/google-services.json`\n5. Add this line at the end of `android/app/build.gradle`:\n   ```gradle\n   apply plugin: 'com.google.gms.google-services'\n   ```\n6. In `android/build.gradle` under `buildscript.dependencies`:\n   ```gradle\n   classpath 'com.google.gms:google-services:4.4.2'\n   ```\n\n**Expo managed:** `google-services.json` goes in the project root, and you reference it in `app.json`:\n```json\n{\n  \"expo\": {\n    \"android\": {\n      \"googleServicesFile\": \"./google-services.json\"\n    },\n    \"plugins\": [\"@react-native-firebase/app\", \"@react-native-firebase/messaging\"]\n  }\n}\n```\n\n### 4c. iOS Firebase config (if using firebase/messaging on iOS)\n\n`react-native-firebase/messaging` wraps APNs under the hood on iOS, so the APNs setup in §3 is what actually powers iOS push. BUT Firebase expects a `GoogleService-Info.plist` even though it doesn't route iOS push through FCM:\n1. Add iOS app in Firebase console (Project Overview → Add app → iOS)\n2. Download `GoogleService-Info.plist`\n3. Add it to `ios/<Name>/` via Xcode (Right-click project → Add Files)\n4. In Expo: put it at project root and reference in `app.json`:\n   ```json\n   { \"expo\": { \"ios\": { \"googleServicesFile\": \"./GoogleService-Info.plist\" } } }\n   ```\n\n---\n\n## 5. CometChat dashboard — upload credentials\n\nhttps://app.cometchat.com → your app → **Notifications** → **Push Notifications**\n\n### 5a. Add an APNs provider (per environment)\n\n- **Add Provider** → choose APNs\n- Provider name: `apns-dev` (or similar)\n- Environment: **Development**\n- Upload the `.p8` file from §3a\n- Paste Key ID, Team ID, Bundle ID\n- Save → copy the **Provider ID** string (you'll need it in §7)\n\nRepeat for Production:\n- Provider name: `apns-prod`\n- Environment: **Production**\n- Same p8, Key ID, Team ID, Bundle ID\n- Save → copy the second Provider ID\n\nIf you skip the production provider, TestFlight / App Store builds will silently not receive push.\n\n### 5b. Add an FCM provider\n\n- **Add Provider** → choose FCM\n- Provider name: `fcm-default`\n- Upload the service account `.json` file from §4a\n- Save → copy the Provider ID\n\n### 5c. Cache the Provider IDs\n\nYou'll have 2-3 provider IDs. Store them in a config constant in your app:\n```ts\n// src/config/push.ts\nexport const PUSH_PROVIDERS = {\n  fcm: \"fcm-<hex-from-dashboard>\",\n  apnsDev: \"apns-dev-<hex-from-dashboard>\",\n  apnsProd: \"apns-prod-<hex-from-dashboard>\",\n};\n```\n\nAt runtime (§7), you'll pick the right one based on platform + `__DEV__`.\n\n---\n\n## 6. Install client packages\n\n### Bare React Native\n\n```bash\nnpm install @react-native-firebase/app @react-native-firebase/messaging \\\n  @notifee/react-native @react-native-community/push-notification-ios\n\ncd ios && pod install && cd ..\n```\n\n- `@react-native-firebase/app` — initializes Firebase (reads GoogleService-Info.plist / google-services.json)\n- `@react-native-firebase/messaging` — FCM on Android AND APNs on iOS (Firebase handles both)\n- `@notifee/react-native` — local notification display (for foreground messages on Android; required because FCM data-only pushes don't auto-display)\n- `@react-native-community/push-notification-ios` — iOS APNs device token retrieval + notification tap handling (`getInitialNotification`, `addEventListener`)\n\n### Expo managed (dev build)\n\n```bash\nnpx expo install @react-native-firebase/app @react-native-firebase/messaging \\\n  @notifee/react-native @react-native-community/push-notification-ios expo-dev-client\nnpx expo prebuild --clean\n```\n\nThen build a dev client (§2) and run `npx expo start --dev-client`.\n\n**iOS permissions in `ios/<Name>/Info.plist`:** no changes needed for basic push.\n\n**Android permissions in `android/app/src/main/AndroidManifest.xml`:**\n```xml\n<uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n<uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n```\n\nFor Expo managed, put permissions in `app.json`:\n```json\n{\n  \"expo\": {\n    \"android\": {\n      \"permissions\": [\"POST_NOTIFICATIONS\", \"WAKE_LOCK\"]\n    }\n  }\n}\n```\n\n---\n\n## 7. Register the push token with CometChat\n\nThe canonical API — confirmed from `examples/SampleAppWithPushNotifications/src/utils/PushNotification.tsx`:\n\n```ts\nimport { CometChatNotifications } from \"@cometchat/chat-sdk-react-native\";\n```\n\n`CometChatNotifications.PushPlatforms` enum values:\n\n| Platform | Enum value |\n|---|---|\n| Android (FCM) | `FCM_REACT_NATIVE_ANDROID` |\n| iOS (FCM — Firebase proxies APNs) | `FCM_REACT_NATIVE_IOS` |\n| iOS (APNs direct, non-VoIP) | `APNS_REACT_NATIVE_DEVICE` |\n| iOS (APNs VoIP — calls only) | `APNS_REACT_NATIVE_VOIP` |\n\nMost apps use FCM on both platforms (simpler — Firebase handles the APNs dance). Only use `APNS_REACT_NATIVE_DEVICE` if you're registering the raw APNs device token without Firebase in between.\n\n### 7a. Canonical register helper\n\n```ts\n// src/push/registerPushToken.ts\nimport { Platform } from \"react-native\";\nimport { CometChatNotifications } from \"@cometchat/chat-sdk-react-native\";\nimport { PUSH_PROVIDERS } from \"../config/push\";\n\nexport async function registerPushToken(token: string): Promise<void> {\n  const platform =\n    Platform.OS === \"android\"\n      ? CometChatNotifications.PushPlatforms.FCM_REACT_NATIVE_ANDROID\n      : CometChatNotifications.PushPlatforms.FCM_REACT_NATIVE_IOS;\n\n  // Single FCM provider covers both platforms when using firebase/messaging.\n  const providerId = PUSH_PROVIDERS.fcm;\n\n  try {\n    await CometChatNotifications.registerPushToken(token, platform, providerId);\n  } catch (err) {\n    console.error(\"[push] registerPushToken failed\", err);\n  }\n}\n```\n\n### 7b. Fetch the FCM token and register (after login)\n\n```ts\n// src/push/bootstrap.ts\nimport messaging from \"@react-native-firebase/messaging\";\nimport { registerPushToken } from \"./registerPushToken\";\n\nexport async function bootstrapPushAfterLogin(): Promise<void> {\n  await messaging().registerDeviceForRemoteMessages();\n  const token = await messaging().getToken();\n  await registerPushToken(token);\n\n  // Re-register when the token rotates (rare but it happens — new install, app restore).\n  messaging().onTokenRefresh(async (newToken) => {\n    await registerPushToken(newToken);\n  });\n}\n```\n\nCall `bootstrapPushAfterLogin()` in the same effect that runs `CometChatUIKit.login()`. Order matters — the SDK needs a logged-in user to associate the token with.\n\n### 7c. Unregister on logout\n\n```ts\nimport { CometChatNotifications } from \"@cometchat/chat-sdk-react-native\";\n\nexport async function unregisterPushTokenOnLogout(): Promise<void> {\n  try {\n    await CometChatNotifications.unregisterPushToken();\n  } catch (err) {\n    console.error(\"[push] unregisterPushToken failed\", err);\n  }\n}\n```\n\nCall this BEFORE `CometChatUIKit.logout()` — after logout the SDK can't resolve the user to unregister the token against.\n\nIf the user switches accounts without logging out (bad pattern, but it happens), re-register with the new user after login. CometChat auto-scopes push to the current user.\n\n---\n\n## 8. Permissions — ask early, handle deny gracefully\n\n### iOS\n\niOS prompts the user on the first call to `messaging().requestPermission()`. Do it early in the onboarding flow (post-login is fine), not in the first render — a permission prompt on app open looks hostile.\n\n```ts\nimport messaging from \"@react-native-firebase/messaging\";\n\nasync function requestIosPush(): Promise<boolean> {\n  const status = await messaging().requestPermission();\n  return (\n    status === messaging.AuthorizationStatus.AUTHORIZED ||\n    status === messaging.AuthorizationStatus.PROVISIONAL\n  );\n}\n```\n\n### Android\n\nAndroid 13+ requires the `POST_NOTIFICATIONS` runtime permission (prior versions grant it automatically from the manifest).\n\n```ts\nimport { PermissionsAndroid, Platform } from \"react-native\";\n\nasync function requestAndroidPush(): Promise<boolean> {\n  if (Platform.OS !== \"android\" || Platform.Version < 33) return true;\n  const status = await PermissionsAndroid.request(\n    PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,\n  );\n  return status === PermissionsAndroid.RESULTS.GRANTED;\n}\n```\n\n### Handle deny\n\nIf the user denies, don't retry — it just shows the system \"open Settings\" prompt. Surface a small UI nudge in chat settings: \"Enable push notifications — so you know when you get a message.\" Link to `Linking.openSettings()`.\n\n---\n\n## 9. Display, background, tap\n\n### 9a. Foreground messages (Android)\n\nFCM on Android delivers data-only pushes while the app is foregrounded — the OS does NOT display them automatically. You have to render a local notification with `@notifee/react-native`:\n\n```ts\nimport messaging from \"@react-native-firebase/messaging\";\nimport notifee, { AndroidImportance } from \"@notifee/react-native\";\n\nmessaging().onMessage(async (remoteMessage) => {\n  const { title, body } = remoteMessage.data ?? {};\n  const channelId = await notifee.createChannel({\n    id: \"chat-messages\",\n    name: \"Chat Messages\",\n    importance: AndroidImportance.HIGH,\n  });\n  await notifee.displayNotification({\n    title: title ?? \"New Message\",\n    body: body ?? \"You received a new message.\",\n    android: { channelId, pressAction: { id: \"default\" } },\n    data: remoteMessage.data, // preserved for tap handling\n  });\n});\n```\n\niOS foregrounding behavior is configured by `messaging().setForegroundNotificationPresentationOptions(...)` — set it once at app startup. Default is \"don't display\" (iOS assumes the app handles it), so you must opt-in to badges/banners/sounds.\n\n### 9b. Background / killed messages\n\nOS-delivered, no code needed. The notification displays as an OS notification. Tap handling: see §9c.\n\n### 9c. Tap to deep-link\n\nThree scenarios to handle:\n\n**iOS — app killed, tap opens the app:**\n```ts\nimport PushNotificationIOS from \"@react-native-community/push-notification-ios\";\n\nasync function checkInitialNotificationIOS(): Promise<void> {\n  const notification = await PushNotificationIOS.getInitialNotification();\n  if (!notification) return;\n  const data = notification.getData();\n  navigateFromPayload(data);\n}\n```\n\n**iOS — app in background, tap foregrounds:**\n```ts\nPushNotificationIOS.addEventListener(\"notification\", (notification) => {\n  const data = notification.getData();\n  if (data.userInteraction === 1) {\n    navigateFromPayload(data);\n  }\n  notification.finish(PushNotificationIOS.FetchResult.NoData);\n});\n```\n\n**Android (via messaging):**\n```ts\nimport messaging from \"@react-native-firebase/messaging\";\n\n// App killed → tap → opens app\nmessaging().getInitialNotification().then((remoteMessage) => {\n  if (remoteMessage?.data) navigateFromPayload(remoteMessage.data);\n});\n\n// App backgrounded → tap → foregrounds\nmessaging().onNotificationOpenedApp((remoteMessage) => {\n  if (remoteMessage?.data) navigateFromPayload(remoteMessage.data);\n});\n\n// Foreground local notification (displayed via notifee in §9a) → tap\nimport notifee, { EventType } from \"@notifee/react-native\";\nnotifee.onForegroundEvent(({ type, detail }) => {\n  if (type === EventType.PRESS) {\n    navigateFromPayload(detail.notification?.data ?? {});\n  }\n});\n```\n\n### 9d. Payload → navigation\n\nCometChat's push payload schema (confirmed from `examples/SampleAppWithPushNotifications/src/utils/helper.ts`):\n\n```ts\n{\n  type: \"chat\",\n  receiverType: \"user\" | \"group\",\n  sender: \"<uid>\",\n  receiver: \"<uid-or-guid>\",\n  conversationId: \"<compound-id>\",\n  unreadMessageCount: \"<number-as-string>\",\n  title: \"Alice\",\n  body: \"Hey, you around?\",\n  senderAvatar: \"<url>\",\n  tag: \"<messageId>\",\n  message: \"<JSON-stringified-full-message>\",   // parse for parentId, id, etc.\n}\n```\n\nParse it into navigation params:\n\n```ts\nimport { CometChat } from \"@cometchat/chat-sdk-react-native\";\nimport { navigate } from \"./NavigationService\";   // createNavigationContainerRef wrapper\n\nasync function navigateFromPayload(data: Record<string, unknown>): Promise<void> {\n  if (data.type !== \"chat\") return;\n\n  let parentMessageId: string | undefined;\n  if (typeof data.message === \"string\") {\n    try {\n      parentMessageId = JSON.parse(data.message).parentId;\n    } catch {}\n  }\n\n  if (data.receiverType === \"group\" && typeof data.receiver === \"string\") {\n    const group = await CometChat.getGroup(data.receiver);\n    navigate(\"Messages\", { group, ...(parentMessageId ? { parentMessageId } : {}) });\n  } else if (data.receiverType === \"user\" && typeof data.sender === \"string\") {\n    const user = await CometChat.getUser(data.sender);\n    navigate(\"Messages\", { user, ...(parentMessageId ? { parentMessageId } : {}) });\n  }\n}\n```\n\nUse React Navigation's `createNavigationContainerRef` so you can navigate from outside React (the tap handler fires before the component tree mounts on app launch):\n\n```ts\n// src/navigation/NavigationService.ts\nimport { createNavigationContainerRef } from \"@react-navigation/native\";\n\nexport const navigationRef = createNavigationContainerRef();\n\nexport function navigate(name: string, params?: unknown): void {\n  if (navigationRef.isReady()) navigationRef.navigate(name as never, params as never);\n  else setTimeout(() => navigate(name, params), 100);   // wait for mount\n}\n```\n\nIn the root layout:\n```tsx\n<NavigationContainer ref={navigationRef}>…</NavigationContainer>\n```\n\nFor Expo Router, use the `router` from `expo-router` inside the tap handler — no navigation ref needed, but check `router.canGoBack()` before pushing on cold start.\n\n---\n\n## 10. Badge count\n\nCometChat sends `unreadMessageCount` in the payload. Set it on iOS via `PushNotificationIOS.setApplicationIconBadgeNumber(count)` inside the notification handler. On Android, Notifee's `setBadgeCount()` works on most launchers but is inconsistent (Samsung, Xiaomi have their own rules).\n\nReset badge to 0 when the user opens a conversation:\n```ts\nimport { AppState, Platform } from \"react-native\";\nimport PushNotificationIOS from \"@react-native-community/push-notification-ios\";\nimport notifee from \"@notifee/react-native\";\n\nfunction clearBadge(): void {\n  if (Platform.OS === \"ios\") PushNotificationIOS.setApplicationIconBadgeNumber(0);\n  else notifee.setBadgeCount(0);\n}\n```\n\n---\n\n## 11. Testing the push pipeline\n\nEnd-to-end verification — run each step in order and stop at the first failure. Silent failures are the norm, so testing each layer separately is faster than chasing a black box.\n\n1. **APNs alone** (iOS): In Firebase Console → Cloud Messaging → Send test message to your FCM token. If this arrives, Firebase + APNs are fine.\n2. **FCM alone** (Android): Same as above — Firebase test message. If it arrives, FCM + `google-services.json` are fine.\n3. **CometChat provider → device**: Send a message to the logged-in user from another user. If this fails but step 1/2 worked, the issue is in the CometChat dashboard provider config (wrong p8 environment, wrong bundle ID, expired service account).\n4. **Tap deep-links correctly**: Put the app in background, send a message, tap the notification. App should land on the right conversation.\n5. **TestFlight / App Store**: Build an archive, upload to TestFlight, install on a real device (NOT the simulator — iOS simulator cannot receive real APNs). Repeat step 3. This is where the \"production APNs provider not uploaded\" trap appears.\n\n---\n\n## 12. Troubleshooting — common silent failures\n\n| Symptom | Likely cause | Fix |\n|---|---|---|\n| Dev works, TestFlight doesn't | Production APNs provider not uploaded OR `aps-environment` is still `development` in release build | Upload prod p8 provider (§5a). Check `ios/<Name>/<Name>.entitlements` has `aps-environment: production` for Release config |\n| No iOS simulator notifications | Simulator can't receive real APNs | Use a real device |\n| `requestPermission()` never prompts | Already denied — prompt won't re-show | `Linking.openSettings()` and tell user to toggle Notifications on |\n| Token prints but no push arrives | Token registered BEFORE login | Call `registerPushToken` AFTER `CometChatUIKit.login` resolves |\n| Android foreground: OS notif shows | FCM delivered as notification + data (CometChat sends data-only now); old app code | Update to firebase/messaging ≥18 — old versions force auto-display |\n| Android foreground: nothing shows | No `onMessage` handler OR no notifee channel created | Add `messaging().onMessage` + `notifee.createChannel` (§9a) |\n| \"Default FirebaseApp is not initialized\" | google-services.json missing or build plugin not applied | Re-check §4b. Clean build: `cd android && ./gradlew clean` |\n| Notification tap doesn't navigate | NavigationContainer not ready when tap handler fires | Use the `setTimeout` retry pattern in `navigate()` (§9d) |\n| Expo app receives nothing in Expo Go | Expo Go can't receive push | Build a dev client (§2) |\n| Token refreshes but CometChat still uses old | `onTokenRefresh` listener not wired | Wire in `bootstrapPushAfterLogin` (§7b) |\n| Works for User A but not User B after logout | `unregisterPushToken` not called on logout | Call BEFORE `logout()` (§7c) |\n| iOS push arrives but `data` is empty | Payload is APS-only (no `content-available`) — CometChat default is correct; check if custom template stripped data | Check dashboard → Notifications → Template |\n\n---\n\n## 13. Hard rules\n\n- **Register AFTER login.** The SDK needs a logged-in user to scope the token. Register before login and the token lands against \"anonymous.\"\n- **Unregister BEFORE logout.** The SDK needs to know the user to dissociate the token.\n- **Call `onTokenRefresh`.** FCM rotates tokens. Missing the rotation means push stops working after a few weeks for some users.\n- **Upload both APNs environments.** Dev + Production. Missing Production = silent TestFlight/App Store breakage.\n- **Expo Go is a dead-end.** Build a dev client for push. No exceptions.\n- **Don't auto-display on Android foreground.** Show a local notification via Notifee so the user sees the message.\n- **Don't ship without testing on a real device.** iOS simulator doesn't receive real APNs.\n\n---\n\n## 14. Skill routing\n\n| This skill | Covers |\n|---|---|\n| `cometchat-native-push` (this) | APNs + FCM + CometChat dashboard + client registration + tap handling |\n| `cometchat-native-core` | Init, login, four-wrapper chain, login concurrency guard |\n| `cometchat-native-features` | Calling SDK (`@cometchat/calls-sdk-react-native`) — push for VoIP is a separate channel (use `APNS_REACT_NATIVE_VOIP` + `react-native-voip-push-notification`) |\n| `cometchat-native-production` | Server-minted auth tokens + user CRUD. Register push only after login; if using auth tokens, register after `login({ authToken })` |\n| `cometchat-native-bare-patterns` | `pod install` + Xcode capability steps |\n| `cometchat-native-expo-patterns` | `expo prebuild` + dev client setup |\n| `cometchat-native-troubleshooting` | Metro cache, Podfile.lock, Android Maven. Push-specific symptoms are in §12 here |","tags":["cometchat","native","push","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-native-push","topic-agent-skills","topic-ai-agent","topic-chat","topic-claude-code","topic-cometchat","topic-cursor","topic-messaging","topic-nextjs","topic-react","topic-react-native","topic-ui-kit"],"categories":["cometchat-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cometchat/cometchat-skills/cometchat-native-push","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cometchat/cometchat-skills","source_repo":"https://github.com/cometchat/cometchat-skills","install_from":"skills.sh"}},"qualityScore":"0.463","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 27 github stars · SKILL.md body (24,093 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:04:54.833Z","embedding":null,"createdAt":"2026-05-07T13:05:15.192Z","updatedAt":"2026-05-18T19:04:54.833Z","lastSeenAt":"2026-05-18T19:04:54.833Z","tsv":"'-3':1069 '/account':443 '/app':839,1124,1145,1214 '/config/push':1389 '/docs/notifications/push-integration':142 '/google-services.json':833 '/googleservice-info.plist':937 '/gradlew':2642 '/info.plist':1252 '/messaging':844,858,1129,1155,1219,1452,1644,1788,1966 '/native':2158 '/navigationservice':2064 '/push-notification-ios':1135,1191,1225,1918,2286 '/registerpushtoken':1456 '0':2264,2298,2301 '1':143,187,279,440,582,718,765,893,1950,2340 '1/2':2401 '10':482,499,587,2223 '100':2185 '11':2302 '12':2483,2985 '13':1661,2746 '14':2869 '18':2598 '2':193,269,448,727,771,905,1068,1239,2363,2681 '3':206,397,462,735,781,871,908,2380,2471 '33':1692 '3a':401,635,974 '3b':528 '3c':588 '4':222,477,707,784,921,2421 '4.4.2':814 '4a':711,1054 '4b':757,2637 '4c':845 '5':236,490,527,789,938,2445 '5.3.3':137 '5a':949,2516 '5b':1033 '5c':1060 '6':505,803,1110 '7':706,993,1099,1279 '7a':1369 '7b':1434,2696 '7c':1519,2715 '8':1592 '9':1743 '9a':1747,2000,2621 '9b':1872 '9c':1892,1893 '9d':2016,2663 'accept':435 'account':717,733,1050,1565,2420 'actual':874 'ad':622 'ad-hoc':621 'add':47,720,758,768,790,894,902,909,919,950,956,1034,1038,2617 'addeventlisten':1201 'agre':154 'alic':2038 'almost':254 'alon':2342,2365 'alphanumer':484,501 'alreadi':2545 'alway':255 'android':215,335,346,710,759,770,831,1158,1174,1259,1273,1303,1308,1400,1404,1659,1660,1690,1750,1753,1828,1955,2244,2366,2576,2605,2641,2839,2977 'android/app/build.gradle':779,797 'android/app/google-services.json':788 'android/app/src/main/androidmanifest.xml':1262 'android/build.gradle':805 'androidimport':1791 'androidimportance.high':1814 'anonym':2772 'anoth':2394 'answer':391 'ap':569,603,615,2504,2522,2726 'api':1288 'apk':351 'apn':11,35,211,300,398,404,453,459,596,671,860,868,952,959,963,1000,1091,1095,1160,1193,1313,1319,1324,1329,1333,1348,1352,1362,2341,2360,2468,2477,2498,2537,2808,2868,2880,2916 'apns-dev':962,1090 'apns-environ':34 'apns-prod':999,1094 'apns/fcm':163 'apnsdev':1089 'apnsprod':1093 'app':94,114,167,231,240,291,310,432,508,593,619,760,769,774,896,903,945,1025,1080,1338,1486,1632,1761,1851,1861,1904,1909,1936,1967,1971,1981,2148,2429,2438,2447,2593,2665 'app.cometchat.com':943 'app.json':828,932,1270 'appear':2482 'appl':61,155,408,455,470 'appli':799,2633 'applicationid':780 'appstat':2273 'aps-environ':568,602,614,2503,2521 'aps-on':2725 'archiv':2451 'around':2042 'arriv':100,381,668,2358,2375,2566,2718 'ask':1594 'associ':1515 'assum':1859 'async':1391,1458,1490,1529,1645,1684,1796,1919,2067 'auth':405,418,630,2933,2944 'authtoken':2949 'auto':1185,1585,2603,2836 'auto-display':1184,2602,2835 'auto-scop':1584 'automat':1672,1770 'avail':2731 'await':1422,1462,1467,1470,1492,1534,1651,1697,1804,1815,1925,2101,2118 'b':186,196,223,2704 'background':23,93,550,553,1745,1873,1938,1982,2431 'bad':1569 'badg':2224,2262 'badges/banners/sounds':1871 'bare':1114,2953 'base':1106 'bash':321,1117,1206 'basic':1257 'behavior':1841 'black':2338 'bodi':1800,1821,1822,2039 'bootstrappushafterlogin':1460,1496,2695 'box':2339 'break':40 'breakag':2817 'broken':251 'build':320,340,608,663,1027,1205,1235,2449,2511,2630,2639,2677,2825 'buildscript.dependencies':807 'bundl':510,980,1010,2416 'cach':1061,2975 'call':565,1331,1495,1543,1607,2571,2709,2712,2787,2905 'came':649 'cannot':272,2465 'canon':1287,1370 'capabl':532,542,545,549,2958 'catch':1427,1536,2092 'caus':2490 'cd':1136,1140,2640 'certif':415,444 'chain':2897 'chang':1254 'channel':2615,2914 'channelid':1803,1829 'char':483,500 'chase':2336 'chat':89,118,1727,1808,1811,2029,2077 'chat-messag':1807 'check':266,454,555,2216,2517,2636,2736,2742 'checkinitialnotificationio':1921 'choos':958,1040 'classpath':809 'claud':44 'clean':332,1233,2638,2643 'clearbadg':2292 'click':544,548,917 'client':17,71,162,201,328,359,1112,1229,1238,1247,2680,2828,2884,2968 'cloud':64,2347 'code':393,1880,2594 'cold':2221 'collect':506 'com.google.gms':810 'com.google.gms.google':801 'cometchat':2,10,52,67,156,157,188,434,452,524,564,641,687,753,939,1285,1583,2019,2058,2226,2381,2408,2586,2685,2732,2876,2882,2889,2902,2927,2951,2961,2971 'cometchat-native-bare-pattern':2950 'cometchat-native-cor':2888 'cometchat-native-expo-pattern':2960 'cometchat-native-featur':2901 'cometchat-native-product':2926 'cometchat-native-push':1,2875 'cometchat-native-troubleshoot':2970 'cometchat.getgroup':2102 'cometchat.getuser':2119 'cometchat/calls-sdk-react-native':2907 'cometchat/chat-sdk-react-native':1296,1384,1527,2060 'cometchat/chat-uikit-react-native':136 'cometchatnotif':1294,1382,1525 'cometchatnotifications.pushplatforms':1297 'cometchatnotifications.pushplatforms.fcm':1401,1405 'cometchatnotifications.registerpushtoken':1423 'cometchatnotifications.unregisterpushtoken':1535 'cometchatuikit.login':1503,2574 'cometchatuikit.logout':1546 'common':2485 'communiti':1134,1190,1224,1917,2285 'compon':2144 'concurr':2899 'config':848,1076,2411,2527 'configur':16,70,304,338,1843 'confirm':1289,2024 'consol':899,2346 'console.error':1429,1538 'console.firebase.google.com':719 'const':1084,1397,1418,1465,1649,1695,1798,1802,1923,1930,1945,2099,2116,2160 'constant':1077 'content':2730 'content-avail':2729 'continu':460,724 'convers':244,2270,2444 'conversationid':2035 'copi':478,495,983,1013,1056 'core':2891 'correct':2426,2735 'count':2225,2238 'cover':1412,2874 'creat':402,712,2616 'createnavigationcontainerref':2065,2130,2153,2162 'cred':172 'credenti':218,678,747,942 'crud':2936 'current':1590 'custom':294,2738 'danc':1349 'dashboard':14,68,160,220,525,661,674,688,755,940,2409,2743,2883 'data':1179,1756,1833,1931,1934,1946,1952,1978,1990,2015,2070,2585,2589,2720,2741 'data-on':1178,1755,2588 'data.message':2085,2090 'data.receiver':2097,2103 'data.receivertype':2094,2111 'data.sender':2114,2120 'data.type':2076 'data.userinteraction':1949 'dead':2823 'dead-end':2822 'debug':264 'deep':28,80,1897,2424 'deep-link':1896,2423 'default':1046,1832,1853,2622,2733 'deliv':1754,1878,2582 'demo':127 'deni':1597,1705,1709,2546 'detail':2009 'detail.notification':2014 'dev':327,358,607,610,964,1092,1109,1204,1228,1237,1246,2492,2679,2810,2827,2967 'dev-client':357,1245 'develop':62,319,342,571,601,605,658,691,968,2508 'developer.apple.com':442 'developer.apple.com/account':441 'devic':225,1194,1327,1355,1363,2383,2459,2541,2861 'direct':1320 'display':22,176,238,1169,1186,1744,1768,1857,1884,1996,2604,2837 'dissoci':2784 'docs/sdk/react-native/push-notification-setup.mdx':138 'doesn':103,108,886,2495,2646,2864 'download':463,474,740,763,782,906 'e.g':451 'ea':339 'earli':1595,1613 'effect':1500 'els':2109,2180,2299 'empti':2722 'enabl':529,1729 'end':57,59,795,2308,2310,2824 'end-to-end':56,2307 'enter':772 'entitl':301,576,2519 'enum':1298,1301 'environ':36,570,579,590,604,616,639,646,955,967,1002,2414,2505,2523,2809 'err':1428,1433,1537,1542 'error':260 'etc':2050 'even':883 'eventtyp':2004 'eventtype.press':2012 'everyth':376 'examples/sampleappwithpushnotifications':134 'examples/sampleappwithpushnotifications/src/utils/helper.ts':2026 'examples/sampleappwithpushnotifications/src/utils/pushnotification.tsx':1291 'except':2832 'expect':880 'expir':425,2418 'expo':32,270,283,285,315,323,326,330,355,364,386,815,830,923,934,1202,1208,1227,1231,1243,1265,1272,2198,2205,2664,2669,2671,2818,2963,2965 'expo-dev-cli':325,1226 'expo-rout':2204 'export':1083,1390,1457,1528,2159,2163 'fail':665,1432,1541,2398 'failur':585,2322,2324,2487 'faster':2334 'fcm':12,214,303,708,892,1036,1041,1045,1087,1088,1156,1177,1304,1305,1310,1314,1340,1410,1437,1751,2354,2364,2376,2581,2789,2881 'fcm-default':1044 'featur':122,2904 'fetch':1435 'file':466,577,743,750,920,972,1052 'fine':1622,2362,2379 'fire':233,2141,2655 'firebas':714,762,838,843,847,857,879,898,1123,1128,1144,1147,1154,1163,1213,1218,1311,1345,1366,1451,1643,1787,1965,2345,2359,2370 'firebase/messaging':851,1417,2597 'firebaseapp':2623 'first':1606,1626,2321 'five':246 'fix':394,679,2491 'flow':1617 'forc':2601 'foreground':21,234,1171,1748,1763,1840,1940,1984,1993,2577,2606,2840 'foreground/background':74 'format':439 'four':149,521,2895 'four-wrapp':2894 'function':1392,1459,1530,1646,1685,1920,2068,2164,2291 'gear':730 'general':516 'generat':333,633,736 'get':1737 'getinitialnotif':1200,1973 'gettoken':1469 'go':33,271,286,387,2670,2672,2819 'goe':818 'googl':63,159,812 'google-servic':811 'google-services.json':764,783,817,1150,2377,2627 'googleservice-info.plist':882,907,1149 'googleservicesfil':832,936 'grace':1598 'gradl':798,808 'grant':1670 'ground':132 'group':2032,2095,2100,2106 'guard':2900 'handl':75,1164,1199,1346,1596,1704,1838,1862,1890,1902,2887 'handler':235,2140,2210,2242,2611,2654 'happen':1483,1573 'hard':2747 'help':396 'helper':1372 'hey':2040 'hoc':623 'hold':221 'hood':863 'hostil':1635 'icon':731 'id':481,498,511,703,977,979,981,986,1007,1009,1011,1017,1059,1064,1071,1806,1831,2049,2417 'identifi':445 'import':1293,1375,1381,1385,1445,1453,1524,1637,1677,1781,1789,1813,1911,1959,2002,2057,2061,2152,2272,2279,2287 'inconsist':2254 'init':2892 'initi':1146,2626 'insid':2207,2239 'instal':324,1111,1119,1139,1209,1485,2455,2956 'integr':55,563 'io':212,334,344,400,513,536,846,853,865,876,889,895,904,912,935,1137,1162,1192,1248,1251,1309,1317,1318,1328,1408,1599,1600,1839,1858,1903,1935,2235,2296,2343,2463,2518,2529,2716,2862 'ip':560 'ipa':350 'issu':2404 'json':170,742,749,829,933,1051,1271 'json.parse':2089 'key':169,406,419,427,438,447,480,488,611,626,631,739,976,1006 'kill':1874,1905,1968 'know':644,1734,2780 'land':2440,2770 'launch':2149 'launcher':2251 'layer':268,2331 'layout':2192 'let':472,2079 'lifecycl':20 'like':2489 'line':792 'link':29,81,1740,1898,2425 'linking.opensettings':1742,2553 'listen':2690 'll':518,989,1066,1101 'local':1167,1776,1994,2843 'lock':1278 'log':258,1511,1567,2390,2757 'logged-in':1510,2389,2756 'login':205,1442,1582,1620,2570,2751,2766,2893,2898,2941,2948 'logout':1522,1548,2706,2711,2714,2775 'look':194,1634 'manag':816,1203,1266 'manifest':1675 'match':677,701 'matter':1505 'maven':2978 'mean':2795 'membership':493 'messag':99,107,175,183,192,1172,1446,1463,1468,1488,1609,1638,1652,1739,1749,1782,1794,1809,1812,1820,1827,1845,1875,1957,1960,1972,1985,2045,2105,2122,2348,2351,2372,2386,2434,2618,2852 'messaging.authorizationstatus.authorized':1656 'messaging.authorizationstatus.provisional':1658 'metro':2974 'mint':2932 'miss':2628,2792,2812 'mode':551,554 'modul':296 'mount':2146,2188 'move':145 'must':152,248,1866 'name':449,722,777,961,998,1043,1810,2166,2174,2183 'nativ':3,9,54,295,337,837,842,856,1116,1122,1127,1133,1143,1153,1189,1212,1217,1223,1307,1316,1326,1335,1354,1380,1403,1407,1450,1642,1683,1786,1916,1964,2278,2284,2877,2890,2903,2918,2922,2928,2952,2962,2972 'navig':241,2018,2054,2062,2104,2121,2128,2134,2157,2165,2182,2212,2648,2662 'navigatefrompayload':1933,1951,1979,1991,2013,2069 'navigationcontain':2194,2649 'navigationref':2161,2196 'navigationref.isready':2172 'navigationref.navigate':2173 'need':756,990,1255,1508,1881,2214,2754,2778 'negoti':86 'network':600 'never':95,424,471,2176,2179,2543 'new':737,1484,1579,1819,1826 'newtoken':1491,1494 'non':85,1322 'non-negoti':84 'non-voip':1321 'norm':2327 'noth':2607,2667 'notif':6,49,177,237,263,275,380,457,531,547,557,946,948,1168,1197,1276,1665,1700,1731,1777,1883,1888,1924,1928,1943,1944,1995,2241,2437,2531,2559,2579,2584,2644,2744,2844,2925 'notife':1790,1998,2003,2245,2288,2614,2846 'notifee.createchannel':1805,2620 'notifee.displaynotification':1816 'notifee.onforegroundevent':2007 'notifee.setbadgecount':2300 'notifee/react-native':1130,1166,1220,1779,1793,2006,2290 'notification.finish':1953 'notification.getdata':1932,1947 'npm':1118 'npx':322,329,354,1207,1230,1242 'nudg':1725 'old':2592,2599,2688 'onboard':1616 'one':426,468,1105 'one-tim':467 'onmessag':1795,2610,2619 'onnotificationopenedapp':1986 'ontokenrefresh':1489,2689,2788 'open':112,347,535,1633,1718,1907,1970,2268 'opt':1868 'opt-in':1867 'option':411 'order':1504,2316 'os':228,1765,1877,1887,2578 'os-deliv':1876 'outsid':2136 'overview':767,901 'p12':416 'p8':168,407,420,422,465,629,655,683,971,1005,2413,2514 'packag':776,1113 'page':489,494 'parallel':599 'param':2055,2168,2177,2184 'parentid':2048,2091 'parentmessageid':2080,2088,2107,2108,2124,2125 'pars':2046,2051 'past':519,975 'path':612,627 'pattern':1570,2660,2954,2964 'payload':2017,2022,2231,2723 'per':954 'permiss':1249,1260,1268,1274,1593,1629,1667 'permissionsandroid':1678 'permissionsandroid.permissions.post':1699 'permissionsandroid.request':1698 'permissionsandroid.results.granted':1703 'pick':1102 'piec':146 'pipelin':2306 'place':785 'platform':343,1108,1300,1343,1376,1398,1414,1425,1679,2274 'platform.os':1399,1689,2295 'platform.version':1691 'plugin':800,834,2631 'pod':1138,2955 'podfile.lock':2976 'post':1275,1619,1664 'post-login':1618 'power':875 'prebuild':331,1232,2966 'prebuilt':289 'preserv':1835 'pressact':1830 'print':2562 'prior':1668 'privat':738 'prod':625,1001,1096,2513 'product':41,88,131,573,613,617,670,695,996,1003,1022,2476,2497,2524,2811,2813,2929 'profil':341,446 'project':316,540,715,721,728,766,821,900,918,927 'promis':1396,1461,1532,1648,1687,1922,2074 'prompt':1601,1630,1720,2544,2547 'provid':15,69,164,692,696,702,953,957,960,985,997,1016,1023,1037,1039,1042,1058,1063,1070,1086,1387,1411,2382,2410,2478,2499,2515 'providerid':1419,1426 'proxi':1312 'purpos':42 'push':4,5,48,82,147,199,209,274,312,314,369,414,456,530,546,877,890,947,1032,1085,1181,1258,1282,1386,1430,1539,1587,1730,1758,2021,2219,2305,2565,2676,2717,2796,2830,2878,2908,2924,2938,2980 'push-specif':2979 'push_providers.fcm':1420 'pushnotificationio':1912,2280 'pushnotificationios.addeventlistener':1942 'pushnotificationios.fetchresult.nodata':1954 'pushnotificationios.getinitialnotification':1926 'pushnotificationios.setapplicationiconbadgenumber':2237,2297 'put':924,1267,2427 'rare':1480 'raw':1361 're':111,384,1358,1474,1575,2551,2635 're-check':2634 're-open':110 're-regist':1473,1574 're-show':2550 'react':8,53,836,841,855,1115,1121,1126,1132,1142,1152,1188,1211,1216,1222,1306,1315,1325,1334,1353,1379,1402,1406,1449,1641,1682,1785,1915,1963,2127,2137,2156,2277,2283,2917,2921 'react-nat':1378,1681,2276 'react-native-commun':1131,1187,1221,1914,2282 'react-native-firebas':835,840,854,1120,1125,1141,1151,1210,1215,1448,1640,1784,1962 'react-native-voip-push-notif':2920 'react-navig':2155 'read':1148 'readi':2651 'real':2458,2467,2536,2540,2860,2867 'receiv':190,226,273,308,368,1031,1824,2034,2466,2535,2666,2675,2866 'receivertyp':2030 'record':2071 'ref':2195,2213 'refer':825,930 'refresh':2683 'regist':198,461,698,1280,1359,1371,1440,1475,1576,2568,2749,2764,2937,2946 'registerdeviceforremotemessag':1464 'registerpushtoken':1393,1431,1454,1471,1493,2572 'registr':18,73,2885 'releas':2510,2526 'remot':556 'remotemessag':1797,1975,1977,1987,1989 'remotemessage.data':1801,1834,1980,1992 'render':1627,1774 'repeat':994,2469 'report':373 'requestandroidpush':1686 'requestiospush':1647 'requestpermiss':1610,1653,2542 'requir':265,317,1175,1662 'reset':2261 'resolv':1553,2575 'restor':1487 'result':349 'retri':1712,2659 'retriev':1196 'return':1654,1693,1701,1929,2078 'right':504,916,1104,2443 'right-click':915 'rn':158 'root':822,928,2191 'rotat':1479,2790,2794 'rout':888,2871 'router':2199,2202,2206 'router.cangoback':2217 'rule':2260,2748 'run':353,385,1241,1502,2312 'runtim':705,1098,1666 'samsung':2255 'save':982,1012,1055 'scenario':1900 'schema':2023 'scope':1586,2761 'sdk':166,1507,1550,2753,2777,2906 'second':1015 'see':105,1891,2850 'select':538 'send':181,207,2227,2349,2384,2432,2587 'sender':2033 'senderavatar':2043 'separ':124,2332,2913 'server':161,189,746,2931 'server-mint':2930 'servic':458,716,732,802,813,1049,2419 'set':375,729,1719,1728,1847,2232 'setbadgecount':2247 'setforegroundnotificationpresentationopt':1846 'settimeout':2181,2658 'setup':13,65,365,399,709,726,869,2969 'shell':290 'ship':2855 'show':1715,2552,2580,2608,2841 'shown':485 'sign':413,541 'silent':39,256,584,664,1029,2323,2486,2814 'silent-failur':583 'similar':966 'simpler':437,1344 'simul':2462,2464,2530,2532,2863 'singl':1409 'skill':2870,2873 'skill-cometchat-native-push' 'skip':1020 'small':1723 'source-cometchat' 'span':148 'specif':2981 'src/config/push.ts':1082 'src/navigation/navigationservice.ts':2151 'src/push/bootstrap.ts':1444 'src/push/registerpushtoken.ts':1374 'start':356,1244,2222 'startup':1852 'status':1650,1655,1657,1696,1702 'step':247,252,2314,2400,2470,2959 'still':2507,2686 'stop':116,2318,2797 'store':594,620,1026,1072,2448,2816 'string':987,1395,2072,2081,2086,2098,2115,2167 'strip':2740 'support':280 'surfac':1721 'switch':1564 'symptom':2488,2982 'system':150,1717 'tab':543,734 'tag':2044 'tap':26,78,239,1198,1746,1837,1889,1894,1906,1939,1969,1983,2001,2139,2209,2422,2435,2645,2653,2886 'tap-to-deep-link':25,77 'target':515 'teach':43 'team':497,978,1008 'tell':2555 'templat':2739,2745 'test':2303,2329,2350,2371,2857 'testflight':592,618,662,1024,2446,2454,2494 'testflight/app':2815 'though':884 'three':1899 'ticket':281 'time':469 'titl':1799,1817,1818,2037 'toggl':2558 'token':19,72,200,648,667,1195,1283,1364,1394,1424,1438,1466,1472,1478,1517,1559,2355,2561,2567,2682,2763,2769,2786,2791,2934,2945 'top':503 'top-right':502 'topic-agent-skills' 'topic-ai-agent' 'topic-chat' 'topic-claude-code' 'topic-cometchat' 'topic-cursor' 'topic-messaging' 'topic-nextjs' 'topic-react' 'topic-react-native' 'topic-ui-kit' 'trap':37,595,2481 'tree':2145 'tri':1421,1533,2087 'troubleshoot':2484,2973 'true':1694 'truth':133 'ts':1081,1292,1373,1443,1523,1636,1676,1780,1910,1941,1958,2027,2056,2150,2271 'tsx':2193 'twice':684 'two':410,589,598 'type':2008,2011,2028 'typeof':2084,2096,2113 'ui':1724 'undefin':2082 'unknown':2073,2169 'unreadmessagecount':2036,2228 'unregist':1520,1557,2773 'unregisterpushtoken':1540,2707 'unregisterpushtokenonlogout':1531 'updat':2595 'upload':171,653,680,941,969,1047,2452,2480,2501,2512,2806 'use':117,216,421,609,624,850,1339,1351,1416,2126,2200,2538,2656,2687,2915,2943 'user':102,179,185,284,372,1513,1555,1563,1580,1591,1603,1708,2031,2112,2117,2123,2267,2392,2395,2556,2699,2703,2759,2782,2805,2849,2935 'valu':1299,1302 'verif':2311 'version':1669,2600 'via':165,210,913,1956,1997,2236,2845 'voic':558 'void':2170,2293 'voip':1323,1330,1336,2910,2919,2923 'wait':2186 'wake':24,96,229,1277 'way':306 'webhook':173 'week':2802 'wire':2692,2693 'without':90,292,1365,1566,2856 'won':2548 'work':125,129,249,428,636,2248,2402,2493,2697,2798 'wrap':859 'wrapper':2066,2896 'write':567 'wrong':578,2412,2415 'www.cometchat.com':141 'www.cometchat.com/docs/notifications/push-integration':140 'xcode':534,606,914,2957 'xcodeproj':514 'xcworkspac':537 'xiaomi':2256 'xml':1263","prices":[{"id":"e16ac563-2804-4820-9662-3e5493cf30bf","listingId":"62ca2737-d397-482b-bde9-ef4c9d826d55","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cometchat","category":"cometchat-skills","install_from":"skills.sh"},"createdAt":"2026-05-07T13:05:15.192Z"}],"sources":[{"listingId":"62ca2737-d397-482b-bde9-ef4c9d826d55","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-native-push","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-native-push","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:15.192Z","lastSeenAt":"2026-05-18T19:04:54.833Z"}],"details":{"listingId":"62ca2737-d397-482b-bde9-ef4c9d826d55","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-native-push","github":{"repo":"cometchat/cometchat-skills","stars":27,"topics":["agent-skills","ai-agent","chat","claude-code","cometchat","cursor","messaging","nextjs","react","react-native","ui-kit"],"license":null,"html_url":"https://github.com/cometchat/cometchat-skills","pushed_at":"2026-05-18T05:04:24Z","description":"Add CometChat chat to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.","skill_md_sha":"f0cd77363161bd957c1e16c70cc4dce22013372e","skill_md_path":"skills/cometchat-native-push/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-native-push"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-native-push","license":"MIT","description":"Push notifications for React Native CometChat — APNs + FCM setup, dashboard provider configuration, client registration, token lifecycle, foreground display, background wake, tap-to-deep-link, and the Expo Go / APNs-environment traps that silently break production.","compatibility":"Node.js >=18; React Native >=0.70; @cometchat/chat-uikit-react-native ^5; @cometchat/chat-sdk-react-native ^4; @react-native-firebase/messaging ^18"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-native-push"},"updatedAt":"2026-05-18T19:04:54.833Z"}}