React Native SDK (iOS & Android, Expo)
Run experiments and feature flags on iOS and Android via React Native or Expo
@abmeter/react-native is pure JavaScript - fetch, AsyncStorage, and AppState - so it works in Expo Go with no native build required, unlike SDKs that ship native modules.
Add It to Your App
@abmeter/react-native is a thin adapter over the same abmeter core the browser SDK uses - AsyncStorage instead of localStorage, app-state transitions instead of tab events. Install all three packages:
npm install @abmeter/react-native abmeter @react-native-async-storage/async-storage
In an Expo app, install AsyncStorage with npx expo install @react-native-async-storage/async-storage so its version matches your Expo SDK.
Then configure it with a publishable key - one that begins with pk_, minted on the
API Keys page (available after signing in).
It is safe to ship in your app bundle: the server restricts it to the three endpoints this SDK uses. Secret keys (api-...) are rejected.
import * as abmeter from '@abmeter/react-native';
abmeter.configure({ apiKey: 'pk_your_publishable_key' });
await abmeter.ready();
const color = abmeter.resolveParameter('checkout-button-color') ?? 'green';
abmeter.trackEvent('purchase');
That is a complete integration. The ?? 'green' fallback is what renders when no experiment is running, so the app is correct before you create anything in ABMeter. The anonymous identity lives in AsyncStorage and settles behind ready(), so a returning user keeps their id — and their variant — across app launches.
Core Concepts
Parameters represent feature variations - a parameter has a set of possible values assigned to users through experiments or feature flags. Use resolveParameter to read the value for the current user.
Events are user actions you want to measure - screen views, purchases, taps. Track them with trackEvent to analyze how parameter variations affect behavior.
Users are identified by a userId - the randomization unit. Anonymous users get one generated for them, persisted in AsyncStorage across app launches, so a returning user keeps seeing the same variation. Pick one id per user and stay with it: switching mid-experiment, such as across the login boundary, re-randomizes them.
Reading Values
await abmeter.ready();
const buttonColor = abmeter.resolveParameter('checkout-button-color');
// => 'blue' (the assigned variant's value for this user)
Returns undefined for a parameter no experiment or feature flag controls. The call makes no network request - it reads a value already fetched - and records that this user saw it.
Tracking Events
abmeter.trackEvent('purchase', { price: 49.99, currency: 'USD' });
There is no user-id argument, unlike the server-side SDKs. The event belongs to whoever configure established, which in an app is the only person there is.
Nothing is sent right away: events are batched and submitted in the background, and the queue drains when the app moves to the background. If the OS kills the app before that flush completes, that tail is lost - the SDK treats network loss as expected and never throws. Call abmeter.flush() at moments you want an eager drain.
API
| Function | Description |
|---|---|
configure(options) |
Initialize the SDK. apiKey is required; baseUrl, user, flushInterval, logger, and errorCallback are optional. |
ready() |
Resolves once the first assignment fetch has completed. |
resolveParameter(slug) |
The value assigned to this user, or undefined. Queues an exposure lazily. |
trackEvent(slug, fields?) |
Queue an event for the configured user. |
flush() |
Drain the queue now. Returns a promise. |
reset(options?) |
Drain fully and tear down timers and listeners. Call configure again to restart. |
Every read and track function is error-safe: failures are logged, passed to errorCallback when you supply one, and return a safe default rather than throwing.
Where Assignments Come From
Like the browser SDK - and unlike the Ruby and Python SDKs - this SDK never receives assignment rules, salts, or audience definitions: shipping them in an app bundle would expose every experiment you are running and let anyone holding the key forge assignments for arbitrary user ids.
Instead it asks ABMeter for pre-evaluated assignments for the current user and caches the resulting value map in AsyncStorage. One request per user per session, refreshed in the background. Everything after that is local: resolving a parameter is a map lookup, and the app never holds enough information to work out anyone else's assignment.
Next Steps
- JavaScript SDK → - the same core in the browser
- Quick Start Guide → - MCP-guided setup for managing experiments with AI
- Setup MCP Connection → - Connect ABMeter to Claude or other MCP clients