source and use the
same call.
Installing the key
Callactivate once, early in your app’s life and before creating a session. The key is a single string.
xcconfig that is not
committed, a BuildConfig field fed from local.properties or CI secrets, or your existing config system. The
key is bound to your app identifiers and cannot be used by another app, so a leaked key does not let anyone else
ship the SDK, but it is still licensed material.
activate is synchronous and fast, and safe from any thread. After it succeeds, VitalsSDK.licenseStatus
returns the parsed status; before that it is nil / null, and creating a session (or calling start()) throws
notActivated. The app identifier it checks is Bundle.main.bundleIdentifier on iOS and the application id
(context.packageName) on Android. The key is held in memory only; activate again on every launch.
Key format
LicenseStatus exposes licensee, apps, features, updatesUntil, type (iOS LicenseType.binary /
.source, Android LicenseType.BINARY / SOURCE) and warnings.
What updatesUntil means
Your license is perpetual.updatesUntil is the end of your maintenance period, and it works like this:
- Every SDK build carries a build date (
VitalsSDK.buildDate, for example2026-09-30). - A key accepts any SDK build whose build date is on or before
updatesUntil. - An SDK build released after
updatesUntilrefuses the key withlicenseUpdatesExpired(updatesUntil:). - Builds you already ship keep working forever. Nothing expires inside your users’ installed apps.
updatesUntil and newer builds accept it. The check compares dates
inside the key and the SDK only; it never reads the device clock, so a wrong system time cannot break a reading.
Verification order and errors
The checks run in this order and stop at the first failure:
Swift throws
VitalsError; Kotlin throws the matching VitalsException subclass (LicenseInvalid,
LicenseUpdatesExpired, LicenseNotValidForApp); the wrappers reject with the same case name in code.
Debug builds
The app-identifier check can be relaxed for development: instead of throwinglicenseNotValidForApp, activate
succeeds and adds a message to LicenseStatus.warnings naming the licensed apps. This lets you run the sample
apps and your own debug flavours under identifiers that are not on the key. The two platforms decide differently:
- Android decides at runtime: the relaxation applies when the host app is debuggable
(
ApplicationInfo.FLAG_DEBUGGABLE). A debug build of your app gets the warning; a release build is rejected. - iOS decides at compile time of the SDK module (
#if DEBUGinsideNeurofitVitals). With the SwiftPM source integration that follows your build configuration, so Debug builds get the warning. The binary xcframework is built Release and never relaxes the check, whatever your app’s configuration: use a key that lists every bundle identifier you run under, including development ones.
Several app identifiers
One key can list several identifiers (production, staging, a white-label variant). Ask NEUROFIT to include every identifier you ship under. Adding an identifier later means a new key; the old key keeps working.Rotation and re-issue
Keys are signed by NEUROFIT’s production signing key and carry itskid. If NEUROFIT ever rotates the signing
key, the SDK build that carries the new public key ships together with re-issued keys for every licensee under
maintenance, and the release notes say so. Builds you already ship are unaffected. Lost keys are re-issued on
request; there is nothing to revoke on the device.
Source licenses
A source license ships the engine and SDK sources. Your build still callsactivate with a key of type source,
which verifies the same way. Because you build from source, you can also replace the compiled-in public key or the
check itself; the license agreement, not the key, is what governs your use.
Questions
Licensing questions go to contact@neurofit.app. Include your licensee name and thekid from your key.