Skip to main content

Flutter SDK+ Integration Guide

Target
Language
For Rokt Ecommerce partners. This complete guide is for ecommerce businesses integrating Rokt into transaction experiences they own. It is not an advertiser implementation guide. Advertisers should use the Rokt Ads integration guides.

This page explains how to implement the Rokt Ecommerce Flutter SDK+. The SDK+ passes user and transaction data to Rokt on configured screens so Rokt can render relevant experiences, such as offers on confirmation screens.

Use the Target and Language selectors above to choose your deployment platform and the native code examples you want to follow.

note

You'll write a few lines of native code (Swift or Objective-C on iOS, Kotlin or Java on Android) when you initialize the SDK+ in Step 2. Every other step uses Dart through the mparticle_flutter_sdk package.

1. Add the Rokt SDK+ to Your Flutter App#

The Flutter SDK+ runs on top of the native SDK+. The Dart-side install steps are the same for every target; the native install differs per target platform. Use the Target pill above to switch between iOS, Android, and Web.

1Add the mparticle_flutter_sdk package#

Add the mparticle_flutter_sdk package to your Flutter project.

Add the Flutter package
flutter pub add mparticle_flutter_sdk

2Pin mparticle_flutter_sdk to 2.0 or later#

After running pub add, your pubspec.yaml should pin the package to 2.0 or later (required for Shoppable Ads).

pubspec.yaml
dependencies:
mparticle_flutter_sdk: ^2.0.0

3Add the Rokt SDK+ to your iOS app#

Rokt SDK+ requires a minimum deployment target of iOS 15.0. Use CocoaPods or Swift Package Manager — whichever your project already uses.

Install method

Add the Rokt SDK+ pod to your ios/Podfile:

ios/Podfile
pod 'RoktSDKPlus', '~> 9.2'

4Get the SDK handle#

Import the package into your Dart code and get an instance of the SDK. This mpInstance is the SDK handle the rest of this guide builds on — every Dart API call in later steps (identify, set user attributes, log events, show placements) goes through it.

Get the SDK handle
import 'package:mparticle_flutter_sdk/mparticle_flutter_sdk.dart';

MparticleFlutterSdk? mpInstance = await MparticleFlutterSdk.getInstance();

2. Initialize the Rokt SDK+#

The Flutter SDK+ initializes through the native SDK+ on your target platform. Insert the appropriate initialization snippet on the native side, then the Dart mparticle_flutter_sdk package will proxy through to it.

When inserting the initialization snippet, you will see customizable fields for:

1Entering your Rokt key and secret#

Set the Rokt key and secret to the values provided by your Rokt account manager.

2Setting your data environment#

Set the SDK+ environment to development while testing to route data to the Development environment, and to production to send live customer activity to Production. (iOS: .development / .production. Android: MParticle.Environment.Development / MParticle.Environment.Production.)

3Entering a custom first-party domain#

Follow the instructions in First-Party Domain Configuration, and set the custom base URL on your network-options object to your custom subdomain. Routing the Rokt SDK+ through your own domain reduces the risk of ad blockers and browsers blocking ads or data. Omit the network options entirely to send traffic to Rokt's default endpoints.

4Identifying your user and setting attributes#

In identifyRequest, pass the user's raw, un-hashed email. Once identified, use the success callback (iOS: onIdentifyComplete. Android: addSuccessListener) to set additional user attributes.

note

Always include identifyRequest in the initialization snippet. If you don't have the user's email at initialization, omit the assignment (iOS) or pass null (Android) — the SDK+ will still initialize, and you can identify the user later via Step 3: Identify the User. See Error Handling for how to handle identity failures — without error handling you may see data consistency issues at scale.

Insert the following initialization snippet in your AppDelegate file. Replace your-key and your-secret with the values provided by your Rokt team.

AppDelegate initialization (Swift)
import mParticle_Apple_SDK
import RoktPaymentExtension

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Initialize the SDK
let options = MParticleOptions(key: "your-key",
secret: "your-secret")
// Specify the data environment with environment:
// Set it to .development if you are still testing your integration.
// Set it to .production if your integration is ready for production data.
// The default is .autoDetect which attempts to detect the environment automatically
options.environment = .development

// Enter your custom subdomain if you are using a first-party domain configuration (optional)
let networkOptions = MPNetworkOptions()
networkOptions.customBaseURL = URL(string: "https://rkt.example.com")
options.networkOptions = networkOptions

// Identify the current user:
let identifyRequest = MPIdentityApiRequest.withEmptyUser()

// If you're using an un-hashed email address, set it in 'email'.
identifyRequest.email = "j.smith@example.com"

// If you're using a hashed email address, set it in 'other' instead of email
identifyRequest.setIdentity("sha256 hashed email goes here", identityType: .other)

