Skip to content
Mobile Joe Docs Dashboard
View Markdown

iOS · Android · SDK

Identity and data

How the SDK identifies app users, connects them to your accounts, and what it stores and sends.

Anonymous by default

On first configuration, the SDK creates an anonymous identity and stores it on the device. Later launches reuse it. Apps without their own accounts need nothing else and should not call identify. Feature plan votes belong to the identity; FAQs and alerts are the same for every identity.

Sign in

Pass your account ID during configuration when the user is already signed in at launch, or identify the user after sign-in:

PlatformAt configurationAfter sign-in
iOStry Joe.configure(withAPIKey:appUserID:)try Joe.identify(appUserID:)
AndroidJoe.configure(applicationContext, apiKey, appUserId = …)Joe.identify(appUserId)

The first identification keeps the anonymous ID, so votes cast before sign-in carry over to the account. Identifying the same account again changes nothing, and configuring without an app user ID keeps the stored identity, including a signed-in account. Devices identified with the same app user ID share their votes.

Choose an app user ID

  • Stable and unique: an ID that belongs to exactly one account and never changes, such as your account's primary key.
  • Not personal data: no email address or phone number.
  • Not temporary: no placeholders, receipt IDs, or purchase SDK IDs that change after a restore, such as anonymous RevenueCat IDs.
  • Not empty: a blank ID throws MobileJoeError.invalidAppUserID on iOS and IllegalArgumentException on Android.

Sign out and switch accounts

After sign-out, call Joe.logout(). The SDK continues with new anonymous and device IDs; the account keeps its votes. Identifying a different account logs out first, so you do not need to call logout() before switching.

Identify requests

The SDK sends the identity to Mobile Joe in the background, once per app start and once per identity change. If that fails, the SDK stays usable and retries on the next app start.

Order of calls

Configure once at app start; further configure calls change nothing until the app relaunches. identify and logout() take effect immediately, in call order, and throw when the identity cannot be stored. identify also throws before configuration; logout() does too on Android, while on iOS it replaces the stored identity locally.

Identifiers

IdentifierFormatPurpose
Anonymous ID $MBJAnonymousID: followed by a random UUID as 32 hex characters Identifies the app user, for example for votes. Created without an account.
Device ID $MBJDeviceID: followed by a random UUID as 32 hex characters Identifies the installation of an app user. It is generated by the SDK, not read from the hardware.
External ID $MBJExternalID: followed by the first 32 hex characters of the unsalted SHA-256 hash of your app user ID Optional. Associates the app user with an account in your app across devices. Only set after configuring or identifying with an app user ID.

The SDK never sends the app user ID itself. The hash is unsalted, so use an opaque account ID.

Local storage

Both SDKs store exactly one identity: the anonymous ID, the device ID, and the external ID if set.

PlatformLocationFormat
iOS Application Support/MobileJoe/identity.mbj in the app container JSON file, written without a Data Protection class
Android Private SharedPreferences file dev.mobilejoe.identity Keys anonymous_id, device_id, and external_id

The SDKs store nothing else, apart from the iOS response cache.

Backups

The SDKs do not exclude the identity from backups. Platform rules apply:

  • iOS: the Application Support directory is part of iCloud and computer backups. To exclude the identity, set isExcludedFromBackup on the Application Support/MobileJoe directory.
  • Android: SharedPreferences are part of Auto Backup unless your app disables or limits it. To exclude the identity, add dev.mobilejoe.identity.xml in the sharedpref domain to your backup rules.
<exclude domain="sharedpref" path="dev.mobilejoe.identity.xml" />

On Android 12 and higher, add the rule to cloud-backup and device-transfer in your data extraction rules. On earlier versions, add it to your full backup content rules.

Request metadata

Each request to the API contains these headers:

HeaderiOSAndroid
AuthorizationPublic SDK API keyPublic SDK API key
Identity-Anonymous-IDAnonymous IDAnonymous ID
Identity-Device-IDDevice IDDevice ID
Identity-External-IDExternal ID, only when setExternal ID, only when set
Framework-VersionSDK versionSDK version
App-VersionCFBundleShortVersionStringversionName
App-Build-VersionCFBundleVersionversionCode
OS-NameiOSAndroid
OS-VersionSystem version, for example 18.2.0API level, for example 35
Device-ModelModel identifier, for example iPhone16,2Build.MODEL, for example Pixel 8
Device-BrandNot sentBuild.BRAND, for example google
Preferred-LanguagesUp to three languages of Locale.preferredLanguages at the first requestUp to three app locales at configuration
Debug-ModedebugMode passed to Joe.configureisDebugMode passed to Joe.configure

Requests also contain the parameters of the operation, such as a search term or a feature plan ID. See the REST API reference.

Response cache

The iOS SDK uses URLSession.shared, whose URLCache stores API responses in the Caches directory. The system can clear it at any time, and it is not backed up. The Android SDK does not cache responses.