WebSDK React-Native Implementation
A guide to load the Cardlytics Embedded SDK inside a React Native WebView.
Prerequisites
- React Native 0.71 or newer
- react-native-webview installed
Step 1: Minimal HTML host for the SDK
WebView will load a tiny HTML string that includes the SDK and bridges to React Native.
What this does:
- Loads the Cardlytics SDK script
- Defines getSession to request a token from React Native
- Exposes open and close methods and forwards events to the app
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://publisher-cdn-us.cardlytics.com/embedding-sdk/v1/cardlytics-embedding-sdk.js"></script>
<style>
html, body, #cdx-root { height: 100%; width: 100%; margin: 0; }
#cdx-root { position: fixed; inset: 0; background: #fff; }
</style>
</head>
<body>
<div id="cdx-root"></div>
<script>
// Promise bridge for RN <-> WebView
const pending = {};
let seq = 0;
function askNative(type, payload) {
return new Promise((resolve, reject) => {
const id = ++seq;
pending[id] = { resolve, reject };
window.ReactNativeWebView.postMessage(JSON.stringify({ id, type, payload }));
setTimeout(() => {
if (pending[id]) {
delete pending[id];
reject(new Error('Timeout waiting for native response'));
}
}, 5000);
});
}
window.addEventListener('message', (evt) => {
try {
const msg = JSON.parse(evt.data || '{}');
if (msg.replyTo && pending[msg.replyTo]) {
pending[msg.replyTo].resolve(msg.payload);
delete pending[msg.replyTo];
}
} catch {}
});
async function getSessionImplementation() {
// Ask native side for a fresh session token
const data = await askNative('getSession');
return data; // { sessionToken, isLoggedIn }
}
const { open, close, show, hide } = CardlyticsEmbeddedSDK.create({
applicationId: 'YOUR_APPLICATION_ID',
getSession: getSessionImplementation,
autoOpen: true,
onShow: () => window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'onShow' })),
onHide: () => window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'onHide' }))
});
// Allow native to call open or close if needed
window.__CardlyticsControl__ = { open, close, show, hide };
</script>
</body>
</html>
Replace YOUR_APPLICATION_ID with the value from Cardlytics.
Step 2: React Native WebView component
// CardlyticsScreen.tsx
import React, { useCallback, useRef, useState } from 'react';
import { ActivityIndicator, SafeAreaView, View } from 'react-native';
import WebView, { WebViewMessageEvent } from 'react-native-webview';
import axios from 'axios';
const html = `<!doctype html><html>... THE HTML FROM STEP 1 ...</html>`;
export default function CardlyticsScreen() {
const webRef = useRef<WebView>(null);
const [loading, setLoading] = useState(true);
const onMessage = useCallback(async (e: WebViewMessageEvent) => {
try {
const msg = JSON.parse(e.nativeEvent.data || '{}');
if (msg.event === 'onShow') return;
if (msg.event === 'onHide') return;
if (msg.id && msg.type === 'getSession') {
const resp = await axios.post('/api/get_cardlytics_session');
const payload = resp.data;
const reply = { replyTo: msg.id, payload };
webRef.current?.postMessage(JSON.stringify(reply));
}
} catch (err) {
console.warn('Bridge message error', err);
}
}, []);
const open = useCallback(() => {
const js = `window.__CardlyticsControl__ && window.__CardlyticsControl__.open();true;`;
webRef.current?.injectJavaScript(js);
}, []);
const close = useCallback(() => {
const js = `window.__CardlyticsControl__ && window.__CardlyticsControl__.close();true;`;
webRef.current?.injectJavaScript(js);
}, []);
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }}>
<View style={{ flex: 1 }}>
{loading && (
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
)}
<WebView
ref={webRef}
originWhitelist={["*"]}
source={{ html }}
onLoadEnd={() => setLoading(false)}
onMessage={onMessage}
javaScriptEnabled
domStorageEnabled
setSupportMultipleWindows={false}
onShouldStartLoadWithRequest={(req) => {
if (!req.mainDocumentURL?.startsWith('about:blank')) return false;
return true;
}}
/>
</View>
</SafeAreaView>
);
}
Step 3: Wire it into your app
// Example with React Navigation
import { Button } from 'react-native';
function Home({ navigation }) {
return <Button title="Open Rewards" onPress={() => navigation.navigate('Cardlytics')} />;
}
Updated 3 days ago