openobserve-react-native-rum-demo
v0.1.2
Published
OpenObserve Real User Monitoring (RUM) SDK for React Native — automatic tap tracking, fetch interception, error capture, and view tracking with zero application code changes.
Downloads
40
Maintainers
Readme
openobserve-react-native-rum-demo
OpenObserve Real User Monitoring (RUM) SDK for React Native.
Track user taps, navigation, network requests, JS errors, and app lifecycle events — automatically, with zero changes to your application code.
Features (Demo Reduced)
| Feature | Status |
|---|---|
| User taps (onPress, onLongPress) | ✅ Automatic interceptor |
| Navigation / Views | ✅ Via integration helper (trackView) |
| Fetch / XHR | ✅ Automatic interceptor |
| JS Errors | ✅ Automatic global interceptor |
| App Foreground / Background | ✅ Automatic AppState interceptor |
| Offline persistence + retry | ✅ AsyncStorage queue (FIFO) |
| User identity | ✅ setUser() |
| Custom context | ✅ setGlobalContext() |
Demo contract
- This package is intended for automatic RUM tracking in demos.
- Manual event APIs (
addAction,addError,flush) are out of the supported demo contract. - Recommended app integration should remain minimal: bootstrap/init + navigation view binding.
Installation
# npm
npm install openobserve-react-native-rum-demo
# yarn
yarn add openobserve-react-native-rum-demo
# pnpm
pnpm add openobserve-react-native-rum-demoNo native modules required.
Works in Expo Go, Expo Dev Client, and bare React Native.
Quick Start
1. Import FIRST and initialize
The SDK auto-installs all interceptors at import time (module side effect). This means the import must appear before any other component so the JSX runtime patches are in place before the first render.
// app/_layout.tsx (Expo Router) — or —
// index.js (bare RN) — or —
// App.tsx (any)
// ⬇️ MUST be the first import
import { OpenObserveRum } from 'openobserve-react-native-rum-demo';
import { AppRegistry } from 'react-native';
import App from './App';
OpenObserveRum.init({
clientToken: 'YOUR_O2_API_KEY',
applicationId: 'YOUR_APP_ID',
site: 'openobserve.example.com', // without protocol
service: 'my-app',
env: 'production', // optional, default 'production'
version: '1.0.0', // optional
// organizationIdentifier: 'default',
// insecureHTTP: false,
// debug: true, // enable verbose logging
});
AppRegistry.registerComponent('main', () => App);That's it! All taps, fetches, errors, and app-state changes are tracked automatically.
2. Track navigation (optional but recommended)
The SDK does not depend on any router — instead it exposes trackView(name) that you call from your navigation listener.
Expo Router
import { OpenObserveRum } from 'openobserve-react-native-rum-demo';
import { usePathname, useSegments } from 'expo-router';
import { useEffect } from 'react';
export default function RootLayout() {
const pathname = usePathname();
const segments = useSegments();
useEffect(() => {
if (pathname) {
OpenObserveRum.trackView(pathname);
}
}, [pathname, segments]);
return ( /* ... */ );
}React Navigation (v5 / v6)
import { OpenObserveRum } from 'openobserve-react-native-rum-demo';
import { NavigationContainer } from '@react-navigation/native';
import { useRef } from 'react';
export default function App() {
const routeNameRef = useRef<string>();
return (
<NavigationContainer
onReady={() => {
routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
}}
onStateChange={() => {
const currentRoute = navigationRef.current?.getCurrentRoute()?.name;
if (currentRoute && currentRoute !== routeNameRef.current) {
OpenObserveRum.trackView(currentRoute);
routeNameRef.current = currentRoute;
}
}}
>
{/* screens */}
</NavigationContainer>
);
}3. Identify the user (optional)
OpenObserveRum.setUser('user-123', 'Jane Doe');4. Add custom context (optional)
OpenObserveRum.setGlobalContext({
plan: 'premium',
abTestGroup: 'B',
});Offline queue sizing (pilot recommendation)
- Start with
maxPersistedEvents: 1000. - If devices may stay offline for long periods, increase to
3000-5000depending on acceptable local storage usage. - Keep
offlineRetryBaseDelayMslow enough for fast recovery (2s) and cap withofflineRetryMaxDelayMs(60s) to avoid aggressive retry loops.
How Automatic Tracking Works
User Interactions (taps)
The SDK patches the JSX runtime functions so every component with an onPress, onPressIn, or onLongPress prop is automatically wrapped. No accessibilityLabel or testID is required — the SDK extracts the action name from:
accessibilityLabeltestID- Visible text content of
children(recursively) - Component
displayName/name
JSX Transform Compatibility
React compiles JSX (<View />) into function calls. Which function depends on the JSX transform configured in your bundler:
| JSX Transform | Functions patched | When used |
|---|---|---|
| Automatic (default since React 17) | jsxDEV (dev), jsx / jsxs (prod) | Expo SDK ≥ 47, RN ≥ 0.72, CRA ≥ 4 |
| Classic | React.createElement | Older projects, or explicit runtime: 'classic' in Babel |
The SDK patches ALL of them, so it works regardless of which transform your project uses.
Look at your babel.config.js:
// Automatic (default in modern Expo / RN)
module.exports = {
presets: ['babel-preset-expo'],
// or
presets: ['module:metro-react-native-babel-preset'],
};
// → Uses automatic transform. jsxDEV (dev) / jsx+jsxs (prod) will be patched.// Classic (explicitly set)
module.exports = {
presets: [
['babel-preset-expo', { jsxRuntime: 'classic' }],
],
};
// → Uses React.createElement. Will be patched too.In both cases, the SDK works automatically. No configuration needed.
Network Requests
globalThis.fetch is monkey-patched. Every fetch call is tracked as a resource event with URL, method, status code, and duration. The SDK's own requests to the OpenObserve endpoint are excluded to avoid recursion.
JS Errors
React Native's ErrorUtils.setGlobalHandler is patched. Unhandled exceptions are captured as error events. Fatal errors trigger an immediate flush. The original error handler (red screen / LogBox) is preserved.
App Lifecycle
AppState.addEventListener('change') is used. Foreground transitions emit an application_start action. Background transitions flush all buffered events.
Offline Persistence and Retry
When network delivery fails, the SDK persists failed serialized events in an AsyncStorage queue and retries automatically with exponential backoff.
- Queue policy: FIFO (oldest events dropped first when capacity is exceeded)
- Capacity: configurable with
maxPersistedEvents - Retry backoff: configurable base/max delay
- No extra dependency is added by the SDK; it attempts to use
@react-native-async-storage/async-storageif present in the host app
Configuration Reference
OpenObserveRum.init({
// ── Required ──────────────────────────────────────────────
clientToken: string, // OpenObserve API key
applicationId: string, // Application ID in OpenObserve
site: string, // OpenObserve host (no protocol)
service: string, // Service name
// ── Optional ──────────────────────────────────────────────
env: string, // default: 'production'
version: string, // default: '0.0.0'
organizationIdentifier: string, // default: 'default'
insecureHTTP: boolean, // default: false
apiVersion: string, // default: 'v1'
sessionSampleRate: number, // 0–100, default: 100
trackResources: boolean, // default: true
trackErrors: boolean, // default: true
trackUserInteractions: boolean, // default: true
trackAppState: boolean, // default: true
maxBufferSize: number, // default: 50
flushIntervalMs: number, // default: 5000
offlinePersistenceEnabled: boolean, // default: true
maxPersistedEvents: number, // default: 1000 (FIFO trim)
offlineRetryBaseDelayMs: number, // default: 2000
offlineRetryMaxDelayMs: number, // default: 60000
debug: boolean, // default: false
// ── Advanced ──────────────────────────────────────────────
beforeSend: (event) => event | null, // modify or discard events
});API Reference
| Method | Description |
|---|---|
| OpenObserveRum.init(config) | Initialize the SDK (call once) |
| OpenObserveRum.trackView(name, context?) | Track a navigation / screen change |
| OpenObserveRum.setUser(id, name?) | Set current user identity |
| OpenObserveRum.setGlobalContext(ctx) | Merge key-value pairs into global context |
| OpenObserveRum.stop() | Stop the SDK and flush remaining events |
| OpenObserveRum.isInitialized() | Check if the SDK is running |
Compatibility
| Platform | Version | Status | |---|---|---| | React Native (bare) | >= 0.60 | Supported | | React Native (Expo Go) | SDK >= 47 | Supported | | React Native (Expo Dev Client) | SDK >= 47 | Supported | | React | >= 16.8 | Supported | | TypeScript | >= 4.0 | Full type definitions included |
Troubleshooting
Events not appearing in OpenObserve
- Enable
debug: truein the config to see detailed SDK console logs. - Verify your
clientToken,site, andapplicationIdare correct. - Confirm the package import is first in your entry file.
Taps not being tracked
- Check that
trackUserInteractions: true(default). - Temporarily set
debug: trueand verify interaction logs. - The component must have an
onPressprop — purely visual components are not tracked.
beforeSend for filtering
OpenObserveRum.init({
// ...
beforeSend: (event) => {
// Drop health-check requests
if (event.type === 'resource' && (event as any).resource?.url?.includes('/health')) {
return null;
}
return event;
},
});Author
- Author: Agustin Bua ([email protected])
- Company: VATROX
- Website: https://www.vatrox.com
License
Apache-2.0
