@channels-social/react-native
Embed your Channels.social community as a native-feeling screen in your React Native app — one component, passthrough auth (no login screen), and push notifications for mentions, DMs, and "Talk to us" replies.
Phase 1 wraps the battle-tested web embed in a
WebViewand adds the two things a WebView can't do on its own: native auth via props and native push. Fully-native chat screens are a later phase.
Requires a Channels account
This is a client SDK for Channels.social — it embeds your community, so it needs a Channels account (a paid product) and your API key. Sign up at https://channels.social, then copy your key from Admin → Integration. The SDK does nothing without a valid key.
Install
npm install @channels-social/react-native react-native-webview
# Push notifications (recommended — see setup below):
npm install @react-native-firebase/app @react-native-firebase/messaging
react-native-webview is required. The two Firebase packages are optional — without them the community still works, push is just disabled (with a console warning).
iOS:
cd ios && pod install
Peer dependencies
| Package | Required | Purpose |
|---|---|---|
react, react-native |
runtime | |
react-native-webview |
renders the community | |
@react-native-firebase/app |
optional | push |
@react-native-firebase/messaging |
optional | push |
Quick start (passthrough auth)
Pass the member your app already knows about. external_id (your own user id) is preferred; email also works.
import React from "react";
import { ChannelsCommunity } from "@channels-social/react-native";
export default function CommunityScreen() {
return (
<ChannelsCommunity
apiKey="YOUR_PUBLIC_EMBED_API_KEY" // Admin → Integration
user={{
external_id: "user_123",
email: "member@acme.com",
name: "Jordan Lee",
image: "https://cdn.acme.com/u/123.png",
}}
// optional:
// channel="general"
// topic="introductions"
// theme="dark"
// enablePush={true}
onEvent={(e) => console.log("channels event", e)}
style={{ flex: 1 }}
/>
);
}
That's it — the member lands signed in, no OTP/Google prompt, because your app vouched for their identity (this is the mobile equivalent of trusted/JWT passthrough on the web).
Requires your business to be on a plan that allows login passthrough, and the embed configured accordingly in the admin panel.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
apiKey |
string |
— | Required. Public embed key (Admin → Integration). |
user |
{ external_id?, email?, name?, image? } |
— | The signed-in member. Provide external_id or email. Omit to let the embed run its own login (OTP/Google). |
channel |
string |
— | Open straight to this channel. |
topic |
string |
— | Open straight to this topic. |
theme |
"light" | "dark" |
admin default | Force a theme. |
host |
string |
https://channels.social |
Override for self-host/staging. |
enablePush |
boolean |
true |
Register the device for push. |
onEvent |
(event) => void |
— | Raw messages forwarded from the embed. |
style |
ViewStyle |
{ flex: 1 } |
Container style. |
Push notifications
1. Firebase setup
Push uses Firebase Cloud Messaging for both platforms (APNs is bridged through FCM).
Android
- Create a Firebase project → add an Android app with your package name.
- Download
google-services.json→android/app/google-services.json. - Add the Google Services Gradle plugin (per
@react-native-firebasedocs).
iOS
- Add an iOS app in the same Firebase project.
- Download
GoogleService-Info.plist→ add it to your Xcode project (target root). - Upload your APNs Auth Key (.p8) to Firebase → Project Settings → Cloud Messaging.
- Enable Push Notifications and Background Modes → Remote notifications capabilities in Xcode.
2. Background handler (required for taps that cold-start the app)
Register a background message handler at your app's entry (index.js), before AppRegistry.registerComponent:
import messaging from "@react-native-firebase/messaging";
messaging().setBackgroundMessageHandler(async () => {
// Data-only handling if you need it; tap navigation is handled by the SDK.
});
3. That's it
When enablePush is on and a user identity is present, ChannelsCommunity will request permission, register the device with the Channels backend, keep the token fresh, and deep-link into the right place when a notification is tapped.
Backend contract (for reference)
The SDK calls (all under ${host}/api):
POST /api/embed/device/register
{ apiKey, external_id?, email?, deviceToken, platform } -> { success }
POST /api/embed/device/unregister
{ apiKey, deviceToken } -> { success }
The backend sends FCM messages whose data payload is:
{ "type": "mention" | "dm" | "brand", "channel": "...", "topic": "...", "roomId": "..." }
On tap, the SDK injects into the embed:
window.postMessage(JSON.stringify({
source: "channels-native", action: "open", channel, topic, roomId
}), "*");
The embed side consuming this
channels-nativemessage to actually switch views is a separate web follow-up. Until it lands, taps open the community but don't deep-jump.
Manual control
You usually don't need these (the component handles them), but they're exported:
import { registerForPush, unregisterPush, onDeepLink } from "@channels-social/react-native";
Auth modes & scope
Phase 1 targets passthrough auth — your app knows who the member is and passes user. That's the app-first happy path and the only mode where we can register the device for push (we need the member's identity to route notifications).
If you omit user, the embed falls back to its own in-WebView login (OTP/Google). That works, but push registration is skipped in that case — wiring push to a member who logs in inside the WebView is a Phase-1.5 item.
License
MIT