// If the user is identified with their email address, set additional user attributes.
options.identifyRequest = identifyRequest
options.onIdentifyComplete = {(result: MPIdentityApiResult?, error: Error?) in
if let user = result?.user {
user.setUserAttribute("example attribute key", value: "example attribute value")
}
}
MParticle.sharedInstance().start(with: options)

// Register after MParticle.sharedInstance().start(), before selectShoppableAds
if let paymentExt = RoktPaymentExtension(
applePayMerchantId: "merchant.com.yourapp.rokt", // omit if not offering Apple Pay
urlScheme: "myapp" // omit if not offering Afterpay / Clearpay
) {
MParticle.sharedInstance().rokt.registerPaymentExtension(paymentExt)
}
return true
}
note

Configure stripePublishableKey in your mParticle Rokt kit settings (mParticle dashboard). The kit forwards it to Rokt as stripeKey at registration time — you do not pass it in code. At least one of applePayMerchantId or urlScheme must be provided.

5Registering the payment extension#

Register RoktPaymentExtension after MParticle.sharedInstance().start() and before selectShoppableAds to enable Shoppable Ads payments. Registration is required for all Shoppable Ads placements on iOS — pass applePayMerchantId for Apple Pay, urlScheme for Afterpay / Clearpay, or both. See Appendix F: Configure Shoppable Ads payments.

3. Identify the User#

The SDK+ initialization script identifies the current user using the identifiers you provided in the script's identifyRequest object. After SDK initialization, you should keep the user's identity in sync whenever they log in, log out, or otherwise provide an identifier (for example, during checkout) using the appropriate method as described below.

Supported user identifiersDirect link to Supported user identifiers

Show supported user identifiers
IdentifierTypeDescription
emailstringPass the customer's raw, unhashed email address.
mobile_numberstringPass the customer's phone number in E.164 format.
customerIdstringPass your internal customer/account identifier. Send on every screen for logged-in users.
otherstringPass a SHA-256-hashed email. Only use when the raw email cannot be provided — do not pass both email and other.
other2stringPass a SHA-256-hashed mobile number. Only use when the raw mobile number cannot be provided — do not pass both mobile_number and other2.

To identify the user:

1Create an identityRequest object#

Create an identityRequest object to contain the user's identifiers. You should integrate the user's raw, unhashed email address into the email field.

2Use the success handler for additional attributes#

To set additional user attributes, use the then success handler on the identify call (web: identityCallback). If the identityRequest succeeds, any user attributes you set inside the handler are assigned to the identified user.

3Send the request using the method that matches the user's action#

Pass the identityRequest (and optional identityCallback) to the method that matches the user's action:

  • login: call when the user logs in or creates an account.
  • identify: call when you obtain the user's email mid-session without a login transition (for example, a guest enters their email at checkout).
  • logout: call when the user logs out.

Calling these methods transitions the SDK's record of the current user's state. The login and logout methods also automatically log a corresponding event to improve Rokt's attribution.

For example, to identify a user named Jane Smith with the email address j.smith@example.com, mobile number +13125551515, and customer ID cust_10482:

Identify Jane Smith (Dart)
import 'package:mparticle_flutter_sdk/identity/identity_type.dart';
import 'package:mparticle_flutter_sdk/identity/identity_api_result.dart';
import 'package:mparticle_flutter_sdk/identity/identity_api_error_response.dart';

// 1. Create the identityRequest object
var identityRequest = MparticleFlutterSdk.identityRequest;
// Preferred: pass the customer's raw, unhashed email.
// If you can only provide a SHA-256-hashed email, remove the Email line and use IdentityType.Other instead — do not pass both.
identityRequest.setIdentity(identityType: IdentityType.Email, value: 'j.smith@example.com');
identityRequest.setIdentity(identityType: IdentityType.Other, value: 'SHA-256 hashed email'); // only if raw email unavailable
// If you can only provide a SHA-256-hashed mobile number, use IdentityType.Other2 instead of MobileNumber — do not pass both.
identityRequest.setIdentity(identityType: IdentityType.Other2, value: 'SHA-256 hashed mobile number'); // only if raw mobile unavailable
identityRequest.setIdentity(identityType: IdentityType.MobileNumber, value: '+13125551515');
identityRequest.setIdentity(identityType: IdentityType.CustomerId, value: 'cust_10482');

// 2. Optionally set user attributes in the success handler.
void Function(IdentityApiResult) identityCallback = (IdentityApiResult successResponse) {
successResponse.user.setUserAttribute('firstname', 'Jane');
successResponse.user.setUserAttribute('lastname', 'Smith');
};

// 3. Call one of the following methods that best matches the user's action:
mpInstance?.identity.login(identityRequest: identityRequest).then(identityCallback); // Call when the user logs in or creates an account
mpInstance?.identity.identify(identityRequest: identityRequest).then(identityCallback); // Call when you obtain the user's email mid-session, but not during a login
mpInstance?.identity.logout(); // Call when the user logs out

