React Native SDK
@sentriq/react-native is a thin TurboModule bridge over the existing native iOS (Swift) and Android (Kotlin) Sentriq SDKs — it never reimplements transport, installation ID, session logic, or device-signal collection; every event still reaches POST /v1/events through the exact same native client the platform-specific SDKs use. Works in both a bare React Native app and an Expo Development Build.
Requirements
- React Native 0.76+ (the New Architecture / TurboModules — this SDK ships no legacy-bridge fallback)
- iOS 13.0+, Android
minSdk24 - Node 22.13+
Install
Not yet published to npm — install from a checked-out commit of this repository until a release process exists:
cd packages/react-native-sdk && npm pack
# then, in your app:
npm install /path/to/sentriq-react-native-0.1.0.tgzAutolinking picks it up automatically — no manual native linking step. iOS additionally needs a pod install (cd ios && pod install) since this SDK ships a CocoaPods podspec, the current standard mechanism for React Native iOS native modules.
Configure
import { Sentriq } from '@sentriq/react-native';
Sentriq.configure({ publicKey: 'pub_test_xxx' });Call this once, typically at app startup. Safe to call again later — the latest call wins, matching both native SDKs' own re-configure behavior.
SentriqOptions has no secret-key field at all — the underlying native SDK rejects a sec_... value immediately with a CONFIGURATION error.Track an event
import { Sentriq, SentriqError } from '@sentriq/react-native';
async function handleLogin(userId: string) {
try {
const result = await Sentriq.track('login', {
account: { id: userId },
screenName: 'login-screen',
});
// result.risk.decision: "allow" | "monitor" | "challenge" | "block"
} catch (error) {
const e = error as SentriqError;
// e.code: "CONFIGURATION" | "VALIDATION" | "NETWORK" | "TIMEOUT" | "CANCELLED" | "DECODING" | "API" | "NATIVE_MODULE_UNAVAILABLE"
}
}Account association
Pass account: { id: ... } to track() once you know who the current user is — your own opaque reference, never a password or email. Omit it for anonymous events.
Installation ID and session — no JS-side duplicate
This SDK has no JavaScript-side installation or session identifier of its own — the underlying native SDK (Keychain-backed on iOS, SharedPreferences-backed on Android) remains the sole authority, exactly as it is for a native-only integration. Sentriq.getInstallationId() reads it read-only, for debugging.
Native architecture
Built on TurboModules/Codegen (the React Native New Architecture) — not the legacy bridge. The generated native interface is implemented by a thin Swift class (iOS) and a thin Kotlin class (Android), each doing nothing but validate/convert arguments and delegate straight into the real native SentriqClient. See docs/architecture/REACT_NATIVE_SDK.md in the repository for the full bridge design.
Error handling
Every rejecting call throws a SentriqError with a stable code string, mapped consistently from the underlying native SDK's own typed error on both platforms:
CONFIGURATION | VALIDATION | NETWORK | TIMEOUT | CANCELLED | DECODING | API | NATIVE_MODULE_UNAVAILABLEAPI/VALIDATION errors additionally carry status, serverCode, requestId, and (validation only) fields.
Custom API URL (local/dev)
Sentriq.configure({
publicKey: 'pub_test_xxx',
apiUrl: 'http://10.0.2.2:8000', // Android emulator's alias for your host's localhost
});Expo
@sentriq/react-native works directly in an Expo Development Build — there is no separate Expo package and no config plugin. A Development Build (produced by expo prebuild) is a real bare React Native project where standard autolinking already works; this SDK needs no Info.plist/AndroidManifest.xml edits beyond what autolinking provides automatically.
Sentriq method inside Expo Go throws NATIVE_MODULE_UNAVAILABLE with a clear message, rather than silently doing nothing. Use a Development Build instead.npx expo prebuild
npx expo run:android # or: npx expo run:iosRead the public key from Expo's own client-safe env convention:
// app.config.js / .env
EXPO_PUBLIC_SENTRIQ_PUBLIC_KEY=pub_test_xxxSentriq.configure({
publicKey: process.env.EXPO_PUBLIC_SENTRIQ_PUBLIC_KEY!,
});Any EXPO_PUBLIC_* name is inlined into the JS bundle at build time — the same public/private boundary idea as Next.js's NEXT_PUBLIC_*. Never put a secret key behind this prefix.
Expo web is explicitly unsupported — every method throws NATIVE_MODULE_UNAVAILABLE rather than silently invoking a native API that doesn't exist on web. An Expo web app wanting Sentriq should use @sentriq/browser directly.
Privacy
This bridge collects no data of its own — every signal (installation ID, session, device metadata) is owned entirely by the underlying native SDK, with the same privacy guarantees documented on the iOS and Android pages.
Runtime verification limitations
- iOS: bridge source is written and reasoned through carefully, but build/runtime is not verified — no Xcode/macOS was available in the environment this SDK was built in.
- Android: the JS↔native bridge, Codegen, and the native Kotlin module all genuinely build, and the bridge module's own unit tests (including a real event sent to a real API) pass. Full end-to-end JS-engine (Hermes) runtime execution on a real device/emulator was not verified — no emulator was available.
Troubleshooting
NATIVE_MODULE_UNAVAILABLEon every call — you're running inside Expo Go (use a Development Build) or a stale build (rebuild after installing this package).- Gradle can't resolve
io.sentriq:sentriq-android— this SDK isn't published to Maven Central yet; addmavenLocal()to your app'sandroid/build.gradleand run./gradlew publishToMavenLocalfromsdks/androidfirst. With Expo,expo prebuildregeneratesandroid/build.gradleon every run, so this needs re-adding each time until a real publish exists.