Supported on: iOS SDK
1.0.70+ · Android SDK 1.0.42+ · React Native SDK 1.0.7+ (New Architecture only)@appdna-ai/react-native-sdk package. The React Native SDK delegates rendering, business logic, and
storage to the native iOS and Android layers, so every method here resolves to native execution.
Every signature on this page is compiled against the package’s published type declarations in CI — if
a signature here disagrees with the code you install, the build fails.
Core Methods
All core methods are static on theAppDNA class.
Config Methods
Session Data
Cross-module key-value bag used by Console-configured template interpolation ({{session.*}}).
null:
What is filled depends on what the user did. Both platforms and both surfaces — a Location field on a
form step and a Location content block — store the same shape.
A coordinate that is not a finite number comes back
null. A zone the lookup could not find leaves timezone and timezone_offset both null — on every platform and surface; the SDK never makes up a "UTC". Always null-check before using a field.
A selected suggestion also carries mapbox_id when it was resolved through a permanent Mapbox geocode. It is an opaque marker of that, not a stable place id to look up (for an interpolated address it encodes the request that produced it and runs to hundreds of characters). place_id is set only on a Google answer (the Places id the user tapped). When a tapped suggestion cannot be resolved (with Mapbox, no permanent access on the account; with Google, the Geocoding API not enabled on the key; with either, any other provider error or a network failure), the answer is the typed text. On a resolved Mapbox answer, an address answer’s city is the place that contains the address, not the street name earlier releases stored; a place, locality, region or country answer keeps its own name as city; and a region answer also fills its own state / state_code, a country answer its own country / country_code, which earlier releases left empty. On a resolved Google answer, city is the first of the place’s locality, postal town, sublocality or second-level administrative area that Google reports — a city answer’s own name, an address answer’s town — so a region or country answer has no city: its own name is its state (a region) or its country (a country).
Experiments
Push (static helpers)
These mirrorAppDNA.push.* — use either style.
Presentation
Web Entitlements
Deep Links
Module Namespaces
setDelegate accepts a delegate or null. The parameter is nullable on every module: passing
null clears the delegate — its listeners are removed and no callback fires afterward.
Registering a new delegate replaces the previous one, so register once at app startup rather than
from a component that mounts and unmounts. shutdown() detaches everything.AppDNA.push
AppDNA.billing
AppDNA.onboarding
AppDNA.paywall
AppDNA.remoteConfig
AppDNA.features
AppDNA.experiments
AppDNA.inAppMessages
AppDNA.surveys
AppDNA.deepLinks
AppDNA.screens
To embed a screen inline in your own React layout instead of presenting it over the app, use
<AppDNAScreenSlot>.
AppDNA.lifecycle
Delegate Interfaces
Implement these and register them with the matching module’ssetDelegate(...).
AppDNAOnboardingDelegate
AppDNAPaywallDelegate
errorType values
onPaywallPurchaseFailed always carries one of these, so you can decide whether a retry even makes
sense without parsing a message:
AppDNAPushDelegate
AppDNABillingDelegate
AppDNAInAppMessageDelegate
AppDNASurveyDelegate
AppDNADeepLinkDelegate
AppDNAScreenDelegate
AppDNALifecycleDelegate
Onboarding events carry location answers unreduced.
onboarding_step_completed’s selection_data and
onboarding_flow_completed’s responses reach onEventTracked as the device stored them: a picked location answer
arrives whole, with the address, coordinates and time zone of the place the user picked (and a Google answer’s place ID). AppDNA reduces an answer to what
the geocoding providers’ terms allow only on its own server, after the event leaves the device. What you store or
forward from these properties is under your terms with the provider, and for a Google answer (one carrying place_id)
under your terms with Google. A Google answer you show yourself must carry Google’s attribution wherever it is shown
without a Google map.The SDK also tracks a
sdk_decode_dropped event carrying the same values, so the fleet view does
not depend on a host implementing this. The delegate exists so YOUR crash reporter can see your
own content being dropped.Components
AppDNAScreenSlot
The package’s only React component: it embeds a server-driven screen inline in your layout. See the Screens guide.Key Types
AppDNAEnvironment
There is no
'staging'. Which backend data you touch is decided by the API-key prefix
(adn_test_ for a test key, adn_live_ for a live one); this value only tags the SDK’s own
environment. Pass 'sandbox' alongside an adn_test_ key for a test build.AppDNAOptions
AppDNALogLevel
AppDNABillingProvider
StepAdvanceResult
The plain object you return fromonBeforeStepAdvance. The hook’s TypeScript return type is
Promise<Record<string, unknown>> — native decodes the type discriminator:
StepConfigOverride
The plain object you return fromonBeforeStepRender (or null to render the step unchanged):
PaywallContext
PaywallAction
Theaction string passed to onPaywallAction:
All five cases are emitted from iOS SDK 1.0.84 and Android SDK 1.0.56. Before that,
cta_tapped was
sent by Android only — the iOS SDK never called onPaywallAction at all, so the same published
paywall reported a tap on one platform and nothing on the other — and the remaining four had no
emitter anywhere.🔴
plan_changed is not sent for the default selection. A paywall selects its default plan as
it appears; that is not a choice the user made, and reporting it would put one event at the top of
every paywall session that looks like engagement and is not.🔴 The action fires BEFORE the SDK decides whether the tap can do anything. A CTA tap that
cannot resolve a plan is reported and then does nothing else — no purchase_started, no purchase
callback. That ordering is what lets you tell “the SDK never received the tap” from “the purchase
was attempted and failed”, which is otherwise the same silence. custom behaves the same way: the
renderer still falls back to its default handling, and you are told it was an action you defined.Feature rows became tappable in iOS 1.0.84 / Android 1.0.56 so that feature_selected could exist. Nothing about them
looks or reads differently, and the paywall still scrolls — the row takes a tap, not a drag.PushPayload
The notification map, with the keys native actually sends — snake_case:PushAction
One structured notification action button.id echoes back as onPushTapped’s actionId.
Entitlement
The union of what the two platforms know. A key that the running platform has no concept of is omitted, never faked — so the platform-specific fields are optional, and an absent one means “this platform does not know”, notfalse or "".
Ask isActive. It is the cross-platform question: both platforms send it, and on Android it is
derived from the Play status so you never have to learn that vocabulary.
TransactionInfo
What a successfulpurchase(...) resolves with. There is no status field: a resolved promise is
the purchase. A cancellation, a pending (deferred / ask-to-buy) purchase, and a store error all
reject — catch them, do not test a status.
ProductInfo
Platform-specific keys are omitted, never faked: an absent key means the platform has no concept of it.There is no numeric
price field. iOS’s native price is a Decimal, which cannot cross the bridge
without loss, so both platforms send integer priceMicros. Render displayPrice (already localized
and currency-formatted), or divide priceMicros by 1,000,000 when you need the number.WebEntitlement
DeferredDeepLink
Notes
Architecture
The React Native package exposes API facades, DTOs, and bridge calls; rendering, business logic, network I/O, and storage execute in the native iOS (Swift) and Android (Kotlin) SDKs. The delegate interfaces and the native module spec are generated from the same source as the iOS and Android surfaces, so the TypeScript API cannot silently drift from them.Platform-specific behavior
billingProviderapplies on both platforms ('storeKit2'= StoreKit 2 on iOS, Google Play Billing on Android). Under'revenueCat', Adapty or'none'the SDK never buys, restores, finishes or acknowledges; purchase and restore reject withproviderNotAvailable.requestPermission()onAppDNA.pushtriggers the iOS APNs prompt or the Android 13+POST_NOTIFICATIONSruntime permission.shutdown()flushes queued events and releases native resources on both platforms, and the wrapper additionally detaches every delegate, veto handler, and cached snapshot.offerTokenonpurchase(...)selects an Android base-plan offer and is ignored on iOS.onBillingUnavailablefires on Android only.notificationIconapplies on Android only.

