React Native
Configuration guide for the Recurly Engage React Native SDK, enabling prompt rendering and event tracking in your React Native applications.
Overview
The Recurly Engage React Native SDK provides components and APIs to render configured prompts—modals (popups, bottom banners, interstitials) and inline views—and handle related user interaction events in React Native apps.
Key benefits
- Cross-platform UI: Seamlessly display modals and inline prompts on both iOS and Android via React Native.
- Built-in interaction handling: Automatically track impressions, clicks, dismissals, and other user events.
- Customizable rendering: Use prebuilt components or implement your own views based on prompt metadata.
Key details
The Recurly Engage React Native SDK provides:
- A prompt manager for initialization and user ID management
- Hooks and components for displaying modal prompts and inline prompts
- APIs for reporting user interactions (impression, goal, decline, dismiss, timeout, holdout)
Install the SDK
Add the following to your .npmrc
or .yarnrc.yml
file. Contact your Customer Success Manager for the AUTHTOKEN.
# .npmrc
@redfast:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=AUTHTOKEN
# .yarnyc.yml
npmAuthToken: "AUTHTOKEN"
Install the package
Using npm
npm install @redfast/redfast-core
npm install @redfast/react-native-redfast
or yarn
yarn add @redfast/redfast-core
yarn add @redfast/react-native-redfast
Initialize Engage
Initialize the SDK in your AppRoot.
// Initialize the SDK, polling until init is complete
React.useEffect(() => {
if (dispatch) {
const promptMgr = new PromptManager(
'YOUR_APP_ID',
'INITIAL_USER_ID' // or null
);
const intervalId = setInterval(() => {
if (promptMgr.isInitialized()) {
dispatch({
type: PromptAction_Init,
data: promptMgr,
});
setReady(true);
clearInterval(intervalId);
}
}, 1000);
return () => clearInterval(intervalId);
}
return () => {};
}, [dispatch]);
// (optional) Utilize specific fonts for various parts of the prompts
useFonts({
buttonFont: require('./assets/fonts/fontA.ttf'),
otherFont: require('./assets/fonts/fontB.ttf'),
});
React.useEffect(() => {
if (dispatch) {
const promptMgr = new PromptManager(
'YOUR_APP_ID',
'INITIAL_USER_ID'
);
const intervalId = setInterval(() => {
if (promptMgr.isInitialized()) {
dispatch({
type: PromptAction_Init,
data: promptMgr,
});
dispatch({
type: PromptAction_Font_Button,
data: 'buttonFont',
});
dispatch({
type: PromptAction_Font_Timer,
data: 'otherFont',
});
dispatch({
type: PromptAction_Font_LegalText,
data: 'otherFont',
});
setReady(true);
clearInterval(intervalId);
}
}, 1000);
return () => clearInterval(intervalId);
}
return () => {};
}, [dispatch]);
Set UserId
You may change the userID after the SDK has been initialized, for example, when the user authenticates mid session. Note that it may take several seconds for the user's prompts to refresh.
promptMgr.setUserId(userId)
Render modal prompts
Interstitial (mobile only), Popup and Bottom Banner modals may be triggered upon entering a screen and/or the user registering a click on an element. Add the following code to screens that are eligible to show a modal.
// Import from Redfast SDK
import {
usePrompt, // Prompt state management
displayPrompt, // Modal prompts
RedfastInline, // Inline prompts
} from '@redfast/react-native-redfast';
// Trigger when entering the "home" screen
const { path, delaySeconds } = await promptMgr.onScreenChanged("home");
if (path) {
setTimeout(() => {
setPathItem(path);
setShowModal(true);
}, delaySeconds);
}
// Or, trigger when "clickId" is clicked
const { path, delaySeconds } = await promptMgr.onButtonClicked("clickId");
if (path) {
setTimeout(() => {
setPathItem(path);
setShowModal(true);
}, delaySeconds);
}
// Display the modal UI for the path object returned above.
// params:
// - showModal: a boolean to stipulate showing or hiding a Prompt
// - path: a path object returned from one of the trigger calls above
// - result: a callback returning PromptResult
displayPrompt(showModal, path, (result) => {
console.log(JSON.stringify({ ...result, source: 'modal' }, null, 2));
setShowModal(false);
})
Render inline prompts
You may utilize the RedfastInline
view to render an inline prompt, if one is available for the current user. Note the inline prompt will scale to fit within its container.
<RedfastInline
zoneId="myZoneId" // ZoneID as specified in Pulse
closeButtonColor="#000000" // Hex color for close button, if enabled
closeButtonBgColor="#FFFFFF" // Hex background color for close button
closeButtonSize="20" // Close button height and width, in pixels
timerFontSize="14" // Countdown timer font size, if enabled
timerFontColor="#FFFFFF" // Countdown timer font hex color
onEvent={(result) =>}
/>
Custom prompt rendering
You may opt to render prompts utilizing the prompt metadata in cases where the desired rendering is different than that produced by the Redfast SDK.
The app should report Prompt interactions via the provided functions on the prompt object.
// Example: Retrieve all available prompts of specified type. See PathType values below. Use this if trigger criteria is to be ignored.
let prompts = promptMgr.getPrompts(PathType.ALL);
// Example: Retrieve all available prompts of specified type and trigger criteria (screenName `homeScreen`)
let prompts = promptMgr.getTriggerablePrompts('home_screen','*', PathType.ALL );
// Example: Retrieve all available prompts of specified type and trigger criteria (screenName `homeScreen` and clickId `add_to_watchlist`)
let prompts = promptMgr.getTriggerablePrompts('home_screen','add_to_watchlist', PathType.ALL );
// Access prompt properties (See below for Prompt interface details)
prompt.button1
prompt.button2
prompt.button3
prompt.inAppSku
promot.deeplink
prompt.deviceMeta
// Report prompt interactions
prompt.impression() // prompt shown to user
prompt.goal() // user clicks on primary CTA
prompt.goal2() // user clicks on secondary CTA
prompt.decline() // user clicks on decline (3rd) button
prompt.dismiss() // user dismisses prompt by clicking on "x" close button
prompt.timeout() // prompt is dismissed via countdown timer
promot.holdout() // prompt is triggered, however the user is in the Control group so prompt should not be shown
/*
PathType values:
PathType.ALL = -1
PathType.MODAL = 2 // Referenced as Popup within Pulse
PathType.HORIZONTAL = 5
PathType.TEXT = 7
PathType.VERTICAL = 8
PathType.TILE = 9
PathType.INTERSTITIAL = 10
PathType.BOTTOM_BANNER = 13
PromptResultCode values:
// Success codes
OK = 1,
// Error codes
ERROR = -100,
NOT_APPLICABLE = -101,
DISABLED = -102,
SUPPRESSED = -103,
// Interactions
IMPRESSION = 100,
BUTTON1 = 101, // CLICK
BUTTON2 = 102, // CLICK2
BUTTON3 = 103, // DECLINE
DISMISS = 110,
TIMEOUT = 111,
HOLDOUT = 120
interface Prompt {
id: string;
type: PathType;
actions: Action;
actionGroupId?: string;
inAppSku?: string;
deviceMeta?: { [key: string]: any };
deeplink?: { [key: string]: any };
button1?: ModalButton;
button2?: ModalButton;
button3?: ModalButton;
buttonBorderRadius: number;
buttonBorderColor: string;
buttonBorderThickness: number;
countDownPrompt: string;
countDownPromptColor: string;
countDownPromptFontSize: number;
countDownPromptInvisible: boolean;
countDown: number;
horizontalPoster?: string;
impression: () => Promise<PromptResult>;
dismiss: () => Promise<PromptResult>;
timeout: () => Promise<PromptResult>;
holdout: () => Promise<PromptResult>;
goal: () => Promise<PromptResult>;
goal2: () => Promise<PromptResult>;
decline: () => Promise<PromptResult>;
}
interface ModalButton {
label?: string;
textColor?: string;
textHightlightColor?: string;
bgColor?: string;
}
*/
Actions
When a user interacts with the primary prompt CTA, a result callback includes various metadata associated with the Prompt to determine the client-side action that should take place.
// Data schema of the result callback
interface PromptResult {
code: PromptResultCode;
value?: { [key: string]: any };
meta?: { [key: string]: any };
promptMeta?: {
promptName: string;
promptID: string;
promptVariationName: string;
promptVariationID: string;
promptExperimentName: string;
promptExperimentID: string;
buttonLabel: string;
};
}
Analytics Callback Example
<RedfastInline
zoneId="myZoneId" // ZoneID as specified in Pulse
closeButtonColor="#000000" // Hex color for close button, if enabled
closeButtonBgColor="#FFFFFF" // Hex background color for close button
closeButtonSize="20" // Close button height and width, in pixels
timerFontSize="14" // Countdown timer font size, if enabled
timerFontColor="#FFFFFF" // Countdown timer font hex color
onEvent={(result) => {
const getEventName = (code: PromptResultCode) => {
switch (code) {
case PromptResultCode.IMPRESSION:
return 'Redfast Impression';
case PromptResultCode.BUTTON1:
return 'Redfast Click';
case PromptResultCode.BUTTON2:
return 'Redfast Click2';
case PromptResultCode.BUTTON3:
return 'Redfast Decline';
case PromptResultCode.DISMISS:
return 'Redfast Dismiss';
case PromptResultCode.TIMEOUT:
return 'Redfast Timeout';
case PromptResultCode.HOLDOUT:
return 'Redfast Holdout';
default:
return 'Redfast Event';
}
};
const analyticsData = {
name: getEventName(result.code),
data: {
...result.promptMeta,
timestamp: new Date().toISOString()
}
};
console.log('ANALYTICS:', JSON.stringify(analyticsData, null, 2));
/* Example:
ANALYTICS: {
"name": "Redfast Click",
"data": {
"promptName": "My Prompt Name",
"promptID": "438c8eec-1111-1111-1111-2222",
"promptVariationName": "Varation 2",
"promptVariationID": "438c8eec-1111-1111-1111-2222",
"promptExperimentName": "My Experiment",
"promptExperimentID": "438c8eec-1111-1111-1111-3333",
"promptType": 5,
"buttonLabel": "Sign me up",
"timestamp": "2025-02-12T05:41:28.365Z"
}
}
*/
// Send Payload to Analytics
}}
/>
// Perform the same for modals
{displayPrompt(showModal, pathItem, (result) => {
// utilize same analytics code above
setShowModal(false);
})}
Deeplink
You can add a Deeplink to a Prompt within Pulse.. When the user invokes the CTA, you can utilize the Deeplink to send the user to a specific location within the app.
{
"code": 0,
"meta": {
"meta": {},
"deeplink": "redflix://test123"
},
}
In-app purchase
An In-App Purchase product SKU may be configured on the prompt, which indicates that the user should be sent to the In-App Purchase flow for the specified SKU once the primary CTA has been selected.
Custom metadata
Custom key-value pairs can be added to an item via Pulse. These values may be used to perform an action that is not the typical media asset deep link, like sending the user to a registration screen or performing an operation on behalf of the user.
{
"code": 0,
"meta": {
"meta": {
"keyName1": "foo",
"keyName2": "bar",
"differentKey": "baz"
},
},
}
Send usage tracking event
Your app can send custom track events using the SDK. If configured as a tracker within Pulse, these custom events can be used to target prompts at specific sets of users.
promptMgr.customTrack(customFieldId)
Debugging
You may reset the current user's prompt status, such that previously suppressed prompts will now be made available.
promptMgr.resetGoal()
Updated 1 day ago