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

# Dashboard vs. Code

> What you configure in the Console, what you write in code, and what's automatic

# Dashboard vs. Code

AppDNA splits responsibility between the Console (UI configuration) and your code (SDK calls). Many features require **zero code** -- the SDK handles them automatically based on what you configure in the Console.

***

## Quick Reference

| Feature                | Console                                | Your Code                                   |
| ---------------------- | -------------------------------------- | ------------------------------------------- |
| **Paywalls**           | Design layout, plans, CTA, publish     | `AppDNA.paywall.present("id")`              |
| **Onboarding flows**   | Design steps, branching rules, publish | `AppDNA.onboarding.present("welcome")`      |
| **Experiments**        | Create, set variants, allocate traffic | `AppDNA.experiments.getVariant("id")`       |
| **Feature flags**      | Create flag, toggle on/off             | `AppDNA.features.isEnabled("flag")`         |
| **Remote config**      | Set key-value pairs                    | `AppDNA.remoteConfig.get("key")`            |
| **In-app messages**    | Design message, set triggers, publish  | **None -- fully automatic**                 |
| **Surveys**            | Design survey, set triggers, publish   | **None -- automatic** (or present manually) |
| **Push notifications** | Create campaigns in Retention          | `AppDNA.setPushToken()` + register          |
| **Deep links**         | Configure routes                       | `AppDNA.checkDeferredDeepLink()`            |
| **Event tracking**     | --                                     | `AppDNA.track("event", properties)`         |
| **User identity**      | --                                     | `AppDNA.identify(userId, traits)`           |
| **Billing**            | Link store products to plans           | `AppDNA.billing.purchase("productId")`      |
| **Web entitlements**   | Stripe integration in Settings         | Automatic after `identify()`                |

***

## What's Automatic (Zero Code)

The SDK tracks these events automatically. You do not need to call `track()` for any of them.

### Session & Lifecycle

* `session_start`, `session_end`, `app_open`, `app_close`

### Onboarding

* Flow started, step viewed, step completed, step skipped, flow completed, flow dismissed

### Paywalls

* Paywall presented, actions, dismissed, purchase started/completed/failed

### Billing

* Purchase started, completed, failed, canceled, restore started/completed

### Push

* Token registered, permission granted/denied, delivered, tapped

### Experiments

* Exposure tracked once per session on first `getVariant()` call

### In-App Messages

* Message presented, action taken, dismissed

### Surveys

* Survey presented, response submitted, dismissed

<Info>
  For the full list of auto-tracked events with their properties, see the [Auto-Tracked Events](/api-reference/auto-tracked-events) reference.
</Info>

***

## Callbacks -- When You Want to React

Every SDK module provides a delegate or callback interface so you can respond to events in your own code. Common scenarios:

<Tabs>
  <Tab title="iOS">
    ```swift theme={null}
    // Unlock premium after paywall purchase
    func onPaywallPurchaseCompleted(paywallId: String, productId: String, transaction: TransactionInfo) {
        unlockPremium()
        navigateToHome()
    }

    // Capture onboarding answers for personalization
    func onOnboardingCompleted(flowId: String, responses: [String: Any]) {
        AppDNA.identify(userId: currentUserId, traits: responses)
    }

    // Route user from push notification tap
    func onPushTapped(notification: PushPayload, actionId: String?) {
        if let action = notification.action {
            navigate(to: action.value)
        }
    }

    // React to survey feedback
    func onSurveyCompleted(surveyId: String, responses: [SurveyResponse]) {
        if let nps = responses.first(where: { $0.questionId == "nps_question" }),
           let score = nps.answer as? Int, score < 7 {
            showSupportLink()
        }
    }
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={null}
    // Unlock premium after paywall purchase
    override fun onPaywallPurchaseCompleted(paywallId: String, productId: String, transaction: TransactionInfo) {
        unlockPremium()
        navigateToHome()
    }

    // Capture onboarding answers for personalization
    override fun onOnboardingCompleted(flowId: String, responses: Map<String, Any>) {
        AppDNA.identify(userId = currentUserId, traits = responses)
    }

    // Route user from push notification tap
    override fun onPushTapped(notification: PushPayload, actionId: String?) {
        notification.action?.let { navigate(it.value) }
    }
    ```
  </Tab>

  <Tab title="Flutter">
    ```dart theme={null}
    // Unlock premium after paywall purchase
    @override
    void onPaywallPurchaseCompleted(String paywallId, String productId, Map<String, dynamic> transaction) {
      unlockPremium();
      navigateToHome();
    }

    // Capture onboarding answers for personalization
    @override
    void onOnboardingCompleted(String flowId, Map<String, dynamic> responses) {
      AppDNA.identify(currentUserId, traits: responses);
    }
    ```
  </Tab>

  <Tab title="React Native">
    ```typescript theme={null}
    // Register a paywall delegate once (registering again replaces it)
    AppDNA.paywall.setDelegate({
      onPaywallPurchaseCompleted: (paywallId, productId, transaction) => {
        unlockPremium();
        navigateToHome();
      },
      // ...implement the other AppDNAPaywallDelegate methods
    });

    // Capture onboarding answers for personalization
    AppDNA.onboarding.setDelegate({
      onOnboardingCompleted: (flowId, responses) => {
        AppDNA.identify(currentUserId, responses);
      },
      // ...implement the other AppDNAOnboardingDelegate methods
    });
    ```
  </Tab>
</Tabs>

Each module's documentation includes the full delegate reference and examples. See:

<CardGroup cols={2}>
  <Card title="Paywalls" icon="credit-card" href="/sdks/ios/paywall">
    AppDNAPaywallDelegate -- purchase, dismiss, action callbacks
  </Card>

  <Card title="Onboarding" icon="list-check" href="/sdks/ios/onboarding">
    AppDNAOnboardingDelegate -- step, completion, response callbacks
  </Card>

  <Card title="Billing" icon="receipt" href="/sdks/ios/billing">
    AppDNABillingDelegate -- purchase, restore, entitlement callbacks
  </Card>

  <Card title="Surveys" icon="message" href="/sdks/ios/surveys">
    AppDNASurveyDelegate -- presentation, response, dismiss callbacks
  </Card>
</CardGroup>