4. Set User Attributes#

Set user attributes progressively as the user navigates your app, not just at checkout. The more attributes you set, the better Rokt can resolve the customer and deliver relevant offers.

Set user attributes (Dart)
import 'package:mparticle_flutter_sdk/mparticle_flutter_sdk.dart';

// Retrieve the current user. This will only succeed if you have identified the user during SDK initialization or by calling the identify method.
var currentUser = await mpInstance?.getCurrentUser();

// Once you have successfully set the current user to `currentUser`, you can set user attributes with:
currentUser?.setUserAttribute(key: 'custom-attribute-name', value: 'custom-attribute-value');
// Note: all user attributes (including list attributes and tags) must have distinct names.

// Rokt recommends setting as many of the following user attributes as possible:
currentUser?.setUserAttribute(key: 'firstname', value: 'John');
currentUser?.setUserAttribute(key: 'lastname', value: 'Doe');
// Phone numbers can be formatted either as '1234567890', or '+1 (234) 567-8901'
currentUser?.setUserAttribute(key: 'mobile', value: '3125551515');
currentUser?.setUserAttribute(key: 'age', value: '33');
currentUser?.setUserAttribute(key: 'gender', value: 'M');
currentUser?.setUserAttribute(key: 'city', value: 'Brooklyn');
currentUser?.setUserAttribute(key: 'state', value: 'NY');
currentUser?.setUserAttribute(key: 'zip', value: '123456');
currentUser?.setUserAttribute(key: 'dob', value: 'yyyymmdd');
currentUser?.setUserAttribute(key: 'title', value: 'Mr');
currentUser?.setUserAttribute(key: 'language', value: 'en');
currentUser?.setUserAttribute(key: 'lifetime_value', value: '52.25');
currentUser?.setUserAttribute(key: 'predictedltv', value: '136.23');

// You can create a user attribute to contain a list of values
var attributeList = <String>[];
attributeList.add('documentary');
attributeList.add('comedy');
attributeList.add('romance');
attributeList.add('drama');
currentUser?.setUserAttributeArray(key: 'favorite-genres', value: attributeList);

// To remove a user attribute, call removeUserAttribute and pass in the attribute name. All user attributes share the same key space.
currentUser?.removeUserAttribute(key: 'attribute-to-remove');

User attributesDirect link to User attributes

Set as many of the following as you can collect:

Show all user attributes
AttributeTypeDescription
firstnamestringCustomer's first name. Used for personalization.
lastnamestringCustomer's last name. Used for personalization.
mobilestringPhone number formatted as 1112345678 or +1 (222) 345-6789. Used for identity resolution and relevance.
ageintegerCustomer's age. Alternate to dob. Used for eligibility and relevance.
dobstringDate of birth, yyyymmdd. Alternate to age. Used for eligibility and relevance.
genderstringCustomer's gender. For example, M, F, Male, or Female. Used for relevance.
titlestringHonorific. For example, Mr, Mrs, Ms. Used for personalization.
languagestringISO 639-1 language code associated with the purchase. Used for relevance.
citystringBilling city. Used for relevance.
statestringBilling state / province / region. Used for relevance and eligibility.
zipstringFull ZIP or postcode (US preference is ZIP+4). Used for identity resolution and relevance.
countrystringISO 3166-1 alpha-2 country code (e.g. US, GB, AU). Used for eligibility and relevance.
newcustomerbooleanWhether this is a first-time buyer. Used for relevance.
customertypestringWhether the user is authenticated (guest / logged_in). Used for relevance.
loyaltytierstringPartner loyalty program tier. Used for relevance and eligibility.
loyaltyidstringLoyalty program member ID. Used for identity resolution.
lifetime_valuedecimalCustomer's cumulative purchase value, as a string (e.g. "52.25"). Used for relevance.
predictedltvdecimalPredicted total lifetime value, typically from a partner ML model. Distinct from lifetime_value. Used for relevance.
subscriptionstatusstringSubscription state if applicable (active, trial, churned, paused, none). Used for relevance and eligibility.
customersegmentstringPartner internal segmentation (e.g. vip, at_risk, new, reactivated). Used for relevance.
utmsourcestringMarketing attribution source. Used for relevance.
utmmediumstringMarketing attribution medium. Used for relevance.
utmcampaignstringMarketing attribution campaign. Used for relevance.

All user attributes (including list attributes) must have distinct names.

5. Log Events#

Track screen views, commerce events, and custom events so Rokt can understand where each customer is in their journey.

Event category

Call mpInstance?.logScreenEvent() with the name of the screen (e.g. 'homepage', 'product_detail_page'). Include any additional custom attributes in the event's customAttributes map.

