AppActor.shared, but the important lifecycle boundary is the static AppActor.configure(...) call.
Configure once
configure(...)is not a passive init. It establishes local identity, starts watchers, warms offerings, and runs bootstrap before it returns.- call it once during app launch, not every time you open a paywall
- use
AppActor.sharedonly after configure has completed
Anonymous vs identified users
- omit
appUserIdto reuse a cached local ID or create a new anonymous customer - pass
appUserIdwhen your app already has account identity - use
try await AppActor.shared.logIn(newAppUserId: "...")when a guest becomes an identified user later - use
try await AppActor.shared.logOut()to leave an identified customer and rotate back to a fresh anonymous local customer
Reset semantics
await AppActor.shared.reset() is the strong local reset path.
- it returns the SDK to idle
- it is stronger than logout
- use it for testing, wrapper restarts, or deliberate local state wipes
Customer state delivery
AppActor.shared.customerInfois the SwiftUI-friendly published propertyonCustomerInfoChangedis the simpler callback path for UIKit or non-reactive consumers- stale async responses are dropped after identity changes, so old login results should not overwrite the new customer
Startup details that matter
- if you use Apple Search Ads tracking, enable the native helper after configure completes
- if you rely on promoted purchases, register
onPurchaseIntentbefore configure so early intents are not missed - configure already runs receipt and entitlement warm-up, so later reads should be made against a prepared runtime
Logout caveats
logOut() is not a hosted session API. It is a local identity transition helper.
- it throws if the current user is already anonymous
- it clears current customer state before the new anonymous runtime is ready
- it does not represent a server-side account logout on its own