sdk-react-native Reference
@emit-vision/sdk-react-native wraps sdk-js for React Native environments, replacing browser-specific APIs with React Native equivalents. It works with both bare React Native and Expo.
Installation
npm install @emit-vision/sdk-react-native @emit-vision/sdk-jsOptional (recommended):
npm install @react-native-async-storage/async-storage @react-native-community/netinfoQuick start
Call initRN early in your app (e.g., App.tsx) and pass in platform APIs you want to use:
import { useEffect } from "react";
import { AppState, ErrorUtils } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import NetInfo from "@react-native-community/netinfo";
import { initRN } from "@emit-vision/sdk-react-native";
export function App() {
useEffect(() => {
let client: Awaited<ReturnType<typeof initRN>> | undefined;
initRN({
dsn: process.env.EXPO_PUBLIC_EMIT_VISION_DSN,
environment: process.env.NODE_ENV,
asyncStorage: AsyncStorage,
appState: AppState,
netInfo: NetInfo,
errorUtils: ErrorUtils,
}).then((c) => {
client = c;
});
return () => {
client?.close();
};
}, []);
return <Router />;
}All asyncStorage, appState, netInfo, and errorUtils options are optional — pass only what you need.
initRN(options)
Async function that initialises the SDK and sets up React Native lifecycle hooks.
import { initRN } from "@emit-vision/sdk-react-native";
const client = await initRN({
apiKey: "your-api-key",
endpoint: "https://your-emit-vision-instance.com",
asyncStorage: AsyncStorage, // persists anonymous session ID
appState: AppState, // flushes events when app goes to background
netInfo: NetInfo, // flushes events when connectivity is restored
errorUtils: ErrorUtils, // captures unhandled JS errors
});
// Later, when shutting down:
client.close();Options
All sdk-js init() options are accepted, plus:
| Option | Type | Description |
|---|---|---|
asyncStorage | AsyncStorageLike | Persists the anonymous session ID across app restarts |
appState | AppStateLike | Flushes the event queue when the app goes to background |
netInfo | NetInfoLike | Flushes when the device comes back online |
errorUtils | ErrorUtilsLike | Captures unhandled JS errors via ErrorUtils.setGlobalHandler |
Auto-capture
- Page views: disabled — there is no DOM in React Native.
- Unhandled JS errors: set via
ErrorUtils.setGlobalHandlerwhenerrorUtilsis provided andautoCapture.errorsis notfalse. - Unhandled promise rejections: not automatically captured in RN (different runtime guarantees). Track manually with
captureError.
useEmitVision()
Returns all SDK capture functions for use inside components.
import { useEmitVision } from "@emit-vision/sdk-react-native";
function SaveButton() {
const { captureEvent } = useEmitVision();
return (
<TouchableOpacity onPress={() => captureEvent("settings_saved")}>
<Text>Save</Text>
</TouchableOpacity>
);
}Available methods:
| Method | Description |
|---|---|
captureEvent(name, props?) | Record a product event |
captureError(error, opts?) | Record a handled error |
identify(userId, traits?) | Associate events with a user |
group(groupId, traits?) | Associate events with a group |
consent() | Unlock the queue after user consent |
flush() | Force an immediate send |
setContext(ctx) | Add ambient context to all subsequent events |
setTags(tags) | Add ambient tags to all subsequent events |
Identifying users
import { identify } from "@emit-vision/sdk-react-native";
// After login:
identify("user_123", { email: "[email protected]" });Consent mode
Same as sdk-js — pass consentRequired: true to initRN and call consent() after the user accepts:
await initRN({ apiKey: "...", consentRequired: true });
// After user accepts:
import { consent } from "@emit-vision/sdk-react-native";
await consent();Injecting platform APIs
If you prefer not to install the optional peer packages, you can adapt any storage or network layer by implementing the corresponding interface:
import type { AsyncStorageLike } from "@emit-vision/sdk-react-native";
import { MMKV } from "react-native-mmkv";
const mmkv = new MMKV();
const mmkvStorage: AsyncStorageLike = {
getItem: (key) => Promise.resolve(mmkv.getString(key) ?? null),
setItem: (key, value) => {
mmkv.set(key, value);
return Promise.resolve();
},
};
await initRN({ apiKey: "...", asyncStorage: mmkvStorage });Batch compression
Event batches larger than 8 KB are automatically gzipped and sent with the Content-Encoding: gzip header. The API accepts both compressed and uncompressed bodies.
React Native runtimes vary in their support for the standard CompressionStream API — notably, some older or polyfilled environments lack it entirely. If CompressionStream is unavailable, the SDK automatically falls back to sending uncompressed JSON — no configuration needed.