Log a screen view (Dart)
import 'package:mparticle_flutter_sdk/events/screen_event.dart';

ScreenEvent screenEvent = ScreenEvent(eventName: 'homepage')
..customAttributes = {'custom-attribute': 'custom-value'};
mpInstance?.logScreenEvent(screenEvent);

6. Show a Placement#

Call selectPlacements on every payment and confirmation screen you want Rokt to render content on. Include one of the following page identifiers to specify the screen type and whether it's for testing or production:

  • stg.rokt.conf: A confirmation page in a staging (or testing) environment.
  • prod.rokt.conf: A confirmation page in a production environment.
  • stg.rokt.payments: A payments page in a staging (or testing) environment.
  • prod.rokt.payments: A payments page in a production environment.

Placement attributesDirect link to Placement attributes

Pass these attributes in the attributes map of selectPlacements. Always supply the most recent value — attributes passed here override any earlier setUserAttribute calls.

Show all placement attributes
AttributeTypeDescription
emailstringCustomer email (unhashed). Used for identity resolution.
firstnamestringCustomer first name. Used for personalization.
lastnamestringCustomer last name. Used for personalization.
mobilestringCustomer mobile number in E.164 format. Used for identity resolution.
confirmationrefstringOrder / confirmation reference number. Used for relevance and deduplication.
currencystringTransaction currency (ISO 4217, e.g. USD, GBP, AUD). Used for relevance.
countrystringISO 3166-1 alpha-2 country code. Used for eligibility and relevance.
languagestringCustomer's preferred language (ISO 639-1). Used for relevance.
totalpricedecimalTotal cart value including tax and shipping. Used for relevance.
amountstringCart subtotal before tax and shipping. Distinct from totalprice. Used for relevance and Shoppable Ads.
cartitemcountintegerNumber of items in the cart. Used for relevance.
cartItemsarrayStructured array of cart-line objects (Flutter Web only). See Cart items under Commerce Events. Used for relevance.
couponcodestringPromo code applied to the order, if any. Used for relevance.
newcustomerbooleanWhether this is a first-time buyer. Used for relevance.
customertypestringguest or logged_in. Used for relevance.
lifetime_valuedecimalCustomer's cumulative purchase value (e.g. "2340.00"). Used for relevance.
subscriptionstatusstringSubscription state if applicable (active, trial, churned, paused, none). Used for relevance and eligibility.
customersegmentstringPartner internal segmentation (e.g. vip, at_risk, new, reactivated). Used for relevance.
paymenttypestringPayment method selected (credit_card, paypal, apple_pay, etc.). Used for Pay+ eligibility and Shoppable Ads payment method prioritization.
paymentServiceProviderstringPayment services offered on the page (apple_pay, paypal, card). Used for Pay+ eligibility.
ccbinstringCredit card BIN (6-8 digits). Used for relevance.
billingaddress1stringBilling street address. Used for identity resolution and relevance.
billingaddress2stringBilling apartment / unit. Used for identity resolution.
billingcitystringBilling city. Used for relevance.
billingstatestringBilling state or province. Used for relevance.
billingzipcodestringBilling ZIP / postcode. Used for identity resolution and relevance.
shippingmethodstringShipping method selected (standard, express, next_day). Used for relevance.
shippingaddress1stringShipping street address. Used for relevance and Shoppable Ads order fulfillment.
shippingcitystringShipping city. Used for relevance and Shoppable Ads order fulfillment.
shippingstatestringShipping state or province. Used for relevance and Shoppable Ads order fulfillment.
shippingzipcodestringShipping ZIP or postcode. Used for relevance and Shoppable Ads order fulfillment.
shippingcountrystringShipping country (ISO 3166-1 alpha-2). Used for relevance and Shoppable Ads order fulfillment.
adsexperiencestringPass "shoppable" when deliberately selecting a Shoppable Ads experience.
Placement position

Overlay placements render on top of your confirmation screen in a Rokt-managed container, requiring no changes to your app's existing layout.

To insert an overlay placement, call selectPlacements once the confirmation screen loads:

Overlay placement (Dart)
import 'package:mparticle_flutter_sdk/mparticle_flutter_sdk.dart';

final attributes = {
// Identity
'email': 'j.smith@example.com',
'firstname': 'Jenny',
'lastname': 'Smith',
'mobile': '+13125551515',

// Transaction
'confirmationref': '54321',
'currency': 'USD',
'country': 'US',
'language': 'en',
'totalprice': '149.99',
'cartitemcount': '2',
'couponcode': 'SUMMER20',

// Customer context
'newcustomer': 'false',
'customertype': 'logged_in',
'lifetime_value': '2340.00',
'subscriptionstatus': 'active',
'customersegment': 'vip',

// Payment (include paymenttype and paymentServiceProvider for Pay+)
'paymenttype': 'credit_card',
'paymentServiceProvider': 'card',
'ccbin': '411112',

// Billing address
'billingaddress1': '123 Main St',
'billingcity': 'Brooklyn',
'billingstate': 'NY',
'billingzipcode': '11201',

// Shipping
'shippingmethod': 'express',
'shippingaddress1': '175 Varick St',
'shippingcity': 'New York',
'shippingstate': 'NY',
'shippingzipcode': '10014',
'shippingcountry': 'US',
};

