React Native
The
@thanksjs/react-native-webviewpackage and itsThanksWidget,ThanksBlock, andThanksWidgetControllercomponents still use the Thanks name. You don't need to change your integration.
Installation
yarn add @thanksjs/react-native-webview react-native-webviewUsage
import { ThanksWidget } from '@thanksjs/react-native-webview';
/// somewhere in your code
<ThanksWidget partnerId="{your partner id}" />;Everything ships with TypeScript types.
Parameters
Refer to the full configuration parameters documentation.
Advanced usage
The important parts are:
- Providing a customer
email. Only a sha256 hash is transferred during the widget lifecycle. No sensitive information leaves your application without your permission. - Giving permission to send personal information to improve the efficiency of communications
subjectandinfocan be used to decide what information to sendsubjectcan berelevance,notification, orautofill
info.tokenis a unique identifier for the request and can be used to trace PII flow further in our systems
keywords,categories, anditemsare used to fine-tune the ads displayed
<ThanksWidget
partnerId="{your partner id}"
// information for the first screen
statusText="Your order has been confirmed"
emailHash={{ sha256: customersEmailHash }}
// or
email={customerEmail}
onPersonalInformationRequest={(subject, info) => {
return {
email,
firstName: 'TestUser',
};
}}
onDisplay={() => {
console.log('widget displayed');
}}
onClose={() => {
console.log('widget closed');
}}
keywords={['violet', 'roses', 'blueberry']}
items={[
{
name: 'Flatwhite',
value: 4.0,
currency: 'AUD',
quantity: 2,
type: 'coffee',
category: 'drinks',
subcategory: 'australian-coffee',
},
]}
categories={['lifestyle']}
/>Using onLinkClick
onLinkClickconst [inAppUrl, setInAppUrl] = useState<string | null>(null);
<ThanksWidget
// ... other configuration parameters
onLinkClick={(url) => {
// Keep deep links in your own app: render content inside the Splash experience modal
// via `children` instead of leaving the app.
if (url.startsWith('myapp://') || url.includes('offers.myapp.com')) {
setInAppUrl(url);
return false; // your app handles it, so the SDK will NOT call Linking.openURL
}
// Everything else: let the SDK open it (equivalent to
// `Linking.openURL(url)`).
return true;
}}
/>Controlling layering and visibility (wrapperComponent)
wrapperComponent)The React Native SDK wraps the widget WebView in React Native's Modal by default. If you need to control z-index or temporarily move the widget out of frame at runtime (for example, while an in-app browser is open), you can replace the wrapper with your own component.
The wrapper receives { children, onRequestClose, animationType, transparent, isReady }. Because it's a normal React component, it can hold its own state and re-render to reposition the widget without closing it.
import { useState } from 'react';
import { View } from 'react-native';
import { ThanksWidget } from '@thanksjs/react-native-webview';
const CustomWrapper = ({ children, isReady }) => {
const [behind, setBehind] = useState(false);
globalThis.__setWidgetBehind = setBehind;
return (
<View
style={{
position: 'absolute',
top: 0, left: 0, right: 0, bottom: 0,
zIndex: behind ? -1 : 9999,
display: isReady ? 'flex' : 'none',
}}
>
{children}
</View>
);
};
<ThanksWidget
partnerId="YOUR_PARTNER_ID"
wrapperComponent={CustomWrapper}
onLinkClick={(url) => {
globalThis.__setWidgetBehind(true);
openInAppBrowser(url, {
onClose: () => globalThis.__setWidgetBehind(false),
});
return false;
}}
/>;wrapperComponent is also accepted by ThanksWidgetController and thanksWidget.open(). When set in both places, the value passed to open() wins.
Note
style.zIndexandoffsetTopruntime updates are for the Web SDK only. For the React Native SDK, usewrapperComponentfor layering and positioning control. While we plan to improve this, the wrapper pattern is the supported approach.
Indirect usage
Sometimes an event-based solution is easier to manage. In this case, we handle some state management for you.
import { ThanksWidgetController, thanksWidget } from '@thanksjs/react-native-webview';
const YourApplication = () => (
<>
{someCode}
// put AFTER all other views, so it will be displayed on top
<ThanksWidgetController partnerId="your-id" />
</>
);
const YourConfirmationPage = () => {
useEffect(
() => {
// ThanksWidgetController will render Widget instantly
// if ThanksWidgetController is not present this will throw an error
thanksWidget.open(thanksConfiguration);
// and hide when you navigate away from the page
return () => thanksWidget.close();
},
[
// important to keep dependencies free to prevent re-rendering widget
// as customer's journey will be reset
],
);
return pageCode;
};Adding a Block
A Block is a permanently embedded element in your application interface.
If you prefer to embed a ThanksBlock into your application, you can follow the example below:
import { ThanksBlock } from '@thanksjs/react-native-webview';
/// somewhere in your code
<View style={{ width, height }}>
<ThanksBlock partnerId="YOUR_PARTNER_ID" />
</View>;In the above example, we wrap the ThanksBlock to set its height and width.
Error handling
You can observe and react to errors in the components with the optional onError prop.
<ThanksWidget
partnerId="YOUR_PARTNER_ID"
onError={(err) => {
// ThanksSdkError
}}
/>
<ThanksBlock
partnerId="YOUR_PARTNER_ID"
slot="main"
onError={(err) => {
// ThanksSdkError
}}
/>Each error has a code, a message, an origin (widget, block, or controller), and optionally context and originalError (for example, the WebView's native error).
Error codes:
WebviewError: WebView failure (network error, or the page crashed or was terminated).HttpError: The widget page returned an HTTP error.StartupTimeout: The widget did not become ready within the startup time limit.LoadingError: Loading failed before the widget was ready.InitialisationFailed: The widget or block could not be initialized.NotEligible: The user is not eligible to see the widget right now (for example, during a cool down period).context.reasonhas the details, andonCloseis called.EligibilityCheckFailed: The eligibility check failed. The widget still displays.PiiRequestFailed: TheonPersonalInformationRequestcallback threw or rejected.InvalidConfiguration,CooldownFetchFailed: Reserved; not currently raised.
Dealing with 'RNCWebView' could not be found
'RNCWebView' could not be foundIn this package, we use react-native-webview to embed our Widget within your application.
Since react-native-webview is a native module, you'll need to make sure react-native-webview is properly linked as a native module. For the following examples, we'll assume you use Expo. If you don't use Expo, you can apply the same steps to your workflow.
Option 1: Install react-native-webview
react-native-webviewStep 1: Install react-native-webview
react-native-webviewnpm install react-native-webviewStep 2: Re-run the Prebuild Command
Now, run the prebuild command again:
expo prebuildStep 3: Run the Custom Development Client
Follow the previous steps to build your custom development client:
expo run:iosOR
expo run:androidBy doing this, we force Expo to add Expo Modules to the iOS Podfile (and build.gradle for Android)
Option 2: Manually install react-native-webview
react-native-webviewIf you do not want to add another dependency to your project, we recommend you manually link the native modules to your Native app's output.
Step 1: Add react-native-webview to your Podfile.
react-native-webview to your Podfile.target 'YourProjectName' do
# ... (other existing pods)
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
endStep 2: Clean the project and reinstall the pods
npx expo prebuild --clean
cd ios && pod install && cd ..Step 3: Run the development client
npx expo run:iosUpdated 6 days ago
