> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appdna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS API Reference

> Complete method reference for AppDNASDK

<Info>
  **Supported on:** iOS SDK `1.0.61+`
</Info>

This is the complete reference for all public methods, properties, types, and delegate protocols in the AppDNA iOS SDK.

## 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 the `AppDNA` 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

```swift theme={null}
protocol AppDNAPushDelegate {
    func onPushTokenRegistered(token: String)
    func onPushReceived(notification: PushPayload, inForeground: Bool)
    func onPushTapped(notification: PushPayload, actionId: String?)
}
```

### AppDNABillingDelegate

```swift theme={null}
protocol AppDNABillingDelegate {
    func onPurchaseCompleted(productId: String, transaction: TransactionInfo)
    func onPurchaseFailed(productId: String, error: Error)
    func onEntitlementsChanged(entitlements: [Entitlement])
    func onRestoreCompleted(restoredProducts: [String])
}
```

### AppDNAOnboardingDelegate

```swift theme={null}
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

```swift theme={null}
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

```swift theme={null}
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

```swift theme={null}
protocol AppDNASurveyDelegate {
    func onSurveyPresented(surveyId: String)
    func onSurveyCompleted(surveyId: String, responses: [SurveyResponse])
    func onSurveyDismissed(surveyId: String)
}
```

### AppDNADeepLinkDelegate

```swift theme={null}
public protocol AppDNADeepLinkDelegate: AnyObject {
    func onDeepLinkReceived(url: URL, params: [String: String])
}
```

***

## Key Types

### AppDNAOptions

```swift theme={null}
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

```swift theme={null}
enum Environment {
    case production
    case sandbox
}
```

### LogLevel

```swift theme={null}
enum LogLevel {
    case none
    case error
    case warning
    case info
    case debug
}
```

### BillingProvider

```swift theme={null}
enum BillingProvider {
    case storeKit2
    case revenueCat
    case adapty(apiKey: String)
    case none
}
```

### PaywallContext

```swift theme={null}
struct PaywallContext {
    let placement: String
    let experiment: String?
    let variant: String?
    let customData: [String: Any]?   // Merged into the `paywall_view` event's properties
}
```

### OnboardingContext

```swift theme={null}
struct OnboardingContext {
    var source: String?
    var campaign: String?
    var referrer: String?
    var userProperties: [String: Any]?
    var experimentOverrides: [String: String]?
}
```

### PushPayload

```swift theme={null}
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

```swift theme={null}
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

```swift theme={null}
struct TransactionInfo {
    var transactionId: String
    var productId: String
    var purchaseDate: Date
    var environment: String
}
```

### ProductInfo

```swift theme={null}
struct ProductInfo {
    var id: String
    var displayName: String
    var description: String
    var price: Decimal
    var displayPrice: String
    var subscription: SubscriptionInfo?
}
```

### Entitlement

```swift theme={null}
struct Entitlement {
    var identifier: String
    var isActive: Bool
    var expiresAt: Date?
    var productId: String
}
```

### WebEntitlement

```swift theme={null}
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

```swift theme={null}
struct DeferredDeepLink {
    var screen: String
    var params: [String: String]
    var visitorId: String
}
```

### PaywallAction

```swift theme={null}
enum PaywallAction {
    case ctaTapped
    case featureSelected
    case planChanged
    case linkTapped
    case custom
}
```

### DismissReason

```swift theme={null}
enum DismissReason {
    case purchased
    case dismissed
    case tappedOutside
    case programmatic
}
```

### StepAdvanceResult

```swift theme={null}
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

```swift theme={null}
struct StepConfigOverride {
    var fieldDefaults: [String: Any]?
    var title: String?
    var subtitle: String?
    var ctaText: String?
    var layoutOverrides: [String: Any]?
}
```

### FormFieldType

```swift theme={null}
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

```swift theme={null}
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

```swift theme={null}
enum ScreenError: String, Codable {
    case configFetchFailed
    case configFetchTimeout
    case screenNotFound
    case configParseError
    case configInvalid
    case nestingDepthExceeded
}
```

### ScreenResult

```swift theme={null}
struct ScreenResult {
    let screenId: String
    let dismissed: Bool
    let responses: [String: Any]
    let lastAction: String?
    let duration_ms: Int
    let error: ScreenError?
}
```

### FlowResult

```swift theme={null}
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.

```swift theme={null}
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. |