final roktConfig = RoktConfig(
colorMode: ColorMode.light,
);

mpInstance?.rokt.selectPlacements(
identifier: 'RoktExperience',
attributes: attributes,
roktConfig: roktConfig,
);

Optional functionsDirect link to Optional functions

FunctionPurpose
Rokt.close()Auto-close overlay placements.

Additional configurationDirect link to Additional configuration

Pass optional parameters such as RoktConfig to customize the placement UI (e.g. dark/light mode, caching). Font file paths can also be supplied as a map of PostScript names to asset paths.

selectPlacements with RoktConfig and font typefaces (Dart)
// If you want to use custom fonts for your placement, create a fontTypefaces map
final fontTypefaces = {'Arial-Bold': 'fonts/Arial-Bold.ttf'};

final roktConfig = RoktConfig(
colorMode: ColorMode.light,
);

mpInstance?.rokt.selectPlacements(
identifier: 'RoktExperience',
attributes: attributes,
fontFilePathMap: fontTypefaces,
roktConfig: roktConfig,
);
note

If you want to update the identifier RoktExperience or embedded identifier RoktEmbedded1 with a different value, contact your Rokt account manager to ensure Rokt placements are configured consistently.

Events APIDirect link to Events API

On iOS and Android, the SDK+ provides placement lifecycle events as a stream through the MPRoktEvents EventChannel. On Web, subscribe to events directly on the selection object returned by selectPlacements.

Subscribe to placement events (Dart)
final EventChannel roktEventChannel = EventChannel('MPRoktEvents');
roktEventChannel.receiveBroadcastStream().listen((dynamic event) {
debugPrint('rokt_event: $event');
});

Standard eventsDirect link to Standard events

Show all standard events
EventDescriptionParams
ShowLoadingIndicatorTriggered before the SDK+ calls the Rokt backend.
HideLoadingIndicatorTriggered when the SDK+ receives a success or failure from the Rokt backend.
PlacementInteractiveTriggered when a placement has been rendered and is interactable.identifier: String
PlacementReadyTriggered when a placement is ready to display but has not rendered content yet.identifier: String
OfferEngagementTriggered when the user engages with the offer.identifier: String
PositiveEngagementTriggered when the user positively engages with the offer.identifier: String
FirstPositiveEngagementTriggered when the user positively engages with the offer for the first time.identifier: String, fulfillmentAttributes: FulfillmentAttributes
OpenUrlTriggered when the user presses a URL that is configured to be sent to the partner app.identifier: String, url: String
PlacementClosedTriggered when a placement is closed by the user.identifier: String
PlacementCompletedTriggered when the offer progression reaches the end and no more offers are available to display. Also triggered when cache is hit but the retrieved placement will not be displayed as it has previously been dismissed.identifier: String
PlacementFailureTriggered when a placement could not be displayed due to some failure or when no placements are available to show.identifier: String (optional)
EmbeddedSizeChangedTriggered when an embedded placement's height changes.identifier: String, selectedHeight: Double
CartItemInstantPurchaseTriggered when the catalog item purchase is initiated by the user.identifier: String, catalogItemId: String, cartItemId: String, totalPrice: String, currency: String
CartItemInstantPurchaseInitiatedPurchase flow started — user tapped "Buy" (Shoppable Ads, iOS only).identifier: String, catalogItemId: String, cartItemId: String
CartItemInstantPurchaseFailurePurchase failed (Shoppable Ads, iOS only).identifier: String, catalogItemId: String, cartItemId: String, error: String
CartItemDevicePayApple Pay / device payment triggered (Shoppable Ads, iOS only).identifier: String, catalogItemId: String, cartItemId: String, paymentProvider: String
InstantPurchaseDismissalUser dismissed the purchase overlay (Shoppable Ads, iOS only).identifier: String

7. Appendix#

Appendix A: App configurationDirect link to Appendix A: App configuration

Applications can pass configuration settings through RoktConfig so the SDK+ uses your app's custom configuration instead of system defaults.

ColorMode objectDirect link to ColorMode object

ValueDescription
lightApplication is in Light Mode
darkApplication is in Dark Mode
systemApplication defaults to System Color Mode
RoktConfig with ColorMode
final roktConfig = RoktConfig(
colorMode: ColorMode.light,
);

mpInstance?.rokt.selectPlacements(
identifier: 'RoktExperience',
attributes: attributes,
roktConfig: roktConfig,
);

