Supported on: iOS SDK
1.0.61+Core Methods
| Method | Signature | Description |
|---|---|---|
configure | AppDNA.configure(apiKey: String, environment: Environment = .production, options: AppDNAOptions = AppDNAOptions()) | Initialize the SDK. Call once at app launch. |
identify | AppDNA.identify(userId: String, traits: [String: Any]?) | Associate events with a user identity. |
reset | AppDNA.reset() | Clear user identity and flush events. Call on logout. |
track | AppDNA.track(event: String, properties: [String: Any]?) | Track a custom event with optional properties. |
flush | AppDNA.flush() | Force an immediate flush of all queued events. |
onReady | AppDNA.onReady(_ callback: @escaping () -> Void) | Register a callback for when the SDK is fully initialized. |
shutdown | AppDNA.shutdown() | Shut down the SDK, flush events, and release resources. |
setLogLevel | AppDNA.setLogLevel(_ level: LogLevel) | Change the SDK log level at runtime. |
setConsent | AppDNA.setConsent(analytics: Bool) | Set analytics consent. When false, events are dropped silently. |
Session Data Methods
| Method | Signature | Description |
|---|---|---|
setSessionData | AppDNA.setSessionData(key: String, value: Any) | Store a key-value pair in the session data store. |
getSessionData | AppDNA.getSessionData(key: String) -> Any? | Retrieve a session data value by key. |
clearSessionData | AppDNA.clearSessionData() | Clear all app-defined session data. |
getLocationData | AppDNA.getLocationData(fieldId: String) -> LocationData? | Get structured location data from an onboarding location field. Returns city, state, country, coordinates, timezone. |
Config Methods
| Method | Signature | Description |
|---|---|---|
getRemoteConfig | AppDNA.getRemoteConfig(key: String) -> Any? | Get a remote config value by key. |
forceRefreshConfig | AppDNA.forceRefreshConfig() | Force an immediate refresh of remote configuration. |
isFeatureEnabled | AppDNA.isFeatureEnabled(flag: String) -> Bool | Check if a feature flag is enabled. |
Experiment Methods
| Method | Signature | Description |
|---|---|---|
getExperimentVariant | AppDNA.getExperimentVariant(experimentId: String) -> String? | Get the assigned variant for an experiment. |
isInVariant | AppDNA.isInVariant(experimentId: String, variantId: String) -> Bool | Check if the user is in a specific variant. |
getExperimentConfig | AppDNA.getExperimentConfig(experimentId: String, key: String) -> Any? | Get a specific config value for an experiment variant. |
Push Methods
| Method | Signature | Description |
|---|---|---|
registerForPush | AppDNA.registerForPush() async -> Bool | Request push permission and register for remote notifications. |
setPushToken | AppDNA.setPushToken(_ deviceToken: Data) | Set the APNs device token manually. |
setPushPermission | AppDNA.setPushPermission(granted: Bool) | Update the push permission status. |
trackPushDelivered | AppDNA.trackPushDelivered(pushId: String) | Track that a push notification was delivered. |
trackPushTapped | AppDNA.trackPushTapped(pushId: String, action: String?) | Track that a push notification was tapped. |
Presentation Methods
| Method | Signature | Description |
|---|---|---|
presentOnboarding | AppDNA.presentOnboarding(flowId: String?, from: UIViewController, delegate: AppDNAOnboardingDelegate?) -> Bool | Present an onboarding flow. Returns false if config unavailable. |
presentPaywall | AppDNA.presentPaywall(id: String, from: UIViewController, context: PaywallContext?, delegate: AppDNAPaywallDelegate?) -> Bool | Present a paywall by ID. Returns false if nothing could present it. |
presentPaywall | AppDNA.presentPaywall(placement: String, from: UIViewController, context: PaywallContext?, delegate: AppDNAPaywallDelegate?) -> Bool | Present whichever paywall the Console assigned to a placement. Returns false if nothing could present it. |
Web Entitlements
| Member | Signature | Description |
|---|---|---|
webEntitlement | AppDNA.webEntitlement: WebEntitlement? | The current web entitlement, if any. |
onWebEntitlementChanged | AppDNA.onWebEntitlementChanged(_ callback: @escaping (WebEntitlement?) -> Void) | Register a callback for web entitlement changes. |
Deep Links
| Method | Signature | Description |
|---|---|---|
checkDeferredDeepLink | AppDNA.checkDeferredDeepLink(completion: @escaping (DeferredDeepLink?) -> Void) | Check for a deferred deep link from install attribution. |
Module Namespaces
Access module-specific functionality through these properties on theAppDNA singleton:
| Property | Type | Description |
|---|---|---|
AppDNA.pushModule | PushModule | Push notification registration, tokens, and delegates |
AppDNA.billing | BillingModule | Products, purchases, entitlements, and restore |
AppDNA.onboarding | OnboardingModule | Server-driven onboarding flow presentation |
AppDNA.paywall | PaywallModule | Server-driven paywall presentation |
AppDNA.remoteConfig | RemoteConfigModule | Remote configuration access |
AppDNA.features | FeaturesModule | Feature flag evaluation |
AppDNA.experiments | ExperimentsModule | Experiment variant assignment |
AppDNA.inAppMessages | InAppMessagesModule | In-app message display |
AppDNA.surveys | SurveysModule | User survey presentation |
AppDNA.deepLinks | DeepLinksModule | Deep link and deferred deep link handling |
Delegate Protocols
AppDNAPushDelegate
protocol AppDNAPushDelegate {
func onPushTokenRegistered(token: String)
func onPushReceived(notification: PushPayload, inForeground: Bool)
func onPushTapped(notification: PushPayload, actionId: String?)
}
AppDNABillingDelegate
protocol AppDNABillingDelegate {
func onPurchaseCompleted(productId: String, transaction: TransactionInfo)
func onPurchaseFailed(productId: String, error: Error)
func onEntitlementsChanged(entitlements: [Entitlement])
func onRestoreCompleted(restoredProducts: [String])
}
AppDNAOnboardingDelegate
protocol AppDNAOnboardingDelegate {
func onOnboardingStarted(flowId: String)
func onOnboardingStepChanged(flowId: String, stepId: String, stepIndex: Int, totalSteps: Int)
func onOnboardingCompleted(flowId: String, responses: [String: Any])
func onOnboardingDismissed(flowId: String, atStep: Int)
// Async hooks (optional)
func onBeforeStepAdvance(flowId: String, fromStepId: String, stepIndex: Int, stepType: String, responses: [String: Any], stepData: [String: Any]?) async -> StepAdvanceResult
func onBeforeStepRender(flowId: String, stepId: String, stepIndex: Int, stepType: String, responses: [String: Any]) async -> StepConfigOverride?
}
AppDNAPaywallDelegate
protocol AppDNAPaywallDelegate {
func onPaywallPresented(paywallId: String)
func onPaywallAction(paywallId: String, action: PaywallAction)
func onPaywallPurchaseStarted(paywallId: String, productId: String)
func onPaywallPurchaseCompleted(paywallId: String, productId: String, transaction: TransactionInfo)
func onPaywallPurchaseFailed(paywallId: String, error: Error)
func onPaywallDismissed(paywallId: String)
func onPromoCodeSubmit(paywallId: String, code: String, completion: @escaping (Bool) -> Void)
func onPostPurchaseDeepLink(paywallId: String, url: String)
func onPostPurchaseNextStep(paywallId: String)
func onPaywallRestoreStarted(paywallId: String)
func onPaywallRestoreCompleted(paywallId: String, productIds: [String])
func onPaywallRestoreFailed(paywallId: String, error: Error)
}
AppDNAInAppMessageDelegate
public protocol AppDNAInAppMessageDelegate: AnyObject {
func onMessageShown(messageId: String, trigger: String)
func onMessageAction(messageId: String, action: String, data: [String: Any]?)
func onMessageDismissed(messageId: String)
func shouldShowMessage(messageId: String) -> Bool
}
AppDNASurveyDelegate
protocol AppDNASurveyDelegate {
func onSurveyPresented(surveyId: String)
func onSurveyCompleted(surveyId: String, responses: [SurveyResponse])
func onSurveyDismissed(surveyId: String)
}
AppDNADeepLinkDelegate
public protocol AppDNADeepLinkDelegate: AnyObject {
func onDeepLinkReceived(url: URL, params: [String: String])
}
Key Types
AppDNAOptions
struct AppDNAOptions {
let flushInterval: TimeInterval // Default: 30
let batchSize: Int // Default: 20
let configTTL: TimeInterval // Default: 3600 (1 hour)
let logLevel: LogLevel // Default: .warning
let billingProvider: BillingProvider // Default: .storeKit2
let framework: String // Default: "native" (wrapper attribution)
let frameworkVersion: String? // Default: nil (wrapper's own version)
let requireConsent: Bool // Default: false (analytics opt-out)
let vetoTimeout: TimeInterval // Default: 5 (seconds a host veto may take)
}
Environment
enum Environment {
case production
case sandbox
}
LogLevel
enum LogLevel {
case none
case error
case warning
case info
case debug
}
BillingProvider
enum BillingProvider {
case storeKit2
case revenueCat
case adapty(apiKey: String)
case none
}
PaywallContext
struct PaywallContext {
let placement: String
let experiment: String?
let variant: String?
let customData: [String: Any]? // Merged into the `paywall_view` event's properties
}
OnboardingContext
struct OnboardingContext {
var source: String?
var campaign: String?
var referrer: String?
var userProperties: [String: Any]?
var experimentOverrides: [String: String]?
}
PushPayload
struct PushPayload {
let pushId: String
let title: String
let body: String
let imageUrl: String?
let data: [String: Any]?
let action: PushAction? // The notification-body tap-through action
let actions: [PushAction] // The registered action BUTTONS (defaults to [])
}
PushAction
struct PushAction {
let type: String
let value: String
let id: String? // Button identifier — matches `actionId` in onPushTapped. Nil for the body action.
let label: String? // Button label as displayed. Nil for the body action.
}
TransactionInfo
struct TransactionInfo {
var transactionId: String
var productId: String
var purchaseDate: Date
var environment: String
}
ProductInfo
struct ProductInfo {
var id: String
var displayName: String
var description: String
var price: Decimal
var displayPrice: String
var subscription: SubscriptionInfo?
}
Entitlement
struct Entitlement {
var identifier: String
var isActive: Bool
var expiresAt: Date?
var productId: String
}
WebEntitlement
struct WebEntitlement {
let isActive: Bool
let planName: String?
let priceId: String?
let interval: String? // "month", "year"
let status: EntitlementStatus
let currentPeriodEnd: Date?
let trialEnd: Date?
}
DeferredDeepLink
struct DeferredDeepLink {
var screen: String
var params: [String: String]
var visitorId: String
}
PaywallAction
enum PaywallAction {
case ctaTapped
case featureSelected
case planChanged
case linkTapped
case custom
}
DismissReason
enum DismissReason {
case purchased
case dismissed
case tappedOutside
case programmatic
}
StepAdvanceResult
enum StepAdvanceResult {
case proceed
case proceedWithData([String: Any])
case block(message: String)
case skipTo(stepId: String)
case skipToWithData(stepId: String, data: [String: Any])
case stay(message: String? = nil)
}
StepConfigOverride
struct StepConfigOverride {
var fieldDefaults: [String: Any]?
var title: String?
var subtitle: String?
var ctaText: String?
var layoutOverrides: [String: Any]?
}
FormFieldType
enum FormFieldType: String, Codable {
case text, textarea, number, email, phone
case password
case url
case date, time, datetime
case select, slider, toggle, stepper, segmented
case location
case rating
case range_slider
case image_picker
case color
case multiline_chips
case signature
}
Server-Driven Screens
| Method | Signature | Description |
|---|---|---|
showScreen | AppDNA.showScreen(_ screenId: String, completion: ((ScreenResult) -> Void)?) | Present a server-driven screen by ID. |
showFlow | AppDNA.showFlow(_ flowId: String, completion: ((FlowResult) -> Void)?) | Present a multi-screen flow by ID. |
dismissScreen | AppDNA.dismissScreen() | Dismiss the currently presented screen or flow. |
enableNavigationInterception | AppDNA.enableNavigationInterception(forScreens: [String]?) | Enable automatic screen injection between navigations. Pass nil for all screens. |
disableNavigationInterception | AppDNA.disableNavigationInterception() | Disable navigation interception. |
previewScreen | @discardableResult AppDNA.previewScreen(json: String, completion: ((ScreenResult) -> Void)? = nil) -> Bool | Preview a screen from raw JSON config. Available in all build configurations. |
screenDelegate | AppDNA.screenDelegate: AppDNAScreenDelegate? | Set a delegate for screen lifecycle callbacks. |
isConsentGranted | AppDNA.isConsentGranted() -> Bool | Check if analytics consent has been granted. |
getUserTraits | AppDNA.getUserTraits() -> [String: Any] | Get the current user traits set via identify(). |
AppDNAScreenDelegate
protocol AppDNAScreenDelegate {
func onScreenPresented(screenId: String)
func onScreenDismissed(screenId: String, result: ScreenResult)
func onFlowCompleted(flowId: String, result: FlowResult)
func onScreenAction(screenId: String, action: SectionAction) -> Bool
}
ScreenError
enum ScreenError: String, Codable {
case configFetchFailed
case configFetchTimeout
case screenNotFound
case configParseError
case configInvalid
case nestingDepthExceeded
}
ScreenResult
struct ScreenResult {
let screenId: String
let dismissed: Bool
let responses: [String: Any]
let lastAction: String?
let duration_ms: Int
let error: ScreenError?
}
FlowResult
struct FlowResult {
let flowId: String
let completed: Bool
let lastScreenId: String
let responses: [String: Any]
let screensViewed: [String]
let duration_ms: Int
let error: ScreenError?
}
SectionAction
An action a section dispatches through its context.SectionAction is an
enum, not a struct — each case carries its own associated values.
enum SectionAction {
case next
case back
case dismiss
case navigate(screenId: String)
case openURL(url: String)
case openWebview(url: String)
case openAppSettings
case share(text: String)
case deepLink(url: String)
case showPaywall(id: String?)
case showSurvey(id: String?)
case showScreen(id: String)
case submitForm(data: [String: Any])
case track(event: String, properties: [String: Any]?)
case haptic(type: String)
case custom(type: String, value: String?)
// Flow-level verbs (routed by FlowManager; ignored on the single-screen path)
case restart
case complete
case setResponse(key: String, value: Any?)
case presentPaywall(id: String?)
case dismissPaywall
case showMessage(id: String?)
case setUserProperty(key: String, value: Any?)
case purchase(productId: String)
case restore
}
Properties
| Property | Type | Description |
|---|---|---|
AppDNA.sdkVersion | String | The current SDK version string (e.g., “1.0.0”). |
AppDNA.configUpdated | Notification.Name | Notification posted when remote config is updated. |

