Flutter SDK+ Integration Guide
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.
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.
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).
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.
Add the Rokt SDK+ pod to your ios/Podfile:
pod 'RoktSDKPlus', '~> 9.2'
In Xcode select File → Add Package Dependencies, enter the URL below, set the dependency rule to Up to Next Major Version, and add the RoktSDKPlus product to your app target. Or pin in Package.swift:
| Package | Repository URL | Product |
|---|---|---|
| Rokt SDK+ for iOS | https://github.com/ROKT/rokt-sdk-plus-ios.git | RoktSDKPlus |
dependencies: [
.package(url: "https://github.com/ROKT/rokt-sdk-plus-ios.git", from: "9.2.0"),
]
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.
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.
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.
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
}
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
| Identifier | Type | Description |
|---|---|---|
email | string | Pass the customer's raw, unhashed email address. |
mobile_number | string | Pass the customer's phone number in E.164 format. |
customerId | string | Pass your internal customer/account identifier. Send on every screen for logged-in users. |
other | string | Pass a SHA-256-hashed email. Only use when the raw email cannot be provided — do not pass both email and other. |
other2 | string | Pass 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:
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.
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
| Attribute | Type | Description |
|---|---|---|
firstname | string | Customer's first name. Used for personalization. |
lastname | string | Customer's last name. Used for personalization. |
mobile | string | Phone number formatted as 1112345678 or +1 (222) 345-6789. Used for identity resolution and relevance. |
age | integer | Customer's age. Alternate to dob. Used for eligibility and relevance. |
dob | string | Date of birth, yyyymmdd. Alternate to age. Used for eligibility and relevance. |
gender | string | Customer's gender. For example, M, F, Male, or Female. Used for relevance. |
title | string | Honorific. For example, Mr, Mrs, Ms. Used for personalization. |
language | string | ISO 639-1 language code associated with the purchase. Used for relevance. |
city | string | Billing city. Used for relevance. |
state | string | Billing state / province / region. Used for relevance and eligibility. |
zip | string | Full ZIP or postcode (US preference is ZIP+4). Used for identity resolution and relevance. |
country | string | ISO 3166-1 alpha-2 country code (e.g. US, GB, AU). Used for eligibility and relevance. |
newcustomer | boolean | Whether this is a first-time buyer. Used for relevance. |
customertype | string | Whether the user is authenticated (guest / logged_in). Used for relevance. |
loyaltytier | string | Partner loyalty program tier. Used for relevance and eligibility. |
loyaltyid | string | Loyalty program member ID. Used for identity resolution. |
lifetime_value | decimal | Customer's cumulative purchase value, as a string (e.g. "52.25"). Used for relevance. |
predictedltv | decimal | Predicted total lifetime value, typically from a partner ML model. Distinct from lifetime_value. Used for relevance. |
subscriptionstatus | string | Subscription state if applicable (active, trial, churned, paused, none). Used for relevance and eligibility. |
customersegment | string | Partner internal segmentation (e.g. vip, at_risk, new, reactivated). Used for relevance. |
utmsource | string | Marketing attribution source. Used for relevance. |
utmmedium | string | Marketing attribution medium. Used for relevance. |
utmcampaign | string | Marketing 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.
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.
import 'package:mparticle_flutter_sdk/events/screen_event.dart';
ScreenEvent screenEvent = ScreenEvent(eventName: 'homepage')
..customAttributes = {'custom-attribute': 'custom-value'};
mpInstance?.logScreenEvent(screenEvent);
Commerce events carry product-level details for the user's journey. Trigger a separate commerce event for each product action the customer takes.
Investing in full commerce event coverage is one of the highest-leverage things you can do during your integration. Each event tells Rokt something different about where the customer is in their journey: a product view signals exploration, an add-to-cart signals consideration, a checkout start signals purchase intent, and a completed purchase confirms conversion. With a richer signal, Rokt can personalize offers more effectively, measure placement performance accurately, and attribute conversions to the right touchpoints. Doing this work during your initial integration also avoids a retrofit later. The signal compounds over time: each event Rokt receives adds context used to sharpen personalization, improve attribution accuracy, and better resolve and segment your customer base on future visits.
Commerce events are logged with CommerceEvent, using a ProductActionType that identifies the customer action (viewing a product, adding to cart, starting checkout, completing a purchase, etc.).
Show all product action types
| Customer action | Product action constant |
|---|---|
| Product detail page viewed | ProductActionType.ViewDetail |
| Product clicked | ProductActionType.Click |
| Item added to cart | ProductActionType.AddToCart |
| Item removed from cart | ProductActionType.RemoveFromCart |
| Item added to wishlist | ProductActionType.AddToWishList |
| Item removed from wishlist | ProductActionType.RemoveFromWishlist |
| Checkout flow initiated | ProductActionType.Checkout |
| Checkout option selected | ProductActionType.CheckoutOption |
| Order confirmed | ProductActionType.Purchase |
| Order refunded | ProductActionType.Refund |
Tracking a commerce event takes three phases:
1Define the product#
Build a product with name, SKU, and price. Set additional fields like quantity, category, brand, and variant directly on the instance. On the Web target, use mParticle.eCommerce.createProduct instead — Flutter Web routes through the mParticle Web SDK.
Product product = Product(
name: 'Double Room - Econ Rate',
sku: 'econ-1',
price: 100.00,
);
product.quantity = 4;
product.category = 'room';
product.brand = 'lodge-o-rama';
product.variant = 'standard';
2Summarize the transaction#
Build a TransactionAttributes for Purchase, Checkout, and CheckoutOption events. On the Web target, use a plain transactionAttributes object literal with PascalCase keys. Order-level coupons belong here, not on individual products.
final TransactionAttributes transactionAttributes = TransactionAttributes(
transactionId: 'ORDER-12345',
revenue: 149.99,
tax: 12.50,
shipping: 5.99,
couponCode: 'SUMMER20',
);
3Log the commerce event#
Build a CommerceEvent with the product action type and your product(s), attach transactionAttributes when applicable, then call mpInstance?.logCommerceEvent. On Web, call mParticle.eCommerce.logProductAction (or logImpression for PLP impressions) instead. Pick the customer action you want to log:
Log a product listing (or category) page view as a product impression. Pass every visible product in a single call, and set the impression's name to the list / category name (Rokt uses this as listname).
| Field | Type | Required | Description |
|---|---|---|---|
Name | string | yes | List or category name (e.g. "Mens Running Shoes"). Becomes listname. |
Products | array | yes | Product objects. Set position to each item's 1-indexed rank. |
currency | string | yes | ISO 4217 currency code (passed as event-level customAttribute). |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
Product product = Product(
name: 'Trail Runner v3',
sku: 'SKU-001',
price: 129.95,
);
product.quantity = 1;
product.position = 1; // 1-indexed rank in the list
CommerceEvent event = CommerceEvent.withImpression(
impressionListName: 'Mens Running Shoes',
product: product,
);
event.customAttributes = {'currency': 'USD'};
mpInstance?.logCommerceEvent(event);
Log when a customer opens a product detail page.
| Field | Type | Required | Description |
|---|---|---|---|
productsku | string | yes | Product SKU. |
productname | string | yes | Display name. |
itemprice | decimal | yes | Per-unit price at the time of view. |
currency | string | yes | ISO 4217 currency code. |
listname | string | no | Set if the user arrived from a PLP. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
Product product = Product(
name: 'Trail Runner v3',
sku: 'SKU-001',
price: 129.95,
);
product.quantity = 1;
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.ViewDetail,
product: product,
);
event.customAttributes = {'currency': 'USD', 'listname': 'PLP-Running'};
mpInstance?.logCommerceEvent(event);
Log when a customer adds an item to the cart.
| Field | Type | Required | Description |
|---|---|---|---|
productsku | string | yes | Product SKU. |
quantity | integer | yes | Units added. |
itemprice | decimal | yes | Per-unit price at time of add. |
currency | string | yes | ISO 4217 currency code. |
couponCode | string | no | Order-level coupon, if applied at add-time. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
Product product = Product(
name: 'Trail Runner v3',
sku: 'SKU-001',
price: 129.95,
);
product.quantity = 1;
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.AddToCart,
product: product,
);
event.customAttributes = {'currency': 'USD'};
mpInstance?.logCommerceEvent(event);
Log when a customer removes an item from the cart.
| Field | Type | Required | Description |
|---|---|---|---|
productsku | string | yes | Product SKU. |
quantity | integer | yes | Units removed. |
currency | string | yes | ISO 4217 currency code. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
Product product = Product(
name: 'Trail Runner v3',
sku: 'SKU-001',
price: 129.95,
);
product.quantity = 1; // units removed
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.RemoveFromCart,
product: product,
);
event.customAttributes = {'currency': 'USD'};
mpInstance?.logCommerceEvent(event);
Log when the customer arrives on the cart page. Since cart page views do not have a native ProductActionType, use MPEvent with the event name "view_cart" and EventType.Other. Pass the full cart contents as custom attributes.
| Field | Type | Required | Description |
|---|---|---|---|
event_name | string | yes | Always "view_cart". |
event_type | EventType | yes | Use EventType.Other. |
cartitems | array | yes | Full cart contents as a real JSON array (don't stringify). |
cartitemcount | integer | yes | Number of cart lines. |
totalprice | decimal | yes | Cart total. |
currency | string | yes | ISO 4217 currency code. |
couponcode | string | no | Order-level promo, if applied. |
Each entry in the cartitems array has the following shape:
| Field | Type | Description |
|---|---|---|
cartitemid | string | Stable partner-side cart-line identifier. Usually equals productsku when there is one line per SKU; use a unique value if you allow multiple lines for the same SKU (e.g. gift-wrap variants). |
productsku | string | Product SKU / stock identifier. |
productname | string | Product display name. |
productcategory | string | Product category / taxonomy leaf. |
productbrand | string | Product brand. |
productvariant | string | Variant identifier (size, color, etc.). |
itemprice | decimal | Per-unit price at event time. |
unitprice | decimal | Per-unit list price pre-discount. Omit if equal to itemprice. |
quantity | integer | Units in this line. |
currency | string | ISO 4217 code. Omit if matches the top-level currency. |
couponcode | string | Coupon applied to this line (if any). Order-level promos belong in transactionAttributes.Coupon. |
productposition | integer | 1-indexed rank of the product within a list or search results. |
import 'package:mparticle_flutter_sdk/events/event_type.dart';
import 'package:mparticle_flutter_sdk/events/mp_event.dart';
MPEvent event = MPEvent(
eventName: 'view_cart',
eventType: EventType.Other)
..customAttributes = {
'cartitemcount': 3,
'totalprice': 169.85,
'currency': 'USD',
'couponcode': 'SUMMER20',
'cartitems': [
{'cartitemid': 'SKU-001', 'productsku': 'SKU-001', 'productname': 'Trail Runner v3', 'itemprice': 129.95, 'quantity': 1},
{'cartitemid': 'SKU-002', 'productsku': 'SKU-002', 'productname': 'Cushion Insole', 'itemprice': 19.95, 'quantity': 2},
],
};
mpInstance?.logEvent(event);
Log when the customer enters the checkout flow. Send all cart products and a transaction summary covering the cart total and any order-level coupon.
| Field | Type | Required | Description |
|---|---|---|---|
cartitems | array | yes | Full cart contents. |
totalprice | decimal | yes | Cart total before tax/shipping. |
cartitemcount | integer | yes | Number of cart lines. |
currency | string | yes | ISO 4217 currency code. |
couponCode | string | no | Order-level promo, if applied. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
import 'package:mparticle_flutter_sdk/events/transaction_attributes.dart';
Product product1 = Product(name: 'Trail Runner v3', sku: 'SKU-001', price: 129.95);
product1.quantity = 1;
Product product2 = Product(name: 'Cushion Insole', sku: 'SKU-002', price: 19.95);
product2.quantity = 2;
final TransactionAttributes transactionAttributes = TransactionAttributes(
revenue: 169.85,
couponCode: 'SUMMER20',
);
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.Checkout,
product: product1,
);
event.addProduct(product2);
event.transactionAttributes = transactionAttributes;
event.customAttributes = {'currency': 'USD', 'cartitemcount': 3};
mpInstance?.logCommerceEvent(event);
Log when the customer completes the shipping step. Pass option: 'shipping' along with the shipping selections as custom attributes.
| Field | Type | Required | Description |
|---|---|---|---|
cartitems | array | yes | Full cart contents. |
option | string | yes | Always "shipping" for this event. |
shippingmethod | string | yes | standard / express / next_day. |
zipcode | string | yes | Shipping ZIP / postcode. |
country | string | yes | ISO 3166-1 alpha-2 country code. |
totalprice | decimal | yes | Cart total. |
currency | string | yes | ISO 4217 currency code. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
Product product1 = Product(name: 'Trail Runner v3', sku: 'SKU-001', price: 129.95);
product1.quantity = 1;
Product product2 = Product(name: 'Cushion Insole', sku: 'SKU-002', price: 19.95);
product2.quantity = 2;
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.CheckoutOption,
product: product1,
);
event.addProduct(product2);
event.customAttributes = {
'option': 'shipping',
'shippingmethod': 'express',
'zipcode': '94103',
'country': 'US',
'totalprice': 169.85,
'currency': 'USD',
};
mpInstance?.logCommerceEvent(event);
Log when the customer completes the payment step. Pass option: 'payment' along with the payment method selected as custom attributes.
| Field | Type | Required | Description |
|---|---|---|---|
cartitems | array | yes | Full cart contents. |
option | string | yes | Always "payment" for this event. |
paymenttype | string | yes | credit_card / paypal / apple_pay / etc. |
payment_method | string | no | Specific method when relevant (e.g. card brand). |
paymentServiceProvider | string | no | PSP identifier (e.g. stripe). Must be camelCase. |
ccbin | string | no | First 6-8 digits of the card, if a card was used. |
totalprice | decimal | yes | Cart total. |
currency | string | yes | ISO 4217 currency code. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
Product product1 = Product(name: 'Trail Runner v3', sku: 'SKU-001', price: 129.95);
product1.quantity = 1;
Product product2 = Product(name: 'Cushion Insole', sku: 'SKU-002', price: 19.95);
product2.quantity = 2;
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.CheckoutOption,
product: product1,
);
event.addProduct(product2);
event.customAttributes = {
'option': 'payment',
'paymenttype': 'credit_card',
'payment_method': 'visa',
'paymentServiceProvider': 'stripe',
'ccbin': '424242',
'totalprice': 169.85,
'currency': 'USD',
};
mpInstance?.logCommerceEvent(event);
Log when an order is confirmed. Send the full cart and a transaction summary identifying the order, revenue, tax, shipping, and any order-level coupon.
| Field | Type | Required | Description |
|---|---|---|---|
cartitems | array | yes | Full cart contents at time of order. |
transactionId | string | yes | Order / transaction identifier. |
totalprice | decimal | yes | Order total (Revenue). |
tax | decimal | yes | Total tax on the order. |
shipping | decimal | yes | Shipping cost. |
currency | string | yes | ISO 4217 currency code. |
couponCode | string | no | Order-level promo, if applied. |
cartitemcount | integer | no | Number of cart lines. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
import 'package:mparticle_flutter_sdk/events/transaction_attributes.dart';
Product product1 = Product(name: 'Trail Runner v3', sku: 'SKU-001', price: 129.95);
product1.quantity = 1;
Product product2 = Product(name: 'Cushion Insole', sku: 'SKU-002', price: 19.95);
product2.quantity = 2;
final TransactionAttributes transactionAttributes = TransactionAttributes(
transactionID: 'ORDER-10482',
revenue: 169.85,
tax: 14.20,
shipping: 5.99,
couponCode: 'SUMMER20',
);
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.Purchase,
product: product1,
);
event.addProduct(product2);
event.transactionAttributes = transactionAttributes;
event.customAttributes = {'currency': 'USD', 'cartitemcount': 3};
mpInstance?.logCommerceEvent(event);
Log when an order (or a line within it) is refunded. Send only the products being refunded plus a transaction summary referencing the original order ID.
| Field | Type | Required | Description |
|---|---|---|---|
productsku | string | yes | SKU of the refunded line(s). |
quantity | integer | yes | Units refunded. |
transactionId | string | yes | Original order ID being refunded against. |
totalprice | decimal | yes | Refunded amount. |
currency | string | yes | ISO 4217 currency code. |
import 'package:mparticle_flutter_sdk/events/product.dart';
import 'package:mparticle_flutter_sdk/events/commerce_event.dart';
import 'package:mparticle_flutter_sdk/events/product_action_type.dart';
import 'package:mparticle_flutter_sdk/events/transaction_attributes.dart';
Product refundedProduct = Product(
name: 'Trail Runner v3',
sku: 'SKU-001',
price: 129.95,
);
refundedProduct.quantity = 1; // units refunded
final TransactionAttributes transactionAttributes = TransactionAttributes(
transactionID: 'ORDER-10482', // original order id
revenue: 129.95, // refunded amount
);
CommerceEvent event = CommerceEvent.withProduct(
productActionType: ProductActionType.Refund,
product: refundedProduct,
);
event.transactionAttributes = transactionAttributes;
event.customAttributes = {'currency': 'USD'};
mpInstance?.logCommerceEvent(event);
Log when the customer runs a site search. Site search is a Web-only standard event — iOS and Android targets don't have a native equivalent.
Site search is a Web-only standard event. For Flutter iOS targets, log a custom event with EventType.Search instead (see the Custom events option in this selector).
Track custom events using MPEvent, passing an event name, event type, and optional custom attributes.
Show custom event types
| Type | Use for |
|---|---|
EventType.Navigation | User navigation flows and screen transitions within your app. |
EventType.Location | Location-based interactions and movements. |
EventType.Search | Search queries and search-related actions. |
EventType.Transaction | Financial transactions and purchase-related activity. |
EventType.UserContent | User-generated content like reviews, comments, or posts. |
EventType.UserPreference | User settings, preferences, and customization choices. |
EventType.Social | Social media interactions and sharing activities. |
EventType.Other | Anything that doesn't fit the categories above. |
import 'package:mparticle_flutter_sdk/events/event_type.dart';
import 'package:mparticle_flutter_sdk/events/mp_event.dart';
MPEvent event = MPEvent(
eventName: 'video_watched',
eventType: EventType.Navigation)
..customAttributes = {
'category': 'Destination Intro',
'title': 'Paris',
};
mpInstance?.logEvent(event);
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
| Attribute | Type | Description |
|---|---|---|
email | string | Customer email (unhashed). Used for identity resolution. |
firstname | string | Customer first name. Used for personalization. |
lastname | string | Customer last name. Used for personalization. |
mobile | string | Customer mobile number in E.164 format. Used for identity resolution. |
confirmationref | string | Order / confirmation reference number. Used for relevance and deduplication. |
currency | string | Transaction currency (ISO 4217, e.g. USD, GBP, AUD). Used for relevance. |
country | string | ISO 3166-1 alpha-2 country code. Used for eligibility and relevance. |
language | string | Customer's preferred language (ISO 639-1). Used for relevance. |
totalprice | decimal | Total cart value including tax and shipping. Used for relevance. |
amount | string | Cart subtotal before tax and shipping. Distinct from totalprice. Used for relevance and Shoppable Ads. |
cartitemcount | integer | Number of items in the cart. Used for relevance. |
cartItems | array | Structured array of cart-line objects (Flutter Web only). See Cart items under Commerce Events. Used for relevance. |
couponcode | string | Promo code applied to the order, if any. Used for relevance. |
newcustomer | boolean | Whether this is a first-time buyer. Used for relevance. |
customertype | string | guest or logged_in. Used for relevance. |
lifetime_value | decimal | Customer's cumulative purchase value (e.g. "2340.00"). Used for relevance. |
subscriptionstatus | string | Subscription state if applicable (active, trial, churned, paused, none). Used for relevance and eligibility. |
customersegment | string | Partner internal segmentation (e.g. vip, at_risk, new, reactivated). Used for relevance. |
paymenttype | string | Payment method selected (credit_card, paypal, apple_pay, etc.). Used for Pay+ eligibility and Shoppable Ads payment method prioritization. |
paymentServiceProvider | string | Payment services offered on the page (apple_pay, paypal, card). Used for Pay+ eligibility. |
ccbin | string | Credit card BIN (6-8 digits). Used for relevance. |
billingaddress1 | string | Billing street address. Used for identity resolution and relevance. |
billingaddress2 | string | Billing apartment / unit. Used for identity resolution. |
billingcity | string | Billing city. Used for relevance. |
billingstate | string | Billing state or province. Used for relevance. |
billingzipcode | string | Billing ZIP / postcode. Used for identity resolution and relevance. |
shippingmethod | string | Shipping method selected (standard, express, next_day). Used for relevance. |
shippingaddress1 | string | Shipping street address. Used for relevance and Shoppable Ads order fulfillment. |
shippingcity | string | Shipping city. Used for relevance and Shoppable Ads order fulfillment. |
shippingstate | string | Shipping state or province. Used for relevance and Shoppable Ads order fulfillment. |
shippingzipcode | string | Shipping ZIP or postcode. Used for relevance and Shoppable Ads order fulfillment. |
shippingcountry | string | Shipping country (ISO 3166-1 alpha-2). Used for relevance and Shoppable Ads order fulfillment. |
adsexperience | string | Pass "shoppable" when deliberately selecting a Shoppable Ads experience. |
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:
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,
);
Embedded placements render inline at a fixed position in your app that you control (for example, above the payment options on a cart screen). Both Thanks and Pay+ use embedded placements, but Pay+ must use embedded placements.
Use the RoktLayout widget to embed a placement in your Flutter UI. The onLayoutCreated callback fires when the widget is created.
import 'package:mparticle_flutter_sdk/mparticle_flutter_sdk.dart';
final attributes = {
'email': 'j.smith@example.com',
'firstname': 'Jenny',
'lastname': 'Smith',
'billingzipcode': '90210',
'confirmationref': '54321',
};
const RoktLayout(
placeholderName: 'RoktEmbedded1',
onLayoutCreated: () {
// Layout created
}
);
mpInstance?.rokt.selectPlacements(
identifier: 'RoktExperience',
attributes: attributes,
);
For Pay+ placements, include paymenttype and paymentServiceProvider in the selectPlacements call on each screen. paymentServiceProvider communicates what payment methods are available on the payment screen; paymenttype communicates what method the user paid with.
Interstitial placements are rendered between the payment and confirmation screens, allowing customers to purchase additional products. Interstitial placements are used by Shoppable Ads.
Interstitial placements (Shoppable Ads) are supported on iOS only in the Flutter SDK+. The Android path does not support interstitial placements. On Web, interstitial placements use the <rokt-thank-you> wrapper described below.
Shoppable Ads require mparticle_flutter_sdk 2.0.0 or later and RoktSDKPlus ~> 9.2 from rokt-sdk-plus-ios on iOS. If you are still on 1.x, follow the SDK+ 2.0 migration guide before proceeding.
The RoktPaymentExtension used below ships with RoktSDKPlus (added to your ios/Podfile in Step 1) — no separate pod is required.
1Register the payment extension in AppDelegate.swift#
In ios/Runner/AppDelegate.swift, register the payment extension after SDK+ initialization:
import mParticle_Apple_SDK
import RoktPaymentExtension
// In application(_:didFinishLaunchingWithOptions:), after MParticle.sharedInstance().start(with: options)
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)
}
Configure stripePublishableKey in your mParticle Rokt kit settings; the kit forwards it to Rokt automatically. In code, provide only the Apple Pay merchant ID and/or urlScheme. At least one of applePayMerchantId or urlScheme must be provided. Apple Pay is optional — Shoppable Ads also supports built-in PayPal and card forwarding without it.
You must call registerPaymentExtension after SDK+ initialization and before calling selectShoppableAds from your Dart code. If no payment extension is registered, selectShoppableAds will fire a PlacementFailure event.
2Forward redirect URLs (Afterpay, Clearpay, PayPal)#
If you offer Afterpay, Clearpay, or PayPal, those methods redirect back to your app after authentication. Forward incoming URLs to Rokt from your native iOS SceneDelegate (or AppDelegate), in addition to any existing mParticle URL handling. Skip this step if you only offer Apple Pay or card forwarding.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for urlContext in URLContexts {
if MParticle.sharedInstance().rokt.handleURLCallback(with: urlContext.url) {
return
}
MParticle.sharedInstance().handleURLContext(urlContext)
}
}
Afterpay / Clearpay also require the matching URL scheme registered under CFBundleURLTypes in Info.plist and passed as urlScheme when creating RoktPaymentExtension (see the previous step).
3Call selectShoppableAds from your Dart code#
Call selectShoppableAds once all required attributes are available. Shoppable Ads always display as an overlay — no embedded views are needed.
final attributes = {
'email': 'j.smith@example.com',
'firstname': 'Jenny',
'lastname': 'Smith',
'confirmationref': 'ORD-12345',
'amount': '52.25',
'currency': 'USD',
'paymenttype': 'visa',
'shippingaddress1': '123 Main St',
'shippingcity': 'New York',
'shippingstate': 'NY',
'shippingzipcode': '10001',
'shippingcountry': 'US',
};
mpInstance?.rokt.selectShoppableAds(
identifier: 'ConfirmationPage',
attributes: attributes,
);
Shoppable Ads events are delivered via the MPRoktEvents EventChannel — see the Events API section below.
Optional functionsDirect link to Optional functions
| Function | Purpose |
|---|---|
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.
// 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,
);
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.
final EventChannel roktEventChannel = EventChannel('MPRoktEvents');
roktEventChannel.receiveBroadcastStream().listen((dynamic event) {
debugPrint('rokt_event: $event');
});
Standard eventsDirect link to Standard events
Show all standard events
| Event | Description | Params |
|---|---|---|
| ShowLoadingIndicator | Triggered before the SDK+ calls the Rokt backend. | |
| HideLoadingIndicator | Triggered when the SDK+ receives a success or failure from the Rokt backend. | |
| PlacementInteractive | Triggered when a placement has been rendered and is interactable. | identifier: String |
| PlacementReady | Triggered when a placement is ready to display but has not rendered content yet. | identifier: String |
| OfferEngagement | Triggered when the user engages with the offer. | identifier: String |
| PositiveEngagement | Triggered when the user positively engages with the offer. | identifier: String |
| FirstPositiveEngagement | Triggered when the user positively engages with the offer for the first time. | identifier: String, fulfillmentAttributes: FulfillmentAttributes |
| OpenUrl | Triggered when the user presses a URL that is configured to be sent to the partner app. | identifier: String, url: String |
| PlacementClosed | Triggered when a placement is closed by the user. | identifier: String |
| PlacementCompleted | Triggered 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 |
| PlacementFailure | Triggered when a placement could not be displayed due to some failure or when no placements are available to show. | identifier: String (optional) |
| EmbeddedSizeChanged | Triggered when an embedded placement's height changes. | identifier: String, selectedHeight: Double |
| CartItemInstantPurchase | Triggered when the catalog item purchase is initiated by the user. | identifier: String, catalogItemId: String, cartItemId: String, totalPrice: String, currency: String |
| CartItemInstantPurchaseInitiated | Purchase flow started — user tapped "Buy" (Shoppable Ads, iOS only). | identifier: String, catalogItemId: String, cartItemId: String |
| CartItemInstantPurchaseFailure | Purchase failed (Shoppable Ads, iOS only). | identifier: String, catalogItemId: String, cartItemId: String, error: String |
| CartItemDevicePay | Apple Pay / device payment triggered (Shoppable Ads, iOS only). | identifier: String, catalogItemId: String, cartItemId: String, paymentProvider: String |
| InstantPurchaseDismissal | User 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
| Value | Description |
|---|---|
light | Application is in Light Mode |
dark | Application is in Dark Mode |
system | Application defaults to System Color Mode |
final roktConfig = RoktConfig(
colorMode: ColorMode.light,
);
mpInstance?.rokt.selectPlacements(
identifier: 'RoktExperience',
attributes: attributes,
roktConfig: roktConfig,
);
EdgeToEdgeDisplay (Android only)Direct link to EdgeToEdgeDisplay (Android only)
| Value | Description |
|---|---|
true (default) | Application supports Edge to Edge display mode |
false | Application 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:
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
| Parameter | Description |
|---|---|
cacheDurationInSeconds | Optional 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. |
cacheAttributes | Optional attributes to be used as cache key. If null, all attributes sent in selectPlacements will be used as the cache key. |
// 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.
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)
}
}
| Parameter | Type | Description |
|---|---|---|
sdkTriggered | Bool | Controls when the placement should be triggered. |
identifier | String | The Rokt placement identifier (e.g., "RoktExperience"). |
locationName | String? | Optional location name for embedded placements (e.g., "RoktEmbedded1"). |
attributes | [String: String] | Dictionary of attributes to pass to the placement. |
config | RoktConfig? | 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.
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
| Parameter | Type | Description |
|---|---|---|
sdkTriggered | Boolean | Controls when the placement should be triggered. |
identifier | String | The identifier of the Rokt experience (e.g. "RoktExperience"). |
location | String? | Optional location name for embedded placements (e.g. "Location1"). |
attributes | Map<String, String> | Map of attributes to pass to the placement. |
modifier | Modifier | Compose Modifier to customize layout, styling, and UI behavior. |
mpRoktEventCallback | MpRoktEventCallback | Optional callback to handle placement events (load, unload, loading state). |
config | RoktConfig? | 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.
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:
| MPIdentityErrorResponseCode | Description |
|---|---|
MPIdentityErrorResponseCodeRequestInProgress | The IDSync HTTP request was not performed as there is already an IDSync HTTP request in progress. |
MPIdentityErrorResponseCodeClientSideTimeout | The IDSync HTTP request failed due to a TCP connection timeout. |
MPIdentityErrorResponseCodeClientNoConnection | The IDSync HTTP request failed due to lack of network coverage. |
MPIdentityErrorResponseCodeSSLError | The IDSync HTTP request failed due to an SSL configuration issue. |
MPIdentityErrorResponseCodeOptOut | The IDSync HTTP request was not performed due to the SDK+ being disabled due to opt-out. |
MPIdentityErrorResponseCodeUnknown | The 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
| Value | Description |
|---|---|
| 400 | The IDSync HTTP call failed due to an invalid request body. |
| 401 | The IDSync HTTP call failed due to an authentication error. Verify that your API key is correct. |
| 429 | The IDSync HTTP call was throttled and should be retried. |
| 5xx | The 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:
const selection = await launcher.selectPlacements({
identifier: "checkout",
attributes: {
email: "user@example.com",
// ... other attributes
}
});
const sessionId = await selection.context.sessionId;
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.
Passing to native app via deep linkDirect link to Passing to native app via deep link
Pass the session ID to your native app using a deep link:
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:
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:
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
setSessionIdbeforeselectPlacementsto 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.
| Method | iOS setup |
|---|---|
| Apple Pay | Apple Pay merchant ID passed as applePayMerchantId on RoktPaymentExtension. Optional. |
| PayPal | Built into the Rokt SDK+ — no extra extension config. Requires redirect-URL forwarding. |
| Afterpay / Clearpay | Custom URL scheme in Info.plist + matching urlScheme on RoktPaymentExtension + redirect-URL forwarding. |
| Card Forwarding | Partner Payment Sharing API + partnerpaymentreference / last4digits attributes on selectShoppableAds. |
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 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) orMPEnvironmentDevelopment(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/experiencesrequest 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
keyandsecret(iOS/Android) orAPI_KEY(Web) match the values from your Rokt account manager. - Confirm native SDK+ initialization runs before any
selectPlacementsorlogEventcall from your Dart code. - On Android, confirm your root Activity extends
FlutterFragmentActivity. - For Shoppable Ads on iOS, confirm
RoktPaymentExtensionis registered after SDK+ initialization and beforeselectShoppableAds.
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, andconfirmationref.