EdgeToEdgeDisplay (Android only)Direct link to EdgeToEdgeDisplay (Android only)

ValueDescription
true (default)Application supports Edge to Edge display mode
falseApplication does not support Edge to Edge display mode

When building the native RoktConfig on Android, call edgeToEdgeDisplay(true) on the RoktConfig.Builder to enable edge-to-edge mode:

RoktConfig with EdgeToEdgeDisplay (Android native)
import com.mparticle.MParticle
import com.mparticle.rokt.RoktConfig

val roktConfig = RoktConfig.Builder()
.edgeToEdgeDisplay(true)
.build()

MParticle.getInstance()?.Rokt()?.selectPlacements(
identifier = "RoktExperience",
attributes = attributes,
config = roktConfig
)

CacheConfig objectDirect link to CacheConfig object

ParameterDescription
cacheDurationInSecondsOptional duration in seconds for which the Rokt SDK+ should cache the experience. Maximum allowed value is 90 minutes; default is 90 minutes if not provided or invalid.
cacheAttributesOptional attributes to be used as cache key. If null, all attributes sent in selectPlacements will be used as the cache key.
Cache for 1200 seconds
// Cache the experience for 1200 seconds, using email and orderNumber as the cache key.
final roktConfig = RoktConfig(
cacheConfig: CacheConfig(
cacheDurationInSeconds: 1200,
cacheAttributes: {'email': 'j.smith@example.com', 'orderNumber': '123'},
),
);

mpInstance?.rokt.selectPlacements(
identifier: 'RoktExperience',
attributes: attributes,
roktConfig: roktConfig,
);

Appendix B: SwiftUI support with MPRoktLayout (iOS only)Direct link to Appendix B: SwiftUI support with MPRoktLayout (iOS only)

If your app is primarily written in SwiftUI, the MPRoktLayout component provides a more modern, declarative approach to integrating Rokt placements in your iOS app.

The MPRoktLayout class provides a SwiftUI-compatible way to display Rokt placements without manually calling selectPlacements, supporting both overlay and embedded placement types.

SwiftUI placement with MPRoktLayout
import SwiftUI
import mParticle_Apple_SDK
import mParticle_Rokt_Swift

