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

# React Native Quickstart

> Configure, identify, and track in 5 minutes

<Info>
  **Supported on:** iOS SDK `1.0.70+` · Android SDK `1.0.42+` · React Native SDK `1.0.7+` (New Architecture only)
</Info>

This guide walks you through configuring the AppDNA SDK, identifying users, and tracking your first event in a React Native application.

## 1. Configure the SDK

Initialize AppDNA as early as possible in your app lifecycle, typically in your app entry point (`index.js`, `App.tsx`, or similar) before rendering the root component:

```typescript theme={null}
import { AppDNA } from '@appdna-ai/react-native-sdk';

async function bootstrap(): Promise<void> {
  await AppDNA.configure('adn_live_xxx', 'production', { logLevel: 'debug' });
}

void bootstrap();
```

<Note>
  **If you don't have your own Firebase:** The AppDNA SDK manages a separate named Firebase instance internally — no `firebase` package install required.

  **If you already use Firebase** in your app (via `@react-native-firebase/app` or similar): the SDK automatically initializes its own named Firebase instance from `GoogleService-Info-AppDNA.plist` (iOS) and `google-services-appdna.json` (Android). Your existing Firebase setup is not affected.
</Note>

<Warning>
  Call `AppDNA.configure(...)` exactly once before using any other SDK methods. Calling it multiple times will result in undefined behavior.
</Warning>

### Configuration Options

The `AppDNAOptions` interface lets you customize SDK behavior:

| Parameter          | Type                     | Default       | Description                                                      |
| ------------------ | ------------------------ | ------------- | ---------------------------------------------------------------- |
| `flushInterval`    | `number?`                | `30`          | Seconds between automatic event flushes                          |
| `batchSize`        | `number?`                | `20`          | Number of events to batch before flushing                        |
| `configTTL`        | `number?`                | `3600`        | Seconds before cached config is considered stale                 |
| `logLevel`         | `AppDNALogLevel?`        | `'warning'`   | Verbosity of SDK console logs                                    |
| `billingProvider`  | `AppDNABillingProvider?` | `'storeKit2'` | Billing integration to use (read by both iOS and Android)        |
| `vetoTimeout`      | `number?`                | `5`           | Seconds a veto hook may take before native applies its default   |
| `requireConsent`   | `boolean?`               | `false`       | When `true`, no event at all is emitted until `setConsent(true)` |
| `notificationIcon` | `number?`                | —             | Android-only notification small-icon drawable resource id        |

### Environment

The `AppDNAEnvironment` type controls which backend environment the SDK targets:

| Value          | Description                                       |
| -------------- | ------------------------------------------------- |
| `'production'` | Production API and configuration                  |
| `'sandbox'`    | Test builds — pair it with an `adn_test_` API key |

<Note>
  There is no `'staging'`. Which data you touch is decided by the **API-key prefix** (`adn_test_` vs
  `adn_live_`); this value only tags the SDK's own environment.
</Note>

### Log Level

The `AppDNALogLevel` type controls console log verbosity:

| Value       | Description                  |
| ----------- | ---------------------------- |
| `'none'`    | No logging                   |
| `'error'`   | Errors only                  |
| `'warning'` | Errors and warnings          |
| `'info'`    | Errors, warnings, and info   |
| `'debug'`   | All messages including debug |

<Info>
  Use `'debug'` during development to see all SDK activity. Switch to `'warning'` or `'none'` for production builds.
</Info>

### Billing Provider

The `AppDNABillingProvider` type specifies which billing system to use:

| Value          | Description                                                 |
| -------------- | ----------------------------------------------------------- |
| `'storeKit2'`  | Native StoreKit 2 on iOS, Play Billing on Android (default) |
| `'revenueCat'` | RevenueCat integration                                      |
| `'none'`       | Disable the billing module                                  |

<Note>
  On Android the SDK uses Google Play Billing under the StoreKit2 alias. RevenueCat is supported across both platforms when the native bridges are configured.
</Note>

## 2. Wait for Ready State

The SDK fetches remote configuration asynchronously. Use `onReady` to know when the SDK is fully initialized:

```typescript theme={null}
await AppDNA.onReady();
console.log('SDK ready -- remote config loaded');
```

`onReady()` takes **no callback** — it returns a Promise that resolves once the remote configuration
has been fetched and applied (immediately, if it already has).

## 3. Identify Users

Once a user signs in, call `identify` to associate events with their user ID:

```typescript theme={null}
await AppDNA.identify('user-123', {
  plan: 'premium',
  signup_date: '2025-01-15',
});
```

<Note>
  Traits are merged with any previously set traits. You do not need to pass all traits on every call -- only the ones that have changed.
</Note>

## 4. Track Events

Track user actions with `track`:

```typescript theme={null}
AppDNA.track('workout_completed', {
  duration: 45,
  type: 'strength',
});
```

`track()` is **fire-and-forget: it returns `void`, not a Promise**, so there is nothing to `await`.
Native enqueues the event and batches the upload; call `flush()` when you need delivery.

Events are batched and flushed automatically based on your `flushInterval` and `batchSize` settings.

## 5. Flush Events Manually

Force an immediate flush of all queued events:

```typescript theme={null}
await AppDNA.flush();
```

This is useful before the app enters the background or when you need to ensure events are sent immediately.

## 6. Set User Consent

Control whether the SDK collects and sends analytics data:

```typescript theme={null}
await AppDNA.setConsent(true);

// And to read the current decision back:
const granted = await AppDNA.isConsentGranted();
```

`setConsent` takes a **boolean** — there is one analytics consent decision, not one per category.

