Solutions
...
Moments Prefetch Integration O...
React Native - Moments Prefetch Integration Guide
overview this guide explains how to integrate the momentscience moments solution into your react native application to present personalized offers during the checkout experience the guide covers two integration modes, both designed to preload and display offers in a webview sdk prefetch mode api prefetch mode both options deliver a high performing native experience while maintaining a lightweight and flexible integration integration modes sdk prefetch mode the sdk automatically preloads and caches offers using a 0Γ0 webview placed in advance of checkout offers are displayed instantly when the user reaches the checkout step easiest integration path no need to make manual api calls api prefetch mode your app uses a native https request to fetch offers from the moments api and passes the response into the sdk during checkout full control over when and how offers are requested ability to customize the request payload (e g , user id, cart value) in both modes, the offers are rendered inside a webview on the checkout screen offers are preloaded ahead of time, so user experience remains responsive, even when no offers are available if no offers are returned, your app can skip rendering the offer section to see a full implementation, check out the momentscience react native demo on github which includes examples for offer fetching, event handling, and webview integration requirements to integrate the momentscience sdk into your react native app, ensure the following prerequisites are met a valid momentscience sdk id , which you can obtain by following these steps environment react 18 0 0 react native 0 70 0 integration steps step 1 add dependencies install dependencies install below packages into your react native app react native webview react native dotenv add internet permission to allow offer content to load, add the following permission in to allow offer content to load, add the following permission in android/app/src/main/androidmanifest xml inside \<manifest> but before \<application> \<uses permission android\ name="android permission internet" /> this is required for the sdk to load offer content in both integration modes step 2 prefetch offers (sdk or api) you can prefetch offers using one of two modes sdk prefetch uses a hidden 0Γ0 webview to preload offers api prefetch uses a native api call to fetch offers, which are then injected into the sdk display template in both modes, you can skip showing the checkout screen if no offers are found option 1 sdk prefetch this method uses a hidden 0Γ0 webview to preload the moments sdk in the background when available offers are detected, the sdk triggers an ads found event in your app this is the most lightweight integration method and is ideal when you want to minimize native code involvement set up the webview place a hidden 0Γ0 webview on any screen before checkout make sure to enable the following webview settings javascriptenabled = true domstorageenabled = true originwhitelist = {\[β β]} register javascript event handler the web sdk communicates with your app through javascript events you must handle these events in your app to react to sdk events implement onmessage handler to listen for sdk events const handlemessage = usecallback(message => { try { const data = json parse(message nativeevent data); if (data name === 'ads found') { setofferscount(data total || 0); } } catch (err) { // handle error gracefully } }, \[]); load webview with the prefetch html template use the existing prefetch template from prefetch js inject your sdkid , sdk cdn url , adpxuser configuration dynamically, then load the resulting html into the webview getwebsdkhtml export const getwebsdkhtml = (sdkid, payload) => { let html = processtemplate(prefetchtemplate, { sdk id sdkid, cdn url sdk config cdn url, }); // create adpxuser script with payload if (payload) { const adpxuserscript = createadpxuserscript(payload); html = html replace('window\ adpxuser = {};', adpxuserscript); } return html; }; processtemplate const processtemplate = (template, values) => { let result = template; object entries(values) foreach((\[key, value]) => { result = result replace(new regexp(`%%${key}%%`, 'g'), value); }); return result; }; createadpxuserscript export const createadpxuserscript = payload => { let adpxuserscript = 'window\ adpxuser = {'; if (payload && object keys(payload) length > 0) { object entries(payload) foreach((\[key, value]) => { // ensure value is properly escaped for javascript string const escapedvalue = string(value) replace(/"/g, '\\\\"'); adpxuserscript += `\n ${key} "${escapedvalue}",`; }); // remove trailing comma adpxuserscript = adpxuserscript slice(0, 1); } adpxuserscript += '\n};'; return adpxuserscript; }; generatepayload const generatepayload = usecallback(() => { return { adpx fp generateuniquevalue(), pub user id generateuniquevalue(), placement 'checkout', themeid 'demo', ua generateuseragent(), }; }, \[]); handle ads found event once the webview receives the ads found event, extract the offer count if offer count == 0, you can skip rendering the offer ui entirely to see working example of how to load prefetch html with injected configurations, refer websdkutils js , prefetch js , adpxutils js , homescreen js in demo app option 2 prefetch with api this method allows your app to prefetch offers directly from the moments api and pass them into the web sdk via script injection for complete details on moments api, refer to the moments api documentation https //docs adspostx com/moments api#rqin send a post request to the moments api moments api endpoint post https //api adspostx com/native/v4/offers json build the request parameters include the following api key as a query parameter a user payload in the request body custom user agent in the request headers validate optional parameters (if used) loyaltyboost must be " 0 ", " 1 ", or " 2 " creative must be " 0 " or " 1 " prepare and send the request use the following example code to construct and send the request // api base url=https //api adspostx com/native/v4 export const fetchoffers = async ({ sdkid, loyaltyboost = '0', creative = '0', campaignid = null, isdevelopment = false, payload = {}, }) => { if (!sdkid) { throw new error('sdk id is required'); } // validate loyaltyboost if (!\['0', '1', '2'] includes(loyaltyboost)) { throw new error('invalid loyaltyboost value must be "0", "1", or "2"'); } // validate creative if (!\['0', '1'] includes(creative)) { throw new error('invalid creative value must be "0" or "1"'); } try { // create base query parameters const queryparams = new urlsearchparams(); queryparams append('api key', sdkid); queryparams append('loyaltyboost', loyaltyboost); queryparams append('creative', creative); // add campaignid if provided if (campaignid !== null) { queryparams append('campaignid', campaignid); } // get user agent from payload or generate it const useragent = payload ua || generateuseragent(); // construct request options const requestoptions = { method 'post', headers { 'content type' 'application/json', 'user agent' useragent, }, body json stringify({ (isdevelopment ? { dev 1 } {}), payload, }), }; const response = await fetch( `${api config base url}/offers json?${queryparams tostring()}`, requestoptions, ); if (!response ok) { const errordata = await response json() catch(() => ({})); throw new error( errordata message || `api request failed with status ${response status}`, ); } return await response json(); } catch (error) { throw new error(`failed to fetch offers ${error message}`); } }; save the api response locally store the json response from the api to use it when initializing the sdk to see working implementation of api call refer api js , helpers js in the demo app step 3 show offers using fullscreen webview after confirming that offers are available, display them on your checkout screen using a fullscreen webview pass the necessary parameters depending on the prefetch method navigate to the checkout screen const handleproceedtocheckout = usecallback(() => { const params = { sdkid, apiresponse selectedprefetchmethod === prefetchmethod api ? response null, // only require for api prefetch prefetchmethod selectedprefetchmethod, // not require, as you are going to use one of the approach offerscount getofferscount(), // optional, require only if you want to show no of offers in checkout screen payload currentpayload, useragent generateuseragent(), }; navigation navigate('checkout', params); }, \[ navigation, sdkid, response, selectedprefetchmethod, getofferscount, currentpayload, ]); load the offer experience inside the checkoutscreen, load the offer experience into the webview using checkout js follow these steps read html from checkout js replace placeholders like %%sdk id%% , %%autoload config%% , %%cdn url%% , %%response handling%% with actual values (from the payload or api response) ensure javascript, dom storage settings are enabled in the webview load the final html into webview choose logic based on prefetch mode use different logic depending on whether you're using prefetch with sdk cached offers are automatically shown by the sdk prefetch with api you need to pass the saved apiresponse and inject it via javascript getcheckouthtml const htmlcontent = usememo(() => { return getcheckouthtml({ sdkid, offerscount, autoloadconfig getautoloadconfiguration(), responsehandling getresponsehandlingscript(), adpxuserscript (), }); }, \[ sdkid, offerscount, getautoloadconfiguration, getresponsehandlingscript, getadpxuserscript, ]); getcheckouthtml export const getcheckouthtml = ({ sdkid, offerscount, autoloadconfig, responsehandling, adpxuserscript, }) => { // first replace all template variables let processedhtml = processtemplate(checkouttemplate, { sdk id sdkid, offers count offerscount, autoload config autoloadconfig, cdn url sdk config cdn url, response handling responsehandling, }); // then replace the adpxuser initialization processedhtml = processedhtml replace( 'window\ adpxuser = {};', adpxuserscript, ); return processedhtml; }; processtemplate const processtemplate = (template, values) => { let result = template; object entries(values) foreach((\[key, value]) => { result = result replace(new regexp(`%%${key}%%`, 'g'), value); }); return result; }; getautoloadconfiguration const getautoloadconfiguration = usecallback(() => { const isprefetchapi = prefetchmethod === prefetchmethod api; return getautoloadconfig(isprefetchapi); }, \[prefetchmethod]); const getautoloadconfig = isprefetchapi => { if (isprefetchapi) { return 'autoload false, prefetch false'; } else { return 'autoload true, prefetch true'; } }; const getresponsehandlingscript = usecallback(() => { const isprefetchapi = prefetchmethod === prefetchmethod api; return createresponsehandlingscript(isprefetchapi, apiresponse); }, \[prefetchmethod, apiresponse]); const createresponsehandlingscript = (isprefetchapi, apiresponse) => { if (isprefetchapi && apiresponse) { const apiresponsejson = json stringify(apiresponse); return ` if (window\ adpx && window\ adpx setapiresponse) { const apiresponse = ${apiresponsejson}; window\ adpx setapiresponse(apiresponse) then(() => { console log('api response set to adpx, now reloading '); window\ adpx reload(); }); } `; } return ''; }; const getadpxuserscript = usecallback(() => { return createadpxuserscript(payload); }, \[payload]); export const createadpxuserscript = payload => { let adpxuserscript = 'window\ adpxuser = {'; if (payload && object keys(payload) length > 0) { object entries(payload) foreach((\[key, value]) => { // ensure value is properly escaped for javascript string const escapedvalue = string(value) replace(/"/g, '\\\\"'); adpxuserscript += `\n ${key} "${escapedvalue}",`; }); // remove trailing comma adpxuserscript = adpxuserscript slice(0, 1); } adpxuserscript += '\n};'; return adpxuserscript; }; checkout adpxutils js , usecheckout jsv , checkoutscreen js in the demo app for working implementation step 4 open clicks in an external browser to ensure that offer clickouts open in the deviceβs default browser (rather than inside the webview), listen for sdk callback events and handle the url externally handle onnavigationstatechange callback to open any url in external browser const handlenavigationstatechange = navstate => { // if the url is not about\ blank or your domain url, open in external browser if ( navstate url && navstate url !== 'about\ blank' && !navstate url startswith('https //exampledomain com') ) { linking openurl(navstate url) catch(err => { console error('failed to open url ', err); }); return false; // prevent webview from loading the url } return true; }; checkout checkoutscreen js in the demo app for working implementation conclusion congratulations! you've now completed the integration of the momentscience sdk into your react native app whether you're using sdk prefetch mode or api prefetch mode, your app is now ready to deliver personalized offers directly within the user journey, enhancing monetization while maintaining full control over offer timing and display π’ if you're running into any issues while going through the integration process, feel free to contact us at help\@momentscience com mailto\ help\@momentscience com