Skip to main content

iOS SDK Integration Guide

This page explains how to implement the Rokt Ecommerce iOS 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. Your Rokt account manager will provide the key and secret required to initialize the SDK.

tip

Work with your Rokt account manager to first implement the SDK in a development environment so you can thoroughly test before going live.

1. Add the Rokt SDK to your iOS appDirect link to 1. Add the Rokt SDK to your iOS app

Rokt SDK+ requires a minimum deployment target of iOS 15.0.

Swift Package ManagerDirect link to Swift Package Manager

In Xcode, select File → Add Package Dependencies and add the following packages with the dependency rule set to Up to Next Major Version:

PackageRepository URLProduct
mParticle Apple SDKhttps://github.com/mParticle/mparticle-apple-sdkmParticle-Apple-SDK
mParticle Rokt Kithttps://github.com/mparticle-integrations/mp-apple-integration-rokt.gitmParticle-Rokt
Payment Extensionhttps://github.com/ROKT/rokt-payment-extension-ios.gitRoktPaymentExtension

If you manage dependencies in Package.swift:

dependencies: [
.package(url: "https://github.com/mParticle/mparticle-apple-sdk", from: "9.0.0"),
.package(url: "https://github.com/mparticle-integrations/mp-apple-integration-rokt.git", from: "9.0.0"),
.package(url: "https://github.com/ROKT/rokt-payment-extension-ios.git", from: "1.0.0"),
]

2. Configure Apple PayDirect link to 2. Configure Apple Pay

Before registering a payment extension, you need to 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 return here to register the payment extension.

3. Initialize the Rokt SDKDirect link to 3. Initialize the Rokt SDK

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

AppDelegate initialization
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
// 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.start(), before selectShoppableAds
if let paymentExt = RoktPaymentExtension(
applePayMerchantId: "merchant.com.yourapp.rokt"
) {
MParticle.sharedInstance().rokt.registerPaymentExtension(paymentExt)
}
return true
}

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

  1. Entering your Rokt key and secret.

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

  2. Setting your data environment.

    Set environment to .development (Swift) or MPEnvironmentDevelopment (Objective-C) while testing to route data to the Development environment, and .production or MPEnvironmentProduction to send live customer activity to Production.

  3. Identifying your user and setting attributes.

    In identifyRequest, pass the user's raw, un-hashed email in the email property. For hashed emails and other identifiers, see Supported User Identifiers. Once identified, use the onIdentifyComplete callback to set additional user attributes — see User Attributes for the recommended list.

    onIdentifyComplete
    options.onIdentifyComplete = {(result: MPIdentityApiResult?, error: Error?) in
    if let user = result?.user {
    user.setUserAttribute("example attribute key", value: "example attribute value")
    }
    }
    note

    Always include identifyRequest in the initialization snippet. If you don't have the user's email at initialization, omit the assignment — the SDK will still initialize, and you can identify the user later via 4. Identify the User. See Error Handling for how to inspect the error argument — without error handling you may see data consistency issues at scale.

  4. Registering the payment extension.

    Register RoktPaymentExtension after MParticle.sharedInstance().start() and before selectPlacements to enable Apple Pay. See 2. Configure Apple Pay.

4. Identify the UserDirect link to 4. Identify the User

Call MParticle.sharedInstance().identity.identify with a fresh identifyRequest any time the user provides their email address after the SDK has initialized (for example, when they log in, create an account, or make a purchase). This ensures event data is attributed to the correct user.

Supported User IdentifiersDirect link to Supported User Identifiers

Show supported user identifiers
IdentifierTypeHow to set
emailstringAssign the customer's raw, unhashed email address to identifyRequest.email.
otherstringPass a SHA-256-hashed email via identifyRequest.setIdentity(hashedEmail, identityType: .other) (Swift) or [identifyRequest setIdentity:hashedEmail identityType:MPIdentityOther] (Objective-C).
customerIdstringAssign your internal customer/account identifier to identifyRequest.customerId.