When consent is `false`, events are silently dropped and not queued. No data is sent to AppDNA
servers until consent is granted. The decision is **persisted** — `setConsent(false)` survives a
cold start.

<Warning>
  **Analytics are opt-OUT by default, and the default emits an event before the user has decided.**

  `requireConsent` defaults to `false`. At that default, `configure()` emits `sdk_initialized` —
  carrying device, OS, locale and session context — **before any consent decision exists**. That is
  the SDK's documented contract, not an accident: it is what every shipped version has done, and it
  matches Amplitude/Mixpanel/Firebase.

  **If you need a lawful basis before the first byte leaves the device (EU/UK GDPR, and similar), you
  must ask for it:**

  ```typescript theme={null}
  declare const apiKey: string;
  declare const userGranted: boolean;

  await AppDNA.configure(apiKey, 'production', { requireConsent: true });
  // Nothing is emitted — not even `sdk_initialized` — until:
  await AppDNA.setConsent(userGranted);
  ```

  With `requireConsent: true`, a user who has never been asked is treated as **denied**. Nothing else
  in the SDK will hold the events back for you.
</Warning>

## 7. Change Log Level at Runtime

Adjust the log level without reconfiguring the SDK:

```typescript theme={null}
AppDNA.setLogLevel('debug');
```

Valid levels: `'none'`, `'error'`, `'warning'`, `'info'`, `'debug'`.

## 8. Remote Config and Feature Flags

Retrieve server-side configuration values:

```typescript theme={null}
const welcomeMessage = await AppDNA.getRemoteConfig('welcome_message');
```

Check whether a feature flag is enabled:

```typescript theme={null}
const darkModeEnabled = await AppDNA.isFeatureEnabled('dark_mode');
```

## 9. Experiments

Get the variant assigned to a user for an experiment:

```typescript theme={null}
const variant = await AppDNA.getExperimentVariant('paywall_test');
```

Check if the user is in a specific variant:

```typescript theme={null}
const isInVariantB = await AppDNA.isInVariant('paywall_test', 'b');
```

Inspect all experiment exposures collected during the current session:

```typescript theme={null}
const exposures = await AppDNA.experiments.getExposures();
for (const exposure of exposures) {
  console.log(`${exposure.experimentId} → ${exposure.variant}`);
}
```

Each exposure is a `Record<string, unknown>` carrying `experimentId` and `variant`.

## 10. Session Data

Store cross-module session data that can be used in template interpolation across onboarding flows, paywalls, and in-app messages:

```typescript theme={null}
// Store session data — positional (key, value)
await AppDNA.session.set('selected_plan', 'premium');
await AppDNA.session.set('referral_code', 'FRIEND2026');

// Retrieve session data
const plan = await AppDNA.session.get('selected_plan'); // "premium"

// Clear all session data
await AppDNA.session.clear();
```

Session data values are accessible in Console-configured content using template syntax: `{{session.selected_plan}}`. See the [Rich Media](/sdks/react-native/rich-media) guide for the full template namespace (`{{user.*}}`, `{{session.*}}`, `{{device.*}}`, `{{remote_config.*}}`).

## 11. Entitlements

Check whether the user has any active subscription (StoreKit, Play Billing, RevenueCat, or web entitlement):

```typescript theme={null}
const isSubscribed = await AppDNA.billing.hasActiveSubscription();
```

Subscribe to live entitlement updates so your UI reflects renewals, cancellations, and restored purchases without polling:

```typescript theme={null}
const unsubscribe = AppDNA.billing.onEntitlementsChanged((entitlements) => {
  const active = entitlements.filter((e) => e.status === 'active');
  console.log(`Active entitlements: ${active.length}`);
});
```

See the [Billing](/sdks/react-native/billing) guide for the full purchase and restore flow.

## 12. Web Entitlement

Retrieve the current web entitlement (subscriptions granted outside the app store, e.g. via Stripe):

```typescript theme={null}
const ent = await AppDNA.getWebEntitlement();
```

Listen for web entitlement changes in real time:

```typescript theme={null}
const unsubscribe = AppDNA.onWebEntitlementChanged((ent) => {
  console.log('Web entitlement changed:', ent);
});
```

## 13. Deferred Deep Links

Check for a deferred deep link that brought the user to your app on first launch:

```typescript theme={null}
const link = await AppDNA.checkDeferredDeepLink();
if (link) {
  // Navigate to the linked content
}
```

## 14. Get SDK Version

Print the underlying native SDK version (useful for support tickets):

```typescript theme={null}
const version = await AppDNA.getSdkVersion();
console.log(`Native SDK version: ${version}`);
```

## 15. Reset on Logout

When a user signs out, call `reset` to clear the user identity and flush any remaining events:

```typescript theme={null}
await AppDNA.reset();
```

This clears the identified user, generates a new anonymous ID, and flushes queued events.

## 16. Shutdown

When the app is terminating, shut down the SDK to ensure all events are flushed and resources are released:

```typescript theme={null}
await AppDNA.shutdown();
```

On both iOS and Android this flushes queued events and releases native resources. The wrapper also
detaches every delegate, veto handler, and cached config snapshot, so a later `configure()` starts
clean.

<Check>
  You now have the SDK configured with user identification, event tracking, remote config, experiments, entitlements, and deep links working. Continue to the module-specific guides for [Push Notifications](/sdks/react-native/push), [Billing](/sdks/react-native/billing), [Onboarding](/sdks/react-native/onboarding), and [Paywalls](/sdks/react-native/paywall).
</Check>
