Playbooks
Serving Moments in Mobile Apps
Flutter - Moments API Integration Guide
17 min
overview the moments api allows you to display personalized offers to users inside your flutter application this guide explains how to integrate the api, from setup to rendering offers and tracking user actions by following this integration guide, you’ll be able to fetch real time, targeted offers based on user context present these offers using your own custom ui or prebuilt reference components track user responses and impressions for reporting and optimization to explore a working example, see the momentscience flutter demo on github prerequisites before you begin, ensure the following requirements are met api key before you start the integration, you must acquire a unique api key follow the instructions provided here to obtain your key install dependency packages add the following dependencies to your pubspec yaml file pubspec yaml dependencies http ^1 4 0 # api requests provider ^6 1 5 # state management url launcher ^6 3 1 # open links in an external browser tinycolor2 ^3 0 1 # convert and manage hex color values provider ^6 0 5 # optional for better state management enable internet access add the following permission to your android app’s manifest android/app/src/main/androidmanifest xml androidmanifest xml \<uses permission android\ name="android permission internet" /> integration steps the moments api delivers personalized offer data based on a set of query parameters and request payload values in this section, you’ll implement a utility function to retrieve and normalize offers for use in your ui for complete details on moments api, refer to the moments api documentation https //docs adspostx com/moments api#rqin step 1 fetch offers in this step, you’ll build a utility function that sends a post request to the moments api docid\ duaxqa4vbbpvihg4cqaac ( native/v4/offers json ) and returns personalized offers based on the given user context instructions define base url and endpoint at the top of offer service dart , define the api constants const string baseurl = 'https //api adspostx com/native/v4'; const string path = 'offers json'; implement loadoffers function paste the following function loadoffers function import 'dart\ convert'; import 'package\ http/http dart' as http; import ' /utils/user agent util dart'; future\<map\<string, dynamic>> loadoffers({ required string apikey, string? loyaltyboost, string? creative, string? campaignid, bool isdevelopment = false, map\<string, string> payload = const {}, }) async { if (apikey isempty) throw exception('api key cannot be empty'); // optional validations if (loyaltyboost != null && !\['0', '1', '2'] contains(loyaltyboost)) { throw exception('loyaltyboost must be 0, 1, or 2'); } if (creative != null && !\['0', '1'] contains(creative)) { throw exception('creative must be 0 or 1'); } final queryparams = { 'api key' apikey, if (loyaltyboost != null) 'loyaltyboost' loyaltyboost, if (creative != null) 'creative' creative, if (campaignid != null) 'campaignid' campaignid, }; final uri = uri parse('$ baseurl/$ path') replace(queryparameters queryparams); final updatedpayload = map\<string, string> from(payload); if (isdevelopment) { updatedpayload\['dev'] = '1'; } final headers = { 'content type' 'application/json', 'accept' 'application/json', 'user agent' payload\['ua'] ?? useragentutil getuseragent(), }; try { final response = await http post(uri, headers headers, body jsonencode(updatedpayload)); if (response statuscode == 200) { return jsondecode(response body); } else { throw exception('api error ${response statuscode} ${response body}'); } } catch (e) { throw exception('error making api call $e'); } } use the function in your app call the loadoffers() function anywhere in your app where you need to fetch offers for example loadoffers usage final offers = await loadoffers( apikey 'your api key', payload { 'adpx fp' 'unique device fp', 'pub user id' 'user123', 'placement' 'checkout success', }, loyaltyboost '0', creative '0', isdevelopment true, // do not use 'true' in prod code ); notes on parameters parameter description apikey your unique api key from momentscience payload context about the user and environment (see below) loyaltyboost 0, 1, or 2 to tune reward targeting creative 0 or 1 to control if creative assets are returned campaignid optional id for tracking a specific campaign isdevelopment set to true to enable dev mode responses common payload fields field type description adpx fp string device fingerprint or session id pub user id string unique user id used by your app (non pii) placement string location in app where the offer is triggered (e g , cart, home) ua string user agent string dev string use "1" to return test offers (note if you are passing isdevelopment value in loadoffers function then you don't need to pass dev in payload ) see offer service dart and user agent util dart in the demo app for a working implementation step 2 build the offer ui after retrieving offer data, you need to design a user interface to present the offers and handle user actions such as claiming or dismissing them the ui example provided below uses offercontainerview offerview offer viewmodel dart from our demo app these are reference implementations only, you are free to implement your own ui components based on your app's design requirements and platform conventions for a detailed explanation of how each field in the offer object is used refer to the offer anatomy docid\ t8o0a 3bctma448n5pyhw this guide will help you understand how to map api fields to ui components and apply dynamic styling correctly offer container ui the offercontainerview displays multiple offers in sequence and manages user navigation, loading, and error states offercontainerview(offers ary of offers) parameter name type description offers list list of offers (decoded json) to be displayed see offer container view\ dart and offer viewmodel dart in the demp app for a working implementation individual offer ui each offer is displayed using the offerview widget, 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 offer viewmodel dart offerview( title currentoffer\['title'], description currentoffer\['description'], imageurl currentoffer\['image'], positivecta currentoffer\['cta yes'], negativecta currentoffer\['cta no'], onpositivepressed () { handlepositivectatap(currentoffer); }, onnegativepressed () { handlenegativectatap(currentoffer); }, // styles from api response styles apistyles, ) parameters name type description title string offer headline description string offer details or body copy imageurl string url of image to display positivecta string label for the "accept" action button negativecta string label for the "decline" or "dismiss" button onpositivepressed voidcallback function to call on positive cta tap onnegativepressed voidcallback function to call on negative cta tap styles map\<string, dynamic> styling metadata from api (e g , button colors, fonts) see offer view\ dart and offer container view\ dart in the demo app for a working implementation if you prefer to use your own layout, styling, or framework specific widgets, you can parse the offer response manually use the offer anatomy docid\ t8o0a 3bctma448n5pyhw documentation to map fields like title, image, cta yes, etc apply any visual styling or logic defined in your own architecture this approach gives you full control over the user experience, while still integrating with the core moments api logic step 3 track user interactions to monitor engagement and ensure accurate analytics, send tracking requests when users interact with offers this includes impressions, dismissals, and cta clicks create a function to fire tracking beacons define a utility function to send tracking pixels via http get requests // this function is used to send requests to tracking urls // provided in the offer payload, such as pixel, adv pixel url, // or beacons close future\<void> sendtrackingrequest(string url) async { if (url isempty) { throw exception('tracking url cannot be empty'); } final uri uri = uri parse(url); try { await http get( uri, headers {'accept' 'application/json'}, ); } catch (e) { throw exception('error sending tracking request $e'); } } track when an offer is displayed when rendering an offer, send impression pixels final pixel = offer?\['pixel']; if (pixel != null && pixel isnotempty) { await sendtrackingrequest(pixel); } final advpixelurl = offer?\['adv pixel url']; if (advpixelurl != null && advpixelurl isnotempty) { await sendtrackingrequest(advpixelurl); } track when the offer container is closed send the "close" beacon when a user dismisses the offer container handlecloseaction future\<void> handlecloseaction(dynamic offer) async { final closebeacon = offer?\['beacons']?\['close']; if (closebeacon != null && closebeacon isnotempty) { await sendtrackingrequest(closebeacon); } } track when the negative cta is clicked fire the no thanks click beacon if a user taps on negative cta final nothanksbeacon = offer?\['beacons']?\['no thanks click']; if (nothanksbeacon != null && nothanksbeacon isnotempty) { await sendtrackingrequest(nothanksbeacon); } see offer viewmodel dart in the demo app for a working implementation next steps we recommend that you go through the moments api implementation checklist https //docs momentscience com/moments and perkswall api implementation checklist to verify your integration completing this checklist ensures that all best practices and requirements are met for a successful moments api deployment 📢 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