Playbooks
Serving Moments in Mobile Apps
Moments API iOS Swift Integration Playbook
18min
overview the moments api enables you to present personalized offers to users within your ios application this guide provides a step by step approach to integrating the moments api, from initial setup to offer display and user interaction tracking by following these instructions, you can seamlessly incorporate momentscience offers into your app, enhancing user engagement with minimal development effort prerequisites before you begin the integration process, ensure the following requirements are met api key obtain a unique api key for your account get your api key here ios version your project must target ios 15 0 or higher integration steps 1\ fetch offers the moments api enables you to easily integrate momentscience offers into your app or website it is designed to work with any programming language that supports restful api calls, making it flexible for both mobile and web applications to retrieve offers, use the following endpoint and method method post base url https //api adspostx com/native/v2/offers json https //api adspostx com/native/v2/offers json below is a swift implementation for fetching offers in an ios app this function builds the request, manages optional parameters, and validates the response example fetching offers in ios func fetchoffers( apikey string, loyaltyboost string = "0", creative string = "0", isdevelopment bool = false, payload \[string string]? = nil ) async throws > offersresponse { // construct the payload, adding 'dev' if needed var finalpayload = payload ?? \[ ] if isdevelopment { finalpayload\["dev"] = "1" } // construct url with query parameters var urlcomponents = urlcomponents(string "\\(baseurl)/offers json") urlcomponents? queryitems = \[ urlqueryitem(name "api key", value apikey), urlqueryitem(name "loyaltyboost", value loyaltyboost), urlqueryitem(name "creative", value creative) ] guard let url = urlcomponents? url else { throw offerserror invalidurl } // prepare request var request = urlrequest(url url) request httpmethod = "post" request setvalue("application/json", forhttpheaderfield "content type") request setvalue("application/json", forhttpheaderfield "accept") request httpbody = try? jsonserialization data(withjsonobject finalpayload) do { let (data, ) = try await urlsession shared data(for request) let response = try jsondecoder() decode(offersresponse self, from data) guard let offers = response data? offers, !offers isempty else { throw offerserror nooffers } return response } catch { // handle error } } parameters the following table describes the parameters you can use when calling the fetchoffers function parameter type description required default apikey string the api key associated with your momentscience account yes β loyaltyboost string sets the loyalty boost level for the offers accepts "0", "1", or "2" no "0" creative string determines the creative mode for the offers accepts "0" or "1" no "0" isdevelopment bool enables development mode set to true for testing environments no false payload \[string string]? additional key value pairs to include in the request body no nil response a successful response returns an object containing the available offers and related metadata for detailed response structure and field descriptions, refer to the official moments api documentation for implementation details, see offerservice swift and offer swift 2\ build the offer ui after retrieving offer data, design the user interface to display offers and enable user navigation offer container ui the offer container ui displays multiple offers in sequence and manages user navigation, loading, and error states below is a sample implementation using swiftui import swiftui /// a view that presents offers in a full screen modal interface struct offercontainerview view { /// view model that manages the offers and their state @observedobject var viewmodel offersviewmodel /// environment value for dismissing the view @environment(\\ dismiss) private var dismiss var body some view { zstack { // semi transparent background from api styling viewmodel getpopupbackgroundcolor() ignoressafearea() if viewmodel isloading { // loading state progressview("loading offers ") foregroundcolor( white) } else if let error = viewmodel error { // error state with retry option vstack(spacing 16) { text(error) foregroundcolor( red) padding() hstack(spacing 20) { button("close") { dismiss() } foregroundcolor( gray) button("try again") { viewmodel loadoffers() } foregroundcolor( blue) } } background(color white) clipshape(roundedrectangle(cornerradius 12)) padding() } else if let offer = viewmodel currentoffer { // main offer display container vstack(spacing 0) { // close button with beacon tracking hstack { spacer() button { task { await viewmodel fireclosebeacon() dismiss() } } label { image(systemname "xmark") imagescale( large) foregroundcolor( gray) padding() } } // main offer content offerview( offer offer, buttonstyles viewmodel styles? offertext, onpositivecta { // handle positive response if let clickurl = offer clickurl, let url = url(string clickurl), uiapplication shared canopenurl(url) { uiapplication shared open(url) } // navigate or dismiss if viewmodel hasnextoffer { viewmodel shownextoffer() } else { task { await viewmodel fireclosebeacon() dismiss() } } }, onnegativecta { // handle negative response if let beacons = offer beacons, let nothanksclickurl = beacons nothanksclick, !nothanksclickurl isempty, let url = url(string nothanksclickurl) { viewmodel firebeaconrequest(url url) } // navigate or dismiss if viewmodel hasnextoffer { viewmodel shownextoffer() } else { // on last offer, fire close beacon and dismiss task { // fire close beacon and wait for it to complete await viewmodel fireclosebeacon() // if no more offers, close the container dismiss() } } }, viewmodel viewmodel ) // navigation controls navigationbuttonsview( hasprevious viewmodel haspreviousoffer, hasnext viewmodel hasnextoffer, onprevious viewmodel showpreviousoffer, onnext viewmodel shownextoffer ) } background(color white) clipshape(roundedrectangle(cornerradius 12)) padding( horizontal) padding( vertical, 40) frame(maxwidth infinity, maxheight infinity) } } statusbar(hidden true) } } for more details, see offercontainerview\ swift and offersviewmodel swift individual offer ui each offer is displayed using the offerview component, which presents offer details such as title, image, description, and call to action buttons with dynamic styling the business logic and state for the offer presentation are managed by the offersviewmodel class, following the mvvm pattern // create the view model let viewmodel = offersviewmodel(service offersservice) // load offers (asynchronously) await viewmodel loadoffers(apikey "your api key") // display the current offer offerview( offer viewmodel currentoffer, buttonstyles viewmodel styles? offertext, onpositivecta { / handle accept / }, onnegativecta { / handle decline / }, viewmodel viewmodel ) for advanced usage and dynamic styling, refer to offerview\ swift , offerviewmodel swift https //github com/adspostx/examples/blob/main/ios native/momentsapidemoapp ios/msapidemoapp/msapidemoapp/viewmodels/offersviewmodel swift 3\ track user interactions to monitor user engagement, fire event beacons at key interaction points use the following function to send tracking requests /// sends a beacon request to the specified url for tracking user interactions func firebeaconrequest(url url) async throws { var request = urlrequest(url url) request httpmethod = "get" request setvalue("application/json", forhttpheaderfield "accept") do { let ( , response) = try await urlsession shared data(for request) } catch { // handle error } } this function sends https get requests to predefined beacon urls when the offer container is closed ( beacons close ) an offer is displayed ( pixel ) the negative cta is tapped ( beacons no thanks click ) for the full implementation, see offersservice swift https //github com/adspostx/examples/blob/main/ios native/momentsapidemoapp ios/msapidemoapp/msapidemoapp/services/offersservice swift firing close beacon when a user closes the offer container func fireclosebeacon() async { guard let offer = currentoffer, let beacons = offer beacons, let closeurl = beacons close, !closeurl isempty, let url = url(string closeurl) else { return } do { try await offersservice firebeaconrequest(url url) } catch { print("close beacon request failed \\(error localizeddescription)") } } firing βno thanksβ beacon when a user taps the negative cta if let beacons = offer beacons, let nothanksclickurl = beacons nothanksclick, !nothanksclickurl isempty, let url = url(string nothanksclickurl) { viewmodel firebeaconrequest(url url) } firing pixel events when an offer is displayed private func firepixelrequestforcurrentoffer() { guard let offer = currentoffer, let pixelurl = offer pixel, !pixelurl isempty, let url = url(string pixelurl) else { return } task { do { try await offersservice firebeaconrequest(url url) } catch { print("pixel request failed \\(error localizeddescription)") } } } explore the momentscience example on github https //github com/adspostx/examples/tree/main/ios native/momentsapidemoapp ios to see a working demo next steps we recommend that you go through the moments api implementation checklist to verify your integration completing this checklist ensures that all best practices and requirements are met for a successful moments api integration π’ if you're running into any issues while going through the integration process, feel free to contact us at help\@momentscience com