To identify the user:

  1. Create an identifyRequest object containing the user's identifiers.
  2. Create an identityCallback to set additional user attributes once identify succeeds.
  3. Call the identify method with both objects.
Identify Jane Smith
// 1. Create the identifyRequest object
let identifyRequest = MPIdentityApiRequest.withEmptyUser()
identifyRequest.email = "j.smith@example.com"

// 2. User attributes are set using identityCallback
let identityCallback = {(result: MPIdentityApiResult?) in
if let user = result?.user {
user.setUserAttribute("first_name", value: "Jane")
user.setUserAttribute("last_name", value: "Smith")
}
}

// 3. Call the identify method
MParticle.sharedInstance().identity.identify(identifyRequest, completion: identityCallback)

5. Set User AttributesDirect link to 5. 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
import mParticle_Apple_SDK

// Retrieve the current user. This will only succeed if you have identified the user during SDK initialization or by calling the identify method.
let currentUser = MParticle.sharedInstance().identity.currentUser

// Once you have successfully set the current user to `currentUser`, you can set user attributes with:
currentUser?.setUserAttribute("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("firstname", value: "John")
currentUser?.setUserAttribute("lastname", value: "Doe")
// Phone numbers can be formatted either as '1234567890', or '+1 (234) 567-8901'
currentUser?.setUserAttribute("mobile", value: "3125551515")
currentUser?.setUserAttribute("age", value: "33")
currentUser?.setUserAttribute("gender", value: "M")
currentUser?.setUserAttribute("city", value: "Brooklyn")
currentUser?.setUserAttribute("state", value: "NY")
currentUser?.setUserAttribute("zip", value: "123456")
currentUser?.setUserAttribute("dob", value: "yyyymmdd")
currentUser?.setUserAttribute("title", value: "Mr")
currentUser?.setUserAttribute("language", value: "en")
currentUser?.setUserAttribute("value", value: "52.25")
currentUser?.setUserAttribute("predictedltv", value: "136.23")

// You can create a user attribute to contain a list of values
currentUser?.setUserAttributeList("favorite-genres", values: ["documentary", "comedy", "romance", "drama"])

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

User AttributesDirect link to User Attributes

Set as many of the following as you can collect:

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

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

6. Track Funnel EventsDirect link to 6. Track Funnel Events

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

Screen ViewsDirect link to Screen Views

Call logScreen with the name of the screen (e.g. "homepage", "product detail page"). Include any additional custom attributes in eventInfo.

Log a screen view
MParticle.sharedInstance().logScreen(
"homepage",
eventInfo: ["custom-attribute": "custom-value"]
)

Account Lifecycle EventsDirect link to Account Lifecycle Events

Log account lifecycle events when the user signs up, logs in, or logs out so Rokt can maintain identity continuity across sessions and devices. Signup and login events accept a method attribute describing how the user signed up or logged in.

Supported lifecycle event typesDirect link to Supported lifecycle event types

Show lifecycle event types
Lifecycle Event TypeWhen to triggerSupported method values
sign_upNew account createdemail, social, guest
loginUser logs inemail, social, sso
logoutUser logs outNot applicable.

Example lifecycle eventsDirect link to Example lifecycle events

Signup, login, logout
// Signup event
if let event = MPEvent(name: "sign_up", type: .other) {
event.customAttributes = ["method": "email"]
MParticle.sharedInstance().logEvent(event)
}

// Login event
if let event = MPEvent(name: "login", type: .other) {
event.customAttributes = ["method": "email"]
MParticle.sharedInstance().logEvent(event)
}

// Logout event
if let event = MPEvent(name: "logout", type: .other) {
MParticle.sharedInstance().logEvent(event)
}

Commerce EventsDirect link to Commerce Events

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 MPCommerceEvent, using an MPCommerceEventAction that identifies the customer action (viewing a product, adding to cart, starting checkout, completing a purchase, etc.). The sections below list the supported action types and walk through assembling the event.

Product action typesDirect link to Product action types

Show all product action types
Customer actionSwift action typeObjective-C action type
Product detail page viewed.viewDetailMPCommerceEventActionViewDetail
Product clicked.clickMPCommerceEventActionClick
Item added to cart.addToCartMPCommerceEventActionAddToCart
Item removed from cart.removeFromCartMPCommerceEventActionRemoveFromCart
Item added to wishlist.addToWishlistMPCommerceEventActionAddToWishlist
Item removed from wishlist.removeFromWishlistMPCommerceEventActionRemoveFromWishlist
Checkout flow initiated.checkoutMPCommerceEventActionCheckout
Checkout option selected.checkoutOptionMPCommerceEventActionCheckoutOption
Order confirmed.purchaseMPCommerceEventActionPurchase
Order refunded.refundMPCommerceEventActionRefund

Tracking a commerce event requires three steps:

1. Define the productDirect link to 1. Define the product

Create an MPProduct with the product's name, SKU, price, and quantity.

Define a product
let product = MPProduct(
name: "Double Room",
sku: "econ-1",
quantity: 4,
price: 100.00
)

2. Summarize the transactionDirect link to 2. Summarize the transaction

Create an MPTransactionAttributes object for .purchase, .checkout, and .checkoutOption events. Include shipping and couponCode when applicable — order-level coupons belong here, not on individual products.

Summarize the transaction
let attributes = MPTransactionAttributes()
attributes.transactionId = "ORDER-12345"
attributes.revenue = 149.99
attributes.tax = 12.50
attributes.shipping = 5.99
attributes.couponCode = "SUMMER20"

3. Log the commerce eventDirect link to 3. Log the commerce event

Create an MPCommerceEvent with an MPCommerceEventAction from the table above, attach the transactionAttributes, and log it.

Log a Purchase commerce event
let event = MPCommerceEvent(action: .purchase, product: product)
event.transactionAttributes = attributes
MParticle.sharedInstance().logEvent(event)

The same structure applies to every MPCommerceEventAction — swap .purchase for the action that matches the customer behavior you're logging.

Custom EventsDirect link to Custom Events

Track custom events with MPEvent, passing an event name, event type, and optional custom attributes.

Supported custom event typesDirect link to Supported custom event types

Show custom event types
TypeUse for
.navigationUser navigation flows and page transitions within your app.
.locationLocation-based interactions and movements.
.searchSearch queries and search-related actions.
.transactionFinancial transactions and purchase-related activity.
.userContentUser-generated content like reviews, comments, or posts.
.userPreferenceUser settings, preferences, and customization choices.
.socialSocial media interactions and sharing activities.
.otherAnything that doesn't fit the categories above.

Example custom eventDirect link to Example custom event

Log a custom event
if let event = MPEvent(name: "Video Watched", type: .navigation) {
event.customAttributes = ["category": "Destination Intro", "title": "Paris"]
MParticle.sharedInstance().logEvent(event)
}

7. Show a PlacementDirect link to 7. 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 payment_type and payment_service_provider in the selectPlacements call on each page. payment_service_provider communicates what payment methods are available on the payment page; payment_type communicates what method the user paid with.

Overlay placementsDirect link to Overlay placements

Overlay placement
import mParticle_Apple_SDK
let attributes = [
"email": "test@gmail.com",
"firstname": "Jenny",
"lastname": "Smith",
"billingzipcode": "07762",
"confirmationref": "54321"
]

MParticle.sharedInstance().rokt.selectPlacements("RoktExperience", attributes: attributes)

Embedded placementsDirect link to Embedded placements

Embedded placements share the same attribute requirements as overlay placements but render the placement view inside your own UI. Use the onEvent callback to respond to placement events (load, unload, loading indicator, embedded size change, etc.). Event types are subclasses of RoktEvent (from the RoktContracts package); check the event type in your callback.

Embedded placement with onEvent
import mParticle_Apple_SDK

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

let roktFrame = CGRect(x: 0, y: 0, width: 320, height: 50)
let roktView = RoktEmbeddedView(frame: roktFrame)
let embeddedViews = ["RoktEmbedded1": roktView]

let roktConfig = RoktConfig.Builder().colorMode(.light).build()

MParticle.sharedInstance().rokt.selectPlacements("RoktExperience", attributes: attributes, embeddedViews: embeddedViews, config: roktConfig) { event in
switch event {
case let sizeEvent as RoktEvent.EmbeddedSizeChanged:
// Example event - Height changed: use sizeEvent.identifier and sizeEvent.updatedHeight
// The full list of events is provided below
break
default:
break
}
}

To fully support Rokt's Shoppable Ads experiences, capture the attributes marked as used for Shoppable Ads in Placement Attributes below in your selectPlacements call. The CartItemInstantPurchase and related events in the Events API below fire during Shoppable Ads purchase flows.

note

If your platform does not have shipping address details (e.g. ticket or digital goods purchases), pass billing address details instead. Rokt will provide a UI for the customer to confirm or edit their shipping address before completing the purchase.

Additional configurationDirect link to Additional configuration

Pass optional parameters such as RoktConfig to customize the placement UI (e.g. dark/light mode). Additional optional parameters including embedded views and the onEvent callback are shown below.

selectPlacements with RoktConfig
let roktConfig = RoktConfig.Builder().colorMode(.light).build()

MParticle.sharedInstance().rokt.selectPlacements("RoktExperience", attributes: attributes, embeddedViews: nil, config: roktConfig) { _ in }
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.

Optional functionsDirect link to Optional functions

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

For a full list of supported attributes, see Placement Attributes below or Data Attributes for the full reference.

Your Rokt team will configure your placement layouts to match your brand.

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
AttributeTypeDescription
emailstringCustomer email (unhashed). Used for identity resolution and Shoppable Ads order confirmation.
firstnamestringCustomer first name. Used for personalization and Shoppable Ads order fulfillment.
lastnamestringCustomer last name. Used for personalization and Shoppable Ads order fulfillment.
mobilestringCustomer mobile number in E.164 format. Used for identity resolution.
confirmationrefstringOrder / confirmation reference number. Used for relevance, deduplication, and Shoppable Ads order reconciliation.
currencystringTransaction currency (ISO 4217, e.g. USD, GBP, AUD). Used for relevance and Shoppable Ads.
countrystringISO 3166-1 alpha-2 country code. Used for eligibility and relevance.
languagestringCustomer's preferred language (ISO 639-1). Used for relevance.
amountstringDecimal transaction amount (e.g. "52.25"). Used for relevance and Shoppable Ads.
new_customerbooleanWhether this is a first-time buyer. Used for relevance.
customer_typestringguest or logged_in. Used for relevance.
payment_typestringPayment method selected (credit_card, paypal, apple_pay, etc.). Used for Pay+ eligibility and Shoppable Ads payment method prioritization.
payment_service_providerstringPayment services offered on the page (apple_pay, paypal, card). Used for Pay+ eligibility.
ccbinstringCredit card BIN (first 6 digits). Used for relevance.
billingzipcodestringBilling ZIP / postcode. Used for identity resolution and relevance.
shippingaddress1stringShipping street address. Used for relevance and Shoppable Ads order fulfillment.
shippingcitystringShipping city. Used for relevance and Shoppable Ads order fulfillment.
shippingstatestringShipping state or province. Used for relevance and Shoppable Ads order fulfillment.
shippingzipcodestringShipping ZIP or postcode. Used for relevance and Shoppable Ads order fulfillment.
shippingcountrystringShipping country (ISO 3166-1 alpha-2). Used for relevance and Shoppable Ads order fulfillment.
adsExperiencestringPass "shoppable" when deliberately selecting a Shoppable Ads experience.

Events APIDirect link to Events API

The SDK emits placement lifecycle events through the Rokt.events API. Subscribe to respond to load state, engagement, failures, and Shoppable Ads purchase flows.

Subscribe to Rokt.events
import mParticle_Apple_SDK

MParticle.sharedInstance().rokt.events("RoktLayout", onEvent: { roktEvent in
if let event = roktEvent as? RoktEvent.ShowLoadingIndicator {
// Example showing handling of ShowLoadingIndicator event
// The full list of events is provided below
}
})

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 interactableidentifier: String
PlacementReadyTriggered when a placement is ready to display but has not rendered content yetidentifier: String
OfferEngagementTriggered when the user engages with the offeridentifier: String
OpenUrlTriggered when the user presses a URL that is configured to be sent to the partner appidentifier: String, url: String
PositiveEngagementTriggered when the user positively engages with the offeridentifier: String
PlacementClosedTriggered when a placement is closed by the useridentifier: String
PlacementCompletedTriggered when the offer progression reaches the end and no more offers are available to display.
Also triggered when cache is hit but the retrieved placement will not be displayed as it has previously been dismissed
identifier: String
PlacementFailureTriggered when a placement could not be displayed due to some failure or when no placements are available to showidentifier: String (optional)
FirstPositiveEngagementTriggered when the user positively engages with the offer for the first timeidentifier: String, setFulfillmentAttributes: func (attributes: [String: String])
CartItemInstantPurchaseTriggered when a purchase is made through a placementidentifier: String, name: String?, cartItemId: String, catalogItemId: String, currency: String, description: String, linkedProductId: String?, providerData: String, quantity: NSDecimalNumber?, totalPrice: NSDecimalNumber?, unitPrice: NSDecimalNumber?
EmbeddedSizeChangedTriggered when the height of an embedded placement changesidentifier: String, updatedHeight: CGFloat

Shoppable Ads eventsDirect link to Shoppable Ads events

Show Shoppable Ads events
EventDescriptionParams
CartItemInstantPurchaseInitiatedPurchase flow started — user tapped "Buy"identifier, catalogItemId, cartItemId
CartItemInstantPurchasePurchase completed successfullyidentifier, name, cartItemId, catalogItemId, currency, description, linkedProductId, providerData, quantity, totalPrice, unitPrice
CartItemInstantPurchaseFailurePurchase failedidentifier, catalogItemId, cartItemId, error
CartItemDevicePayApple Pay / device payment triggeredidentifier, catalogItemId, cartItemId, paymentProvider
InstantPurchaseDismissalUser dismissed the purchase overlayidentifier

8. Test Your IntegrationDirect link to 8. Test Your Integration

To confirm the SDK initializes and events log correctly:

  1. Enable verbose SDK logging before initialization so you can see what's being sent.
  2. Build and run your app against a development key with environment = .development (or MPEnvironmentDevelopment).
  3. Trigger selectPlacements on the screen where the placement should render and confirm the placement loads.
  4. Verify events appear in your mParticle workspace's Live Stream, and confirm the identifyRequest call succeeds.
Enable verbose SDK logging
Rokt.setLoggingEnabled(enable: true)

TroubleshootingDirect link to Troubleshooting

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

Initialization errorsDirect link to Initialization errors

  • Confirm key and secret match the values from your Rokt account manager.
  • Confirm MParticle.sharedInstance().start(with: options) runs before any selectPlacements or logEvent call.
  • For Shoppable Ads, confirm RoktPaymentExtension is registered after start() and before selectPlacements.

Identity errorsDirect link to Identity errors

If the onIdentifyComplete or identify callback fires with an error instead of a user, see Error Handling for the MPIdentityErrorResponseCode values 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.
  • Check that the attributes dictionary contains at least email, firstname, lastname, billingzipcode, and confirmationref.

AppendixDirect link to Appendix

Appendix A: App ConfigurationDirect link to Appendix A: App Configuration

Applications can send configuration settings through RoktConfig so the iOS 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
ColorMode.light
// if application supports only Light Mode.
let roktConfig = RoktConfig.Builder().colorMode(.light).build()

MParticle.sharedInstance().rokt.selectPlacements("RoktExperience", attributes: attributes, embeddedViews: nil, config: roktConfig) { _ in }

CacheConfig objectDirect link to CacheConfig object

ParameterDescription
cacheDurationOptional TimeInterval for which the Rokt SDK should cache the experience. Maximum allowed value is 90 minutes and the default (if value is not provided or invalid) is 90 minutes.
cacheAttributesOptional attributes to be used as cache key. If null, all the attributes sent in the selectPlacements call will be used as the cache key.
Cache for 1200 seconds
// to cache the experience for 1200 seconds, using email and orderNumber attributes as the cache key.
let roktConfig = RoktConfig.Builder()
.cacheConfig(RoktConfig.CacheConfig(
cacheDuration: TimeInterval(1200),
cacheAttributes: ["email": "j.smith@example.com", "orderNumber": "123"]
))
.build()

MParticle.sharedInstance().rokt.selectPlacements("RoktExperience", attributes: attributes, embeddedViews: nil, config: roktConfig) { _ in }

Appendix B: SwiftUI Support with MPRoktLayoutDirect link to Appendix B: SwiftUI Support with MPRoktLayout

If your app is primarily written in SwiftUI we have provided the MPRoktLayout component for 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.

Adding the SwiftUI componentDirect link to Adding the SwiftUI component
SwiftUI placement with MPRoktLayout
import SwiftUI
import mParticle_Apple_SDK
import mParticle_Rokt_Swift

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

@State private var sdkTriggered = true

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

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

Appendix C: 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 - we intend you to treat these APIs as gating operations in order to maintain a consistent user state. The SDK will not retry API calls automatically, but provides callback APIs such that you can do so according to your business logic. The tolerance you have for retry and inconsistent state is up to your product requirements.

If you do not wish to handle errors, you may see data consistency issues at scale. It's recommended to at least monitor for errors during your implementation.

Your IDSync callback block will be invoked with one of two objects:

  • MPIdentityApiResult: A result object containing the new or updated user object.
  • NSError/Error: An error object containing a code and description if the IDSync call failed
IDSync error handling
let identityCallback = {(result: MPIdentityApiResult?, error: Error?) in
if (result?.user != nil) {
//IDSync request succeeded, mutate attributes or query for the MPID as needed
result?.user.setUserAttribute("example attribute key", value: "example attribute value")
} else {
NSLog(error!.localizedDescription)
let resultCode = MPIdentityErrorResponseCode(rawValue: UInt((error! as NSError).code))
switch (resultCode!) {
case .clientNoConnection,
.clientSideTimeout:
//retry the IDSync request
break;
case .requestInProgress,
.retry:
//inspect your implementation if this occurs frequency
//otherwise retry the IDSync request
break;
default:
// inspect error.localizedDescription to determine why the request failed
// this typically means an implementation issue
break;
}
}
}

Status CodesDirect link to Status Codes

When an IDSync callback block in invoked with a failure, you can inspect the code property to determine the cause. This property is meant to describe the result of the invocation of the respective iOS SDK IDSync API. It may either contain a client-side generated value, or an actual HTTP status code.

Client-side CodesDirect link to Client-side Codes

The NSError code property may contain the following client-side codes, defined within the MPIdentityErrorResponseCode enum:

MPIdentityErrorResponseCodeDescription
MPIdentityErrorResponseCodeRequestInProgressThe IDSync HTTP request was not performed as there is already an IDSync HTTP request in progress
MPIdentityErrorResponseCodeClientSideTimeoutThe IDSync HTTP request failed due to a TCP connection timeout.
MPIdentityErrorResponseCodeClientNoConnectionThe IDSync HTTP request failed due to lack of network coverage.
MPIdentityErrorResponseCodeSSLErrorThe IDSync HTTP request failed due to an SSL configuration issue. The SDK pins the mParticle SSL certificate which requires custom initialization via the MPNetworkOptions API to disable.
MPIdentityErrorResponseCodeOptOutThe IDSync HTTP request was not performed due to the SDK being disabled due to opt-out.
MPIdentityErrorResponseCodeUnknownThe IDSync HTTP request failed due to an unknown error. This should be rare and could mean the app is in a bad memory state.

HTTP Status CodesDirect link to HTTP Status Codes

The NSError code property may contain the following server generated HTTP status codes, some of which are defined within the MPIdentityErrorResponseCode enum for your convenience:

ValueDescription
400The IDSync HTTP call failed due to an invalid request body. Inspect the error.userInfo object for more information.
401The IDSync HTTP call failed due to an authentication error. Verify that your API key is correct.
403 ForbiddenAliasing is not provisioned for your mParticle workspace. Contact your mParticle account representative to have aliasing provisioned.
429The IDSync HTTP call was throttled and should be retried. This may indicate a user "hotkey" or an incorrect implementation resulting in a higher than expected volume of IDSync requests.
5xxThe IDSync HTTP call failed due to an mParticle server-side issue. This should never happen under typical circumstances. Check the mParticle status page if this is occurring.

UIApplication Delegate ProxyDirect link to UIApplication Delegate Proxy

By default the mParticle SDK replaces your UIApplication.delegate with its own NSProxy implementation in order to facilitate and simplify the handling of remote notifications, local notifications, interactions with notification actions, and application launching. Over time we have found this to be less intrusive than other SDKs which instead perform swizzling, but it can cause complications when a client is using a 3rd party framework that does.

Recommendation

We recommend new integrations disable proxyAppDelegate and instead use the SceneDelegate methods below to manually forward lifecycle events to mParticle. In a future major release, proxyAppDelegate will default to false.

You can disable the proxy via the proxyAppDelegate flag of the MParticleOptions object. Doing so means you will need to audit any kits that you use individually to determine which UIApplication APIs they require. Any required methods should be manually invoked on mParticle, such that mParticle can forward those APIs onto each kit.

let options = MParticleOptions(key: "REPLACE WITH APP KEY",
secret: "REPLACE WITH APP SECRET")
options.proxyAppDelegate = false
MParticle.sharedInstance().start(with: options)

AppDelegate Methods with Proxy DisabledDirect link to AppDelegate Methods with Proxy Disabled

When proxyAppDelegate is disabled, you must manually forward the following methods from your AppDelegate to mParticle. These methods are required for kits that have remote or local notification functionality, and for using mParticle to register for push notifications.

// MARK: - Remote Notification Registration

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
MParticle.sharedInstance().didRegisterForRemoteNotifications(withDeviceToken: deviceToken)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: any Error) {
MParticle.sharedInstance().didFailToRegisterForRemoteNotificationsWithError(error)
}

// MARK: - UNUserNotificationCenterDelegate

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
MParticle.sharedInstance().userNotificationCenter(center, willPresent: notification)
if #available(iOS 14, *) {
completionHandler([.list, .banner])
} else {
completionHandler(.alert)
}
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
MParticle.sharedInstance().userNotificationCenter(center, didReceive: response)
completionHandler()
}

SceneDelegate Support (iOS 13+)Direct link to SceneDelegate Support (iOS 13+)

For apps using a UISceneDelegate (the modern lifecycle introduced in iOS 13), mParticle provides dedicated methods for handling URL contexts and user activities. These are the recommended approach for all integrations.

Handling URL ContextsDirect link to Handling URL Contexts

To handle deep links and custom URL schemes in your SceneDelegate, use the handleURLContext: method:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for urlContext in URLContexts {
MParticle.sharedInstance().handleURLContext(urlContext)
}
}

To handle Universal Links in your SceneDelegate, use the handleUserActivity: method:

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
MParticle.sharedInstance().handleUserActivity(userActivity)
}

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 mParticle iOS 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 SDKDirect 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;

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 mParticle SDK before calling selectPlacements.

Handle deep link and set sessionId
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
}

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
Was this article helpful?