Skip to main content

MAUI SDK+ Integration Guide

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 MAUI 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.

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

Add the SDK+ packages to your project:

Add SDK+ packages
dotnet add package mParticle.MAUI
dotnet add package mParticle.MAUI.Kits.Rokt
dotnet add package mParticle.MAUI.Kits.Rokt.Payments

mParticle.MAUI.Kits.Rokt.Payments already includes the core Rokt kit transitively.

note

For Android you also need to ensure your activity extends MauiAppCompatActivity.

2. Initialize the Rokt SDK+#

Insert the following initialization snippet in your application startup. The SDK+ must be initialized before any other SDK+ API calls. Replace your-key and your-secret with the key and secret provided by your Rokt team.

SDK+ initialization
using mParticle.MAUI;

string key = "";
string secret = "";
#if __ANDROID__
key = "your-key";
secret = "your-secret";
#elif __IOS__
key = "your-key";
secret = "your-secret";
#endif

// Initialize the SDK+
var options = new MParticleOptions()
{
ApiKey = key,
ApiSecret = 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 = mParticle.MAUI.Environment.Development;

// Enter your custom subdomain if you are using a first-party domain configuration (optional)
options.NetworkOptions = new NetworkOptions()
{
CustomBaseUrl = "https://rkt.example.com"
};

// Identify the current user:
var identifyRequest = new IdentityApiRequest();
identifyRequest.UserIdentities = new Dictionary<UserIdentity, string>()
{
#if __ANDROID__
// Preferred: pass the customer's raw, unhashed email.
// If you can only provide a SHA-256-hashed email, use UserIdentity.Other instead — do not pass both.
{ UserIdentity.Email, "j.smith@example.com" },
{ UserIdentity.Other, "SHA-256 hashed email" }, // only if raw email unavailable
// If you can only provide a SHA-256-hashed mobile number, use Other2 instead of MobileNumber — do not pass both.
{ UserIdentity.Other2, "SHA-256 hashed mobile number" }, // only if raw mobile unavailable
{ UserIdentity.MobileNumber, "+13125551515" },
{ UserIdentity.CustomerId, "cust_10482" }
#elif __IOS__
// Preferred: pass the customer's raw, unhashed email.
// If you can only provide a SHA-256-hashed email, use UserIdentity.Other instead — do not pass both.
{ UserIdentity.Email, "j.smith@example.com" },
{ UserIdentity.Other, "SHA-256 hashed email" }, // only if raw email unavailable
// Customer phone number in E.164 format.
{ UserIdentity.MobileNumber, "+13125551515" },
// If you can only provide a SHA-256-hashed mobile number, use Other2 instead of MobileNumber — do not pass both.
{ UserIdentity.Other2, "SHA-256 hashed mobile number" }, // only if raw mobile unavailable
{ UserIdentity.CustomerId, "cust_10482" }
#endif
};

// If the user is identified with their email address, set additional user attributes.
options.IdentifyRequest = identifyRequest;

OnUserIdentified onIdentifyComplete = newUser =>
{
if (newUser != null)
{
newUser.SetUserAttribute("example attribute key", "example attribute value");
}
};
options.IdentityStateListener = onIdentifyComplete;

// Register the Rokt kit with mParticle before initialization
RoktKit.Register();

MParticle.Instance.Initialize(options);

When inserting the initialization snippet into your application startup, you will see customizable fields for:

1Entering your Rokt key and secret#

Set your-key and your-secret inside the platform-specific blocks to the key and secret values provided by your Rokt account manager.

2Setting your data environment#

Set options.Environment to mParticle.MAUI.Environment.Development while testing to route data to the Development environment, and mParticle.MAUI.Environment.Production to send live customer activity to Production.

3Entering a custom first-party domain#

Follow the instructions in First-Party Domain Configuration, and set options.NetworkOptions.CustomBaseUrl to your custom subdomain before calling MParticle.Instance.Initialize(options). Omit options.NetworkOptions to send traffic to Rokt's default endpoints.

4Identifying your user and setting attributes#

In identifyRequest.UserIdentities, pass the user's raw, un-hashed email via UserIdentity.Email. For hashed emails and other identifiers, see Supported user identifiers. Once identified, use the IdentityStateListener callback to set additional user attributes — see User attributes for the recommended list.

IdentityStateListener
OnUserIdentified onIdentifyComplete = newUser =>
{
if (newUser != null)
{
newUser.SetUserAttribute("example attribute key", "example attribute value");
}
};
options.IdentityStateListener = onIdentifyComplete;
note

Always include identifyRequest in the initialization snippet. If you don't have the user's email at initialization, omit the UserIdentity.Email entry — the SDK+ will still initialize, and you can identify the user later via Identify the user. See Error handling for how to handle identity failures — without error handling you may see data consistency issues at scale.

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
FieldTypeDescription
emailstringPass the customer's raw, unhashed email address.
mobilestringPass 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. (Android path only.)
other2stringPass a SHA-256-hashed mobile number. Only use when the raw mobile number cannot be provided — do not pass both mobile and other2. (Android path only.)
emailSha256stringPass a SHA-256-hashed email. Only use when the raw email cannot be provided — do not pass both email and emailSha256. (iOS path only.)
mobileSha256stringPass a SHA-256-hashed mobile number. Only use when the raw mobile number cannot be provided — do not pass both mobile and mobileSha256. (iOS path only.)

To identify the user:

1Create an identifyRequest object#

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

2Set additional user attributes via AddSuccessListener#

To set additional user attributes, use the AddSuccessListener callback on the identify result. If the identifyRequest succeeds, any user attributes you set inside the listener are assigned to the identified user.

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

Pass the identifyRequest to the method that matches the user's action:

  • MParticle.Instance.Identity.Login: call when the user logs in or creates an account.
  • MParticle.Instance.Identity.Identify: call when you obtain the user's email mid-session without a login transition (for example, a guest enters their email at checkout).
  • MParticle.Instance.Identity.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, for a user named Jane Smith with email j.smith@example.com, mobile number +13125551515, and customer ID cust_10482:

Identify the user
// 1. Create the identifyRequest object
var identifyRequest = new IdentityApiRequest();
identifyRequest.UserIdentities = new Dictionary<UserIdentity, string>()
{
#if __ANDROID__
// Preferred: pass the customer's raw, unhashed email.
// If you can only provide a SHA-256-hashed email, use UserIdentity.Other instead — do not pass both.
{ UserIdentity.Email, "j.smith@example.com" },
{ UserIdentity.Other, "SHA-256 hashed email" }, // only if raw email unavailable
// If you can only provide a SHA-256-hashed mobile number, use Other2 instead of MobileNumber — do not pass both.
{ UserIdentity.Other2, "SHA-256 hashed mobile number" }, // only if raw mobile unavailable
{ UserIdentity.MobileNumber, "+13125551515" },
{ UserIdentity.CustomerId, "cust_10482" }
#elif __IOS__
// Preferred: pass the customer's raw, unhashed email.
// If you can only provide a SHA-256-hashed email, use UserIdentity.Other instead — do not pass both.
{ UserIdentity.Email, "j.smith@example.com" },
{ UserIdentity.Other, "SHA-256 hashed email" }, // only if raw email unavailable
// Customer phone number in E.164 format.
{ UserIdentity.MobileNumber, "+13125551515" },
// If you can only provide a SHA-256-hashed mobile number, use Other2 instead of MobileNumber — do not pass both.
{ UserIdentity.Other2, "SHA-256 hashed mobile number" }, // only if raw mobile unavailable
{ UserIdentity.CustomerId, "cust_10482" }
#endif
};

// 2. User attributes are set using the AddSuccessListener callback
// 3. Call one of the following methods that best matches the user's action:
MParticle.Instance.Identity.Login(identifyRequest)
.AddSuccessListener(result =>
{
result.User.SetUserAttribute("firstname", "Jane");
result.User.SetUserAttribute("lastname", "Smith");
}); // Call when the user logs in or creates an account
MParticle.Instance.Identity.Identify(identifyRequest)
.AddSuccessListener(result =>
{
result.User.SetUserAttribute("firstname", "Jane");
result.User.SetUserAttribute("lastname", "Smith");
}); // Call when you obtain the user's email mid-session, but not during a login
MParticle.Instance.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
using mParticle.MAUI;

// 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 = MParticle.Instance.Identity.CurrentUser;

// Once you have successfully set the current user, you can set user attributes with:
currentUser.SetUserAttribute("custom-attribute-name", "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("firstname", "John");
currentUser.SetUserAttribute("lastname", "Doe");
// Phone numbers can be formatted either as '1234567890', or '+1 (234) 567-8901'
currentUser.SetUserAttribute("mobile", "3125551515");
currentUser.SetUserAttribute("age", "33");
currentUser.SetUserAttribute("gender", "M");
currentUser.SetUserAttribute("billingcity", "Brooklyn");
currentUser.SetUserAttribute("billingstate", "NY");
currentUser.SetUserAttribute("billingzipcode", "123456");
currentUser.SetUserAttribute("dob", "yyyymmdd");
currentUser.SetUserAttribute("title", "Mr");
currentUser.SetUserAttribute("language", "en");
currentUser.SetUserAttribute("predictedltv", "136.23");

// You can create a user attribute to contain a list of values
currentUser.SetUserAttribute("favorite-genres", string.Join(", ", new string[] { "documentary", "comedy", "romance", "drama" }));

// To remove a user attribute, call RemoveUserAttribute and pass in the attribute name.
currentUser.RemoveUserAttribute("attribute-to-remove");

User attributesDirect link to User attributes

Set as many of the following as you can collect:

Show all user attributes
FieldTypeDescription
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.
billingcitystringBilling city. Used for relevance.
billingstatestringBilling state / province / region. Used for relevance and eligibility.
billingzipcodestringFull ZIP or postcode (US preference is ZIP+4). Used for identity resolution and relevance.
billingaddress1stringBilling street address line 1. Used for identity resolution and relevance.
billingaddress2stringBilling street address line 2. Used for identity resolution.
countrystringISO 3166-1 alpha-2 country code (e.g. US, GB, AU). Used for eligibility and relevance.
birthyearintegerCustomer's birth year (e.g. 1990). 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.
predictedltvdecimalPredicted total lifetime value, typically from a partner ML model. 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.
acquisitionchannelstringChannel through which the customer was acquired. Used for relevance.

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

5. Track Funnel Events#

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

Event category

Call MParticle.Instance.LogScreen with the name of the screen (e.g. "homepage", "product_detail_page"). Include any additional custom attributes in the info dictionary.

Log a screen view
MParticle.Instance.LogScreen(
"homepage",
new Dictionary<string, string>() { { "custom-attribute", "custom-value" } }
);

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 screen in a staging (or testing) environment.
  • prod.rokt.conf: A confirmation screen in a production environment.
  • stg.rokt.payments: A payments screen in a staging (or testing) environment.
  • prod.rokt.payments: A payments screen in a production environment.

Call SelectPlacements as early as the screen loads and once all relevant attributes are available. At minimum, pass email, firstname, lastname, billingzipcode, and confirmationref. See Placement attributes for the full list.

Pay+

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.

Placement attributesDirect link to Placement attributes

Pass these attributes in the attributes dictionary of SelectPlacements. Always supply the most recent value — attributes passed here override any earlier SetUserAttribute calls.

Show all placement attributes
FieldTypeDescription
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.
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.
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.
paymentServiceProviderstringComma-separated list of payment methods accepted on the page (e.g. applepay,paypal,cardpayment). Values must be lowercase with no spaces. See Payment Service Provider for the full list of accepted values. Used for Pay+ eligibility.
ccbinstringCredit card BIN (6-8 digits). Used for relevance.
billingnamestringBilling name. Used for identity resolution.
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.
shippingnamestringShipping name. Used for relevance.
shippingaddress1stringShipping street address. Used for relevance.
shippingcitystringShipping city. Used for relevance.
shippingstatestringShipping state or province. Used for relevance.
shippingzipcodestringShipping ZIP or postcode. Used for relevance.
shippingcountrystringShipping country (ISO 3166-1 alpha-2). Used for relevance.
cartItemsarrayStructured array of cart-line objects. Used for relevance.
adsexperiencestringPass "shoppable" when deliberately targeting 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
using mParticle.MAUI;

var attributes = new Dictionary<string, string>
{
// Identity
["email"] = "j.smith@example.com",
["firstname"] = "Jenny",
["lastname"] = "Smith",
["mobile"] = "+13125551515",

// Transaction
["confirmationref"] = "54321",
["currency"] = "USD",
["country"] = "US",
["language"] = "en",
["totalprice"] = "149.99",
["couponCode"] = "SUMMER20",

// Customer context
["newcustomer"] = "false",
["customertype"] = "logged_in",
["value"] = "2340.00",
["subscriptionstatus"] = "active",
["customersegment"] = "vip",

// Payment (include paymenttype and paymentServiceProvider for Pay+)
["paymenttype"] = "credit_card",
["paymentServiceProvider"] = "cardpayment",
["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"
};

MParticle.Instance.Rokt.SelectPlacements(
identifier: "RoktExperience",
attributes: attributes
);

Optional functionsDirect link to Optional functions

FunctionPurpose
MParticle.Instance.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).

SelectPlacements with RoktConfig
using mParticle.MAUI;

var roktConfig = new RoktConfig()
{
ColorMode = RoktConfig.RoktColorMode.Light
};

MParticle.Instance.Rokt.SelectPlacements(
identifier: "RoktExperience",
attributes: attributes,
config: 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

The SDK+ provides placement lifecycle events through the MParticle.Instance.Rokt API. Use Events to subscribe per placement identifier and respond to loading state, readiness, interaction, completion, and failures.

Subscribe to placement events
void HandleRoktEvent(object roktEvent)
{
switch (roktEvent.GetType().Name)
{
case "RoktShowLoadingIndicator":
Console.WriteLine("Rokt is loading...");
break;
case "RoktHideLoadingIndicator":
Console.WriteLine("Rokt finished loading.");
break;
case "RoktPlacementReady":
Console.WriteLine("Placement is ready.");
break;
case "RoktPlacementInteractive":
Console.WriteLine("Placement is interactive.");
break;
case "RoktPositiveEngagement":
case "RoktFirstPositiveEngagement":
Console.WriteLine("User positively engaged.");
break;
case "RoktPlacementCompleted":
Console.WriteLine("Placement completed.");
break;
case "RoktPlacementFailure":
Console.WriteLine("Placement failed or no fill.");
break;
default:
Console.WriteLine($"Unhandled event: {roktEvent.GetType().Name}");
break;
}
}

MParticle.Instance.Rokt.Events("RoktExperience", roktEvent =>
{
HandleRoktEvent(roktEvent);
});

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.placementId: string
PlacementReadyTriggered when a placement is ready to display but has not rendered content yet.placementId: string
OfferEngagementTriggered when the user engages with the offer.placementId: string
PositiveEngagementTriggered when the user positively engages with the offer.placementId: string
FirstPositiveEngagementTriggered when the user positively engages with the offer for the first time.placementId: string, fulfillmentAttributes: Dictionary<string, string>
OpenUrlTriggered when the user presses a URL that is configured to be sent to the partner app.placementId: string, url: string
PlacementClosedTriggered when a placement is closed by the user.placementId: 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.placementId: string
PlacementFailureTriggered when a placement could not be displayed due to some failure or when no placements are available to show.placementId: string (optional)
CartItemInstantPurchaseTriggered when the catalog item purchase is initiated by the user.placementId: string, cartItemId: string, catalogItemId: string, currency: string, description: string, linkedProductId: string, totalPrice: double, quantity: int, unitPrice: double

7. Configure Apple Pay (iOS only)#

Apple Pay is required for Shoppable Ads on iOS. If you are not using Shoppable Ads, skip this step.

Before registering the payment extension, create an Apple Pay merchant ID, configure your Xcode project, and generate a Payment Processing Certificate.

Follow the steps in Apple Pay — iOS setup, then register RoktPaymentExtension in your iOS-specific platform code. In a MAUI project, place this in your iOS platform AppDelegate.cs (or in MauiProgram.cs inside a #if __IOS__ block), and call it after MParticle.Instance.Initialize(options) and before any SelectPlacements or SelectShoppableAds call:

Register RoktPaymentExtension (iOS only)
#if __IOS__
// iOS only: register after MParticle.Instance.Initialize(options),
// before SelectPlacements/SelectShoppableAds.
RoktPaymentExtension.Register("merchant.com.yourapp.rokt");
#endif
caution

RoktPaymentExtension must be registered after MParticle.Instance.Initialize(options) and before any SelectPlacements or SelectShoppableAds call. Registering out of order will prevent Apple Pay from functioning correctly.

note

The exact C# API for RoktPaymentExtension registration may vary by MAUI binding version. If the method signature above does not match your NuGet package, check your NuGet release notes for the equivalent call, or contact Rokt support for binding-specific guidance.

8. Appendix#

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

Applications can pass configuration settings through RoktConfig so the MAUI 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
var roktConfig = new RoktConfig()
{
ColorMode = RoktConfig.RoktColorMode.Light
};

MParticle.Instance.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
var roktConfig = new RoktConfig()
{
CacheConfig = new CacheConfig()
{
CacheDurationInSeconds = 1200,
CacheAttributes = new Dictionary<string, string>()
{
{ "email", "j.smith@example.com" },
{ "orderNumber", "123" }
}
}
};

MParticle.Instance.Rokt.SelectPlacements(
identifier: "RoktExperience",
attributes: attributes,
config: 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

Use the #if __ANDROID__ block to scope this setting to Android only:

EdgeToEdgeDisplay (Android only)
#if __ANDROID__
var roktConfig = new RoktConfig()
{
EdgeToEdgeDisplay = true
};

MParticle.Instance.Rokt.SelectPlacements(
identifier: "RoktExperience",
attributes: attributes,
config: roktConfig
);
#endif

Appendix B: MAUI declarative UI supportDirect link to Appendix B: MAUI declarative UI support

The MAUI SDK+ supports both XML-based layout (RoktEmbeddedView in XAML) and code-behind placement integration. For embedded placements in XAML, register the RoktEmbeddedViewHandler in MauiProgram.CreateMauiApp() (see Embedded placements) and reference the view by its x:Name in your code-behind.

There is no equivalent of Jetpack Compose (RoktLayout) or SwiftUI (MPRoktLayout) for MAUI at this time. Use the XML + code-behind pattern for embedded placements.

Appendix C: Error handlingDirect link to Appendix C: 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.

The failure listener receives an errorResponse object. Use the HttpCode property to determine the cause and decide whether to retry.

Android error handlingDirect link to Android error handling

On Android, IdentityApi.UNKNOWN_ERROR indicates a client-side failure (device offline or client-side timeout) — retry the request. HTTP 429 (IdentityApi.THROTTLE_ERROR) means the request was rate-limited — retry with exponential backoff. Other HTTP error codes indicate implementation or server issues that should be logged and investigated.

IDSync error handling (Android)
#if __ANDROID__
MParticle.Instance.Identity.Identify(identifyRequest)
.AddFailureListener(errorResponse =>
{
if (errorResponse.HttpCode == IdentityApi.UnknownError)
{
// Device is likely offline or client-side timeout — retry the request
}
else if (errorResponse.HttpCode == 429)
{
// Throttled — retry with exponential backoff
}
else
{
// Log errorResponse.HttpCode and investigate — likely an implementation issue
}
})
.AddSuccessListener(result =>
{
// Proceed with the identified user
});
#endif

iOS error handlingDirect link to iOS error handling

On iOS, the failure listener's HttpCode maps to MPIdentityErrorResponseCode values from the native iOS SDK+. Network failures (clientNoConnection, clientSideTimeout) should be retried immediately. Throttle errors (HTTP 429, corresponding to retry) should be retried with backoff. requestInProgress means another IDSync call is in flight — inspect your implementation if this occurs frequently, then retry. All other codes typically indicate an implementation issue; inspect errorResponse details to diagnose.

IDSync error handling (iOS)
#if __IOS__
MParticle.Instance.Identity.Identify(identifyRequest)
.AddFailureListener(errorResponse =>
{
if (errorResponse.HttpCode == IdentityApi.UnknownError)
{
// clientNoConnection or clientSideTimeout — device is offline or timed out, retry the request
}
else if (errorResponse.HttpCode == 429)
{
// Throttled (MPIdentityErrorResponseCodeRetry) — retry with exponential backoff
}
else if (errorResponse.HttpCode == (int)IdentityApi.RequestInProgress)
{
// Another IDSync request is already in progress — inspect implementation frequency, then retry
}
else
{
// Log errorResponse details and investigate — likely an implementation issue
}
})
.AddSuccessListener(result =>
{
// Proceed with the identified user
});
#endif
note

The C# constant names above (IdentityApi.UnknownError, IdentityApi.RequestInProgress) reflect the MAUI binding layer. If your NuGet version exposes different constant names, they map to the underlying iOS MPIdentityErrorResponseCode values:

MAUI C# constantiOS MPIdentityErrorResponseCode
IdentityApi.UnknownErrorclientNoConnection, clientSideTimeout, or unknown
IdentityApi.RequestInProgressrequestInProgress
HTTP 429retry (throttle)

Appendix D: Passing session ID from web to nativeDirect link to Appendix D: 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 MAUI 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 IDDirect link to Setting the session ID

Extract the session ID from the deep link and pass it to the SDK+ before calling SelectPlacements.

Handle deep link and set sessionId
// Extract sessionId from the incoming deep link URI
// and set it on the Rokt SDK+ before calling SelectPlacements
var uri = new Uri(deepLinkUrl);
var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
var sessionId = query["sessionId"];

if (!string.IsNullOrEmpty(sessionId))
{
MParticle.Instance.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.

9. 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
#if __ANDROID__
MParticle.Instance.SetLogLevel(LogLevel.Verbose);
#elif __IOS__
MParticle.Instance.SetLogLevel(LogLevel.Verbose);
#endif

2Build and run against a development key#

Build and run your app with options.Environment = mParticle.MAUI.Environment.Development.

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 identifyRequest call succeeds.

TroubleshootingDirect link to Troubleshooting

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

Initialization errorsDirect link to Initialization errors

  • Confirm the key and secret inside the platform-specific blocks match the values from your Rokt account manager.
  • Confirm MParticle.Instance.Initialize(options) runs before any SelectPlacements or LogEvent call.
  • Confirm RoktKit.Register() is called before MParticle.Instance.Initialize(options).

Identity errorsDirect link to Identity errors

If the AddFailureListener callback fires, see Error handling for the error codes and retry guidance. 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 and that RoktEmbeddedViewHandler is registered in MauiProgram.
  • Check that the attributes dictionary contains at least email, firstname, lastname, billingzipcode, and confirmationref.
Was this article helpful?