[Customer Center] `presentCustomerCenter()` does not work inside react-navigation modal
- [x] I have updated Purchases SDK to the latest version
- [x] I have read the Contribution Guidelines
- [x] I have searched the Community
- [x] I have read docs.revenuecat.com
- [x] I have searched for existing Github issues
- Environment
- Platform: iOS
- SDK version:
-
"react-native-purchases": "8.7.0" -
"react-native-purchases-ui": "8.7.0"
-
- React Native version:
0.76 - Related deps
-
"@react-navigation/native": "7.0.14" -
"@react-navigation/native-stack": "7.2.0" -
"react-native-screens": "4.4.0"
-
- Steps to reproduce, with a description of expected vs. actual behavior
Try to open customer center from a modal screen via RevenueCatUI.presentCustomerCenter()
Expected: Customer Center opens Actual: Nothing happens
Works as expected on non-modal screens.
👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!
Thank you for opening, we'll take a look. Do you get any logs? Debug logs would be very helpful in order to debug this
@vegaro logs:
[UIKitCore] Attempt to present <PurchasesHybridCommonUI.CustomerCenterUIViewController: 0x10670b320> on
<UIViewController: 0x102a247d0> (from <UIViewController: 0x102a247d0>) which is already presenting <RNSScreen:
0x1269ee200>.
Created a quick reproducable for you
bun create expo
bun add react-native-purchases react-native-purchases-ui
// Added modal & button that calls `presentCustomerCenter()`
Here https://github.com/rrebase/rc-customer-center-bug-demo
@rrebase just opened https://github.com/RevenueCat/react-native-purchases/pull/1209
it doesn't work with wix/react-native-navigation as well.
Any update on this?
I am also posting here to say this is an issue for us. I can't get it to show at all in a modal, on a dashboard etc.
It would also be nice to have a JSX component for this like the paywall as its odd to have a promise to display a UI element.
Here's a native log if that helps address the issue
Attempt to present <PurchasesHybridCommonUI.CustomerCenterUIViewController: 0x1599098a0> on <UIViewController: 0x101623f10> (from <UIViewController: 0x101623f10>) which is already presenting <RCTModalHostViewController: 0x168bb4600>.
+1
@alextbogdanov can you share the code you're using?
@facumenzella I'm just doing the following:
import RevenueCatUI from "react-native-purchases-ui";
<TouchableOpacity
className="mx-4 p-4 bg-white rounded-xl shadow-sm shadow-gray-200 mt-6 flex-row items-center justify-between gap-x-2"
onPress={async () => {
await RevenueCatUI.presentCustomerCenter();
}}
>
...
The problem is that the screen I'm calling it from is a modal. If I make it a basic screen it works:
<Stack.Screen
name="my-profile"
options={{
presentation: "modal",
gestureEnabled: false,
}}
/>
Thanks for raising this. We added flexible presentation options in PR #1209. await RevenueCatUI.presentCustomerCenter() is expected not to work inside another modal — use the view directly instead.
Full-Screen Screen (React Navigation)
// CustomerCenterScreen.tsx
import React from 'react';
import RevenueCatUI from 'react-native-purchases-ui';
export default function CustomerCenterScreen() {
return (
<RevenueCatUI.CustomerCenterView
style={{ flex: 1 }}
// Hide internal close button; rely on nav back
shouldShowCloseButton={false}
onCustomActionSelected={({ actionId }) => {
// Handle custom actions if configured in the dashboard
console.log('Custom action:', actionId);
}}
/>
);
}
// In your navigator
<Stack.Screen
name="CustomerCenter"
component={CustomerCenterScreen}
options={{ title: 'Customer Center' }}
/>
Modal Without Header (Use Internal Close)
// CustomerCenterModal.tsx
import React from 'react';
import RevenueCatUI from 'react-native-purchases-ui';
export default function CustomerCenterModal({ navigation }) {
return (
<RevenueCatUI.CustomerCenterView
style={{ flex: 1 }}
onDismiss={() => navigation.goBack()}
onCustomActionSelected={({ actionId }) => {
console.log('Custom action:', actionId);
}}
/>
);
}
// In your navigator
<Stack.Group screenOptions={{ presentation: 'modal', headerShown: false }}>
<Stack.Screen name="CustomerCenterModal" component={CustomerCenterModal} />
</Stack.Group>
Modal With Header (Use System Back)
// CustomerCenterModalWithHeader.tsx
import React from 'react';
import RevenueCatUI from 'react-native-purchases-ui';
export default function CustomerCenterModalWithHeader() {
return (
<RevenueCatUI.CustomerCenterView
style={{ flex: 1 }}
// Hide internal close button; header back will dismiss
shouldShowCloseButton={false}
/>
);
}
// In your navigator
<Stack.Group screenOptions={{ presentation: 'modal', headerShown: true }}>
<Stack.Screen
name="CustomerCenterModalWithHeader"
component={CustomerCenterModalWithHeader}
/>
</Stack.Group>
Plain React Native Modal
import React from 'react';
import { Modal, View } from 'react-native';
import RevenueCatUI from 'react-native-purchases-ui';
export default function CustomerCenterRNModal({
visible,
onRequestClose,
}: {
visible: boolean;
onRequestClose: () => void;
}) {
return (
<Modal visible={visible} animationType="slide" onRequestClose={onRequestClose}>
<View style={{ flex: 1 }}>
<RevenueCatUI.CustomerCenterView
style={{ flex: 1 }}
shouldShowCloseButton={true}
onDismiss={onRequestClose}
/>
</View>
</Modal>
);
}
Notes
- Use shouldShowCloseButton={false} when you don't want an internal close UI;
- iOS 15+ is required for Customer Center.
@alextbogdanov please let me know if that doesn't work for you. Otherwise, I'll close this one to avoid confusion :)