struct OrderConfirmationView: View {
let attributes = [
"email": "test@gmail.com",
"firstname": "Jenny",
"lastname": "Smith",
"billingzipcode": "07762",
"confirmationref": "54321"
]

@State private var sdkTriggered = true

var body: some View {
VStack(alignment: .leading) {
// Other UI components
Text("Order Confirmation")
.font(.title)

// Rokt placement using SwiftUI
MPRoktLayout(
sdkTriggered: $sdkTriggered,
identifier: "RoktExperience",
locationName: "RoktEmbedded1", // For embedded placements
attributes: attributes,
config: roktConfig, // Optional RoktConfig
onEvent: { roktEvent in
// Optional: Handle different event types see above
}
).roktLayout
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
ParameterTypeDescription
sdkTriggeredBoolControls when the placement should be triggered.
identifierStringThe Rokt placement identifier (e.g., "RoktExperience").
locationNameString?Optional location name for embedded placements (e.g., "RoktEmbedded1").
attributes[String: String]Dictionary of attributes to pass to the placement.
configRoktConfig?Optional configuration object for color mode, caching, etc.
onEvent((RoktEvent) -> Void)?Optional callback to handle all placement events.

Appendix C: Jetpack Compose support with RoktLayout (Android only)Direct link to Appendix C: Jetpack Compose support with RoktLayout (Android only)

For screens implemented using Jetpack Compose, the SDK+ provides the RoktLayout composable for a modern, declarative integration of Rokt placements. RoktLayout supports Overlay, BottomSheet, and Embedded placement types without manually invoking selectPlacements.

Jetpack Compose placement with RoktLayout
import com.mparticle.kits.RoktLayout
import com.mparticle.MpRoktEventCallback
import com.mparticle.UnloadReasons

@Composable
fun MainScreen(modifier: Modifier = Modifier) {
Column(
modifier = modifier
.background(Color.LightGray)
.padding(8.dp),
) {
val attributes = mapOf(
"email" to "j.smith@example.com",
"firstname" to "Jenny",
"lastname" to "Smith",
"mobile" to "(323) 867-5309",
"postcode" to "90210",
"country" to "US"
)
val callbacks = object : MpRoktEventCallback {
override fun onLoad() = println("View loaded")
override fun onUnload(reason: UnloadReasons) = println("View unloaded due to: $reason")
override fun onShouldShowLoadingIndicator() = println("Show loading indicator")
override fun onShouldHideLoadingIndicator() = println("Hide loading indicator")
}
val roktConfig = RoktConfig.Builder()
.colorMode(RoktConfig.ColorMode.DARK)
.cacheConfig(CacheConfig(
cacheDurationInSeconds = 1200,
cacheAttributes = mapOf("email" to "j.smith@example.com")
))
.build()

RoktLayout(
sdkTriggered = true,
identifier = "RoktExperience",
attributes = attributes,
location = "Location1",
modifier = Modifier
.fillMaxWidth()
.background(Color.Black),
mpRoktEventCallback = callbacks,
config = roktConfig
)
}
}

ParametersDirect link to Parameters

ParameterTypeDescription
sdkTriggeredBooleanControls when the placement should be triggered.
identifierStringThe identifier of the Rokt experience (e.g. "RoktExperience").
locationString?Optional location name for embedded placements (e.g. "Location1").
attributesMap<String, String>Map of attributes to pass to the placement.
modifierModifierCompose Modifier to customize layout, styling, and UI behavior.
mpRoktEventCallbackMpRoktEventCallbackOptional callback to handle placement events (load, unload, loading state).
configRoktConfig?Optional configuration for color mode, caching, etc.

Appendix D: Error handlingDirect link to Appendix D: Error handling

The IDSync API is intended to be central to your app's state and is designed to be fast and highly-available. Similar to how your app may prevent users from logging in, logging out, or modifying their state without an internet connection — treat these APIs as gating operations to maintain a consistent user state. The SDK+ will not retry API calls automatically, but provides callback APIs so you can do so according to your business logic.

If you do not implement error handling, you may see data consistency issues at scale.

IDSync error handling
import 'package:mparticle_flutter_sdk/identity/identity_api_result.dart';
import 'package:mparticle_flutter_sdk/identity/identity_api_error_response.dart';

mpInstance?.identity
.identify(identityRequest: identityRequest)
.then(
(IdentityApiResult successResponse) {
// Proceed with the identified user
},
onError: (error) {
var failureResponse = error as IdentityAPIErrorResponse;
// Inspect failureResponse.statusCode to determine the error type:
// - Check for network errors (device offline) and retry the request
// - Check for throttle errors (429) and retry with backoff
print('Identity error: $failureResponse');
}
);

Client-side error codes (iOS)Direct link to Client-side error codes (iOS)

The MPIdentityErrorResponseCode enum defines the following client-side codes:

MPIdentityErrorResponseCodeDescription
MPIdentityErrorResponseCodeRequestInProgressThe IDSync HTTP request was not performed as there is already an IDSync HTTP request in progress.
MPIdentityErrorResponseCodeClientSideTimeoutThe IDSync HTTP request failed due to a TCP connection timeout.
MPIdentityErrorResponseCodeClientNoConnectionThe IDSync HTTP request failed due to lack of network coverage.
MPIdentityErrorResponseCodeSSLErrorThe IDSync HTTP request failed due to an SSL configuration issue.
MPIdentityErrorResponseCodeOptOutThe IDSync HTTP request was not performed due to the SDK+ being disabled due to opt-out.
MPIdentityErrorResponseCodeUnknownThe IDSync HTTP request failed due to an unknown error.

Android error codesDirect link to Android error codes

The Android SDK+ returns IdentityApi.UNKNOWN_ERROR for client-side issues including device out of coverage, client-side timeout, or invalid identity requests. Check for THROTTLE_ERROR (HTTP 429) and retry with backoff when encountered.

HTTP status codesDirect link to HTTP status codes

ValueDescription
400The IDSync HTTP call failed due to an invalid request body.
401The IDSync HTTP call failed due to an authentication error. Verify that your API key is correct.
429The IDSync HTTP call was throttled and should be retried.
5xxThe IDSync HTTP call failed due to a Rokt server-side issue. Contact your account representative for additional information.

Appendix E: Passing session ID from web to nativeDirect link to Appendix E: Passing session ID from web to native

When a user journey spans both web and native platforms, you can maintain a consistent Rokt session by passing the session ID from the Web SDK+ to the Flutter SDK+. This is useful for hybrid flows where users complete an action in a WebView (such as a payment page) and return to the native app for confirmation.

Getting the session ID from Web SDK+Direct link to Getting the session ID from Web SDK+

After calling selectPlacements, the session ID is available on the selection context:

Retrieve sessionId from the selection context
const selection = await launcher.selectPlacements({
identifier: "checkout",
attributes: {
email: "user@example.com",
// ... other attributes
}
});

const sessionId = await selection.context.sessionId;
note

The session ID is a unique GUID assigned to the current user journey. It is useful for debugging and for correlating a user's activity across your web and native surfaces.

Pass the session ID to your native app using a deep link:

Deep-link to native app
const deepLink = `myapp://confirmation?sessionId=${encodeURIComponent(sessionId)}`;
window.location.href = deepLink;

Setting the session ID on iOSDirect link to Setting the session ID on iOS

Extract the session ID from the deep link and pass it to the SDK+ before calling selectPlacements. Add this to your AppDelegate.swift:

Handle deep link and set sessionId (iOS)
func handleDeepLink(url: URL) {
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
if let sessionId = components?.queryItems?.first(where: { $0.name == "sessionId" })?.value {
MParticle.sharedInstance().rokt.setSessionId(sessionId: sessionId)
}
// Proceed with your confirmation flow
}

Setting the session ID on AndroidDirect link to Setting the session ID on Android

Extract the session ID from the deep link and pass it to the SDK+ before calling selectPlacements. Add this to your MainActivity:

Handle deep link and set sessionId (Android)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

intent.data?.getQueryParameter("sessionId")?.let { sessionId ->
MParticle.getInstance()?.Rokt()?.setSessionId(sessionId)
}

// Proceed with your confirmation flow
}

NotesDirect link to Notes

  • Call setSessionId before selectPlacements to ensure the session is used.
  • Empty strings are ignored and will not update the session.
  • Always URL-encode the session ID when passing as a query parameter.

Appendix F: Configure Shoppable Ads payments (iOS only)Direct link to Appendix F: Configure Shoppable Ads payments (iOS only)

If you are not using Shoppable Ads, skip this step.

Shoppable Ads on iOS require a registered RoktPaymentExtension (native iOS) and support multiple payment methods. Registering the extension is mandatory for every Shoppable Ads placement, even if you offer only redirect-based methods. The registration and redirect-forwarding snippets are in the Show a Placement step's Shoppable Ads (interstitial) target.

MethodiOS setup
Apple PayApple Pay merchant ID passed as applePayMerchantId on RoktPaymentExtension. Optional.
PayPalBuilt into the Rokt SDK+ — no extra extension config. Requires redirect-URL forwarding.
Afterpay / ClearpayCustom URL scheme in Info.plist + matching urlScheme on RoktPaymentExtension + redirect-URL forwarding.
Card ForwardingPartner Payment Sharing API + partnerpaymentreference / last4digits attributes on selectShoppableAds.
note

Apple Pay is optional — Shoppable Ads also supports built-in PayPal and card forwarding without an Apple Pay merchant ID. At least one of applePayMerchantId or urlScheme must be provided when creating the extension. Configure stripePublishableKey in your mParticle Rokt kit settings; the kit forwards it to Rokt automatically.

To offer Apple Pay, create an Apple Pay merchant ID, configure your Xcode project, and generate a Payment Processing Certificate by following Apple Pay — iOS setup, then pass the merchant ID as applePayMerchantId.

8. Test Your Integration#

To confirm the SDK+ initializes and events log correctly:

1Enable verbose SDK+ logging#

Enable verbose SDK+ logging before initialization so you can see what's being sent.

Enable verbose SDK+ logging
// Enable mParticle debug logging at the Dart level
MparticleFlutterSdk.setLogLevel(LogLevel.verbose);

2Build and run against a development environment#

Build and run your app with the development environment set on the native side:

  • iOS: environment = .development (Swift) or MPEnvironmentDevelopment (Objective-C)
  • Android: MParticle.Environment.Development
  • Web: isDevelopmentMode: true

3Trigger selectPlacements#

Trigger selectPlacements on the screen where the placement should render and confirm the placement loads.

4Verify events#

Verify the events are logged and the identify call succeeds.

  • iOS: Check the Xcode console for Rokt SDK+ log output.
  • Android: Check Android Studio's Logcat for Rokt SDK+ log output.
  • Web: Open developer tools, go to the Network tab, filter by experiences, and confirm a /experiences request with status 200 fires.

TroubleshootingDirect link to Troubleshooting

If the placement doesn't render or events don't appear, check your platform's debug console for Rokt SDK+ errors. Common issues:

Initialization errorsDirect link to Initialization errors

  • Confirm the key and secret (iOS/Android) or API_KEY (Web) match the values from your Rokt account manager.
  • Confirm native SDK+ initialization runs before any selectPlacements or logEvent call from your Dart code.
  • On Android, confirm your root Activity extends FlutterFragmentActivity.
  • For Shoppable Ads on iOS, confirm RoktPaymentExtension is registered after SDK+ initialization and before selectShoppableAds.

Identity errorsDirect link to Identity errors

If the identify call's onError handler fires, inspect the IdentityAPIErrorResponse for the status code and retry the request according to your business logic. Without error handling you may see data consistency issues at scale.

Placement not renderingDirect link to Placement not rendering

  • Confirm the placement identifier (e.g. RoktExperience) matches what your Rokt account manager configured.
  • For embedded placements, confirm the embedded view identifier (e.g. RoktEmbedded1) matches the layout configuration.
  • Check that the attributes map contains at least email, firstname, lastname, billingzipcode, and confirmationref.
Was this article helpful?