@trevosdk/react-native runs experiments and records events in React Native and Expo apps,
assigning the same variants the web SDK does for the same user.
Pure TypeScript — no native module, no linking step, no config plugin.
Expo:
Quick start
Create the client in its own module. This example uses Expo’s public environment convention; in bare React Native, use the app’s existing runtime-config adapter.null, so AsyncStorage hydration cannot flash control to a treatment user. If
auth restores a known user, call trevo.identify(user.id) before mounting this
experiment UI.
tsk_live_…). A shipped binary can be unpacked, so a secret key
in an app is a leaked key.
Read this before you plan your first mobile experiment
Three properties of mobile are not choices we made, and every vendor shares them. Planning around them is easier than discovering them mid-experiment. A mobile cohort ramps over weeks, not days. Experiment code ships inside an app release, so your population is whoever has updated. Web reaches full traffic within a day of activation; mobile climbs as adoption climbs, and both variants coexist across app versions for as long as old builds stay installed. An experiment can be switched off without a release, but not changed. Config is re-read on every foreground, so pausing or stopping is immediate. Changing what a variant does is code, and code ships through App Store review. Anonymous users are per-device. A visitor who browses on a laptop and then opens the app is two participants until they sign in.identify() links them from that point forward;
nothing can link them retroactively. Identifying a user can change their arm because all SDKs
assign the signed-in user from the same user id. Restore auth and call identify() before
showing experiment UI; the onChange subscription above re-renders if identity changes later.
Durability
Phones lose the network constantly, are killed without warning, and have wrong clocks more often than desktops. The SDK is built around that:- Events survive a cold start. The queue is written to AsyncStorage and replayed on next launch. Delivery is at-least-once, and every event carries an idempotency key so a replay is recorded once.
- Timestamps survive a wrong clock. Each batch is stamped with
sentAtwhen it leaves the device. Ingestion compares that against its own clock to recover the device’s offset and correct every event in the batch — which is what lets a queue drained three days late land on a real timeline. Nothing is dropped for being out of range. - Assignment survives no network at all. Config is persisted, so a cold start in a lift assigns the same variant it assigned yesterday instead of falling back to control and silently switching once the network returns.
- A signed-in identity survives a relaunch.
identify()persists the user id, so the next cold start buckets on it rather than reverting to the anonymous id and splitting one person across two identities.
Gating on app version
An experiment whose variant code only exists from a given build onward should not enrol devices that cannot render it. SetminAppVersion on the experiment:
control and record no exposure, so they never appear in the
results. This requires you to pass appVersion when creating the client — without it, a
gated experiment returns control for everyone, because the SDK cannot prove the build is new
enough and guessing wrong means a broken screen.
Always pass the installed binary’s real app version, never a copied sample. Expo apps can read
it from expo-application (npx expo install expo-application):
minAppVersion; do not
hard-code it.
Options
API summary
Expo
Works in Expo Go and in development builds with no config plugin — there is no native code to link. Install AsyncStorage the Expo way:Store compliance
Apple. The package shipsios/PrivacyInfo.xcprivacy. Xcode aggregates third-party
manifests automatically — an app embedding an SDK without one is rejected at submission. It
declares product interaction and a user id, both linked, neither used for tracking, and no
required-reason APIs.
Google Play. Data safety answers you can paste into the Play Console:
The anonymous id is minted on device and is not an advertising or hardware identifier, which
is why “Device or other IDs” is No. Declaring it there invites a policy review you do
not need.