RedChurn

React Native SDK

Install the SDK once. Configure billing recovery, cancel saves, and win back from the RedChurn dashboard. Copy, offers, and flow toggles update in your app within 60 seconds without a release.

Install with AI

Click a tool to copy a ready-to-paste integration prompt with your SDK key and code snippets.

Download SDK v0.5.0
Or install from npm: npm install @redchurn/react-native-sdk

Overview

The React Native SDK connects your app to RedChurn through a single API key. It registers your RevenueCat App User ID, syncs remote configuration, and renders native UI for three retention scenarios.

Everything visible to the subscriber (titles, messages, buttons, offers) is edited in the dashboard. The SDK polls for changes and updates automatically. You do not ship a new build to change copy.

  • Cancel Save: intercept cancel taps with a native sheet
  • Billing Recovery: in-app dunning when RevenueCat reports a billing issue
  • Win back: reactivation prompt for churned subscribers
  • Remote config: flows, copy, and offers controlled from the dashboard

Requirements

  • React 18 or later
  • React Native 0.72 or later (Expo dev build / prebuild supported)
  • RevenueCat configured in your app with App User IDs
  • @notifee/react-native (peer) for local billing recovery and win back notifications

1. Install

Add the SDK and the Notifee peer dependency. Notifee powers the local notifications used by billing recovery and win back.

bash
# Expo
npx expo install @redchurn/react-native-sdk @notifee/react-native

# bare React Native
npm install @redchurn/react-native-sdk @notifee/react-native

2. Wrap your app with the provider

Wrap your root once with RedchurnProvider. Get your SDK key from the RedChurn dashboard (Settings, or during onboarding). Pass the RevenueCat App User ID so RedChurn can match subscribers to webhook events. Keep notificationsEnabled to schedule local reminders from your dashboard copy.

tsx
import { RedchurnProvider } from "@redchurn/react-native-sdk";

export default function App() {
  return (
    <RedchurnProvider config={{
      sdkKey: "rdchrn_live_xxxxxxxx",
      rcAppUserId: user.revenueCatAppUserId,
      notificationsEnabled: true,
      // locale: "fr",            // optional — auto-detected from device
      // debug: __DEV__,          // optional — logs [RedChurn SDK] lines
    }}>
      <RootNavigator />
    </RedchurnProvider>
  );
}

3. Register the background handler

Call registerRedchurnBackgroundEventHandler once in index.js, outside React, so notification taps open the right flow when the app is backgrounded. On Android 13+ request the notification permission once after login.

tsx
// index.js — before "expo-router/entry" (or your app entry)
import { registerRedchurnBackgroundEventHandler } from "@redchurn/react-native-sdk";

registerRedchurnBackgroundEventHandler();

import "expo-router/entry";

4. Set the App User ID after login

If the RevenueCat App User ID is not available at app launch, set it after authentication so prompts target the right subscriber:

tsx
import { useEffect } from "react";
import { useRedChurn } from "@redchurn/react-native-sdk";

function AuthBridge({ userId }: { userId: string }) {
  const { setRCAppUserId } = useRedChurn();

  useEffect(() => {
    setRCAppUserId(userId);
  }, [userId, setRCAppUserId]);

  return null;
}

5. Cancel Save

Wrap your cancel button with CancelSaveFlow. interceptCancel() shows the save sheet (survey then your configured offers) and returns false when nothing should be shown, so you fall back to the store cancellation UI. Apply the accepted offer in onOfferAccepted via RevenueCat — throw on failure so RedChurn only counts a save after a successful store/RC operation.

tsx
import { CancelSaveFlow } from "@redchurn/react-native-sdk";

function SubscriptionSettings({ rcAppUserId }: { rcAppUserId: string }) {
  return (
    <CancelSaveFlow
      rcAppUserId={rcAppUserId}
      onOfferAccepted={async (offer) => {
        // Apply via RevenueCat. Throw on failure — save is recorded only on success.
      }}
      render={({ interceptCancel }) => (
        <Button
          title="Cancel subscription"
          onPress={async () => {
            const intercepted = await interceptCancel();
            if (!intercepted) openAppStoreSubscriptions();
          }}
        />
      )}
    />
  );
}

6. Billing Recovery

When RevenueCat reports a billing issue, RedChurn shows an in-app dunning banner and (with Notifee) schedules local reminders. Mount BillingRecoveryFlow as a child of a full-screen container and pick where it pins.

Default CTA: if you don't pass `onCtaPress`, tapping "Update payment" opens the prompt's `ctaUrl` (the payment-update link from your dashboard) so the subscriber can fix their card. Pass `onCtaPress` to route to your own screen instead (e.g. a paywall). Recovery is credited from the renewal webhook, not the button tap.

tsx
import { BillingRecoveryFlow } from "@redchurn/react-native-sdk";
import { useSafeAreaInsets } from "react-native-safe-area-context";

function HomeScreen({ rcAppUserId }: { rcAppUserId: string }) {
  const insets = useSafeAreaInsets();
  return (
    <View style={{ flex: 1 }}>
      <YourHomeContent />
      <BillingRecoveryFlow
        rcAppUserId={rcAppUserId}
        placement="top"          // "top" | "bottom" | "inline"
        edgeInset={insets.top}
        onNotificationOpen={() => navigation.navigate("Home")}
      />
    </View>
  );
}

