Appearance
React Native / Expo
The JavaScript SDK detects React Native and runs in app mode: no browser autocapture, sessions driven by AppState, and the platform's own User-Agent.
Install
sh
npx expo install simpledatalogs @react-native-async-storage/async-storage
npx simpledatalogs init # adds EXPO_PUBLIC_SIMPLEDATALOGS_KEY and simpledatalogs.tsAdd it
ts
// simpledatalogs.ts
import AsyncStorage from '@react-native-async-storage/async-storage'
import { AppState } from 'react-native'
import { init } from 'simpledatalogs'
export const sdl = init({
key: process.env.EXPO_PUBLIC_SIMPLEDATALOGS_KEY,
storage: AsyncStorage, // unsent events survive the app being killed
appState: AppState, // flush on background, sessions
autocapture: true,
defaultProperties: { app_version: '1.4.0' },
})
// Crashes and uncaught errors, as unhandled exceptions.
sdl.installGlobalHandlers()ts
import { sdl } from './simpledatalogs'
sdl.setDeviceId(installId) // an anonymous id you keep, for active devices
sdl.track('level_complete', { level: 3 })
sdl.track('screen_view', { screen: 'Settings' })What each option does
| Option | What you get |
|---|---|
storage: AsyncStorage | The outbox is saved at most once a second, and at once when the app goes to the background. Events left from the last launch go out after the next one starts. Without it, the outbox is in memory and lost if the app is killed |
appState: AppState | Going to the background saves and flushes. Without it, call sdl.handleAppStateChange(state) from your own listener |
autocapture: true | A session from launch: session_start, a session_id on every event, and a new session when the app returns after 30 minutes or more in the background. session_end is stamped when the app left the foreground. A launch in the background (a background task) starts no session until the app is active |
installGlobalHandlers() | Chains ErrorUtils: each uncaught error is sent with its Hermes stack frames, and a fatal one waits up to 1 second for the flush before the app's previous handler runs |
Any storage with getItem, setItem and removeItem works, whether they return Promises or values.
One key per platform
Create an iOS deployment and an Android deployment in the same environment, and pick the public key at runtime, so the dashboard splits the platforms:
ts
import { Platform } from 'react-native'
const key = Platform.OS === 'ios' ? process.env.EXPO_PUBLIC_SIMPLEDATALOGS_KEY_IOS : process.env.EXPO_PUBLIC_SIMPLEDATALOGS_KEY_ANDROID
export const sdl = init({ key, storage: AsyncStorage, appState: AppState, autocapture: true })Errors you catch
ts
try {
await purchase()
} catch (error) {
sdl.captureException(error, { props: { sku: 'pro_monthly' } })
}Native crashes
The SDK sees JavaScript errors only. Crashes in Swift, Kotlin or C++ code, and out-of-memory kills, never reach the JS thread, so a JS-only sender can't report them.
Re-sending safely
An event you queue yourself (an offline purchase log, for example) can keep its own id, so sending it twice counts once:
ts
sdl.track('purchase', { sku }, { eventId: purchase.uuid, ts: purchase.createdAt })In the first minute
- Your first events on the dashboard within a second or two, or at once with
await sdl.flush(). - With
setDeviceId, the device counts in active devices. - Track screens with
screen_viewevents, for example from your navigation container'sonStateChange.
Against a local ingest
- Android emulator: the Mac's
localhostis10.0.2.2, so useendpoint: 'http://10.0.2.2:4001'. - iOS simulator:
http://localhost:4001works as is. - Phone over USB: run
adb reverse tcp:4001 tcp:4001and keeplocalhost, or use the Mac's LAN address.