7. Win back

For churned subscribers (RevenueCat EXPIRATION), WinBackFlow shows your reactivation prompt on next open and wires the notification tap. Route the CTA to your paywall.

tsx
import { WinBackFlow } from "@redchurn/react-native-sdk";

function HomeScreen({ rcAppUserId }: { rcAppUserId: string }) {
  return (
    <WinBackFlow
      rcAppUserId={rcAppUserId}
      onCtaPress={() => navigation.navigate("Paywall")}
      onNotificationOpen={() => navigation.navigate("Home")}
    />
  );
}

8. Server push (optional)

Local notifications only fire while the app has run at least once. To reach subscribers who never reopen the app, RedChurn also sends server push via FCM / APNs, triggered by the RevenueCat webhook.

The token is registered automatically — no manual step in your code. On iOS the SDK uses the native APNs device token; install @react-native-firebase/messaging if you prefer FCM. Add your FCM / APNs credentials once in Dashboard → Integrations → Push notifications.

  • Credentials are per app (BYOK): FCM service account JSON and/or APNs .p8 key
  • Sandbox vs Production: Debug builds from Xcode use sandbox; EAS internal/ad-hoc, TestFlight and App Store use production
  • Test end-to-end from Dashboard → Events → Test push notifications (latest device targeted automatically)

Remote configuration

After the SDK is installed, all subscriber-facing content is managed in the dashboard. Toggle flows on or off, edit copy, change offers, and update styling. Changes propagate within 60 seconds.

The SDK polls a lightweight /version endpoint every minute and only re-downloads configuration when something changed. You can also trigger a refresh when the app returns to foreground.

  • In-app flows and copy: Dashboard → Scenarios → In-app
  • Cancel offers: Dashboard → Cancel saves
  • Email sequences: Dashboard → Scenarios → Email
  • Branding and fallback CTA: Dashboard → Settings

How the SDK talks to RedChurn

Every SDK call goes to the RedChurn API at https://app.redchurn.io, authenticated with your SDK key as a Bearer token. You never call these endpoints directly — the provider and flow components do it for you — but knowing the contract helps when debugging.

On boot the SDK registers the device (heartbeat) and fetches the remote config. It then polls a tiny /version endpoint and only re-downloads /config when the version number changes. Events and outcomes are posted as the subscriber interacts with the flows; only /outcomes is retried (up to twice) because it is the one call that credits saved MRR.

  • 12 second timeout per request, no UI blocking
  • Retries: only POST /outcomes (linear back-off, max 2 retries)
  • rcAppUserId is the join key with your RevenueCat webhook events
  • Need a raw client? import { createRedchurnClient } and call it yourself
Auth headers sent on every request · bash
Authorization: Bearer rdchrn_live_xxxxxxxx
Content-Type: application/json
Accept: application/json
X-RedChurn-Sdk-Version: 0.4.0
Accept-Language: fr            # when a locale is set
Endpoints used by the SDK · text
POST /api/sdk/v1/register     heartbeat + push token registration
GET  /api/sdk/v1/config       full remote config (flows, copy, offers)
GET  /api/sdk/v1/version      lightweight change check (polled)
GET  /api/sdk/v1/prompts      contextual billing-recovery / win-back prompts
POST /api/sdk/v1/events       APP_OPEN, CANCEL_SESSION, PROMPT_SHOWN/DISMISSED, LINK_OPENED
POST /api/sdk/v1/outcomes     saved / declined / dismissed (retried)

Fail-safe behavior

The SDK never throws errors to your app. If RedChurn is unreachable, hooks become no-op and your app renders normally. If cancel tracking fails, the subscriber can still complete cancellation.

Use the onError callback to log non-fatal issues to Sentry or your monitoring tool.

  • 12 second request timeout, no UI freeze
  • Fail-open on cancel: user always reaches store if they insist
  • Invalid SDK key: children render, hooks are no-op
  • Unmount-safe: no state updates after component unmount
tsx
<RedchurnProvider config={{
  sdkKey: "rdchrn_live_...",
  debug: __DEV__,
  onError: (error) => {
    Sentry.captureMessage(`[RedChurn] ${error.code}: ${error.message}`);
  },
}}>

Production checklist

  • RevenueCat webhook connected and delivering events
  • SDK key from production environment (rdchrn_live_...)
  • App User ID set for every authenticated subscriber
  • registerRedchurnBackgroundEventHandler() called in index.js
  • Cancel button wired through CancelSaveFlow / interceptCancel, not a direct store link
  • BillingRecoveryFlow and WinBackFlow mounted in your home/root layout
  • Push credentials added in Dashboard → Integrations (if using server push)
  • In-app copy and offers reviewed in dashboard before launch

Install from npm or download

The recommended path is npm (or npx expo install for Expo). You can also download the SDK tarball from the button at the top of this page if you need an offline copy or a private registry mirror.

bash
# Public npm (once published)
npm install @redchurn/react-native-sdk @notifee/react-native

# Or from a downloaded tarball
npm install ./redchurn-react-native-sdk-0.4.0.tgz