React Native SDK
React Native SDK for event tracking, error monitoring, and logging in iOS and Android mobile applications. Built on top of logstyx-js-core, the React Native SDK provides mobile-specific features including an ErrorBoundary component and a Trackable component for touch event tracking.
Installation
npm install github:devatlogstyx/logstyx-js-react-native#releaseQuick Start
import logstyx from 'logstyx-js-react-native';
import { View, Text, TouchableOpacity } from 'react-native';
function App() {
const logger = logstyx({
projectId: 'your_project_id',
appid: 'com.yourcompany.app',
endpoint: 'https://your-domain.com/api/v1/logs',
captureUncaught: true,
captureUnhandledRejections: true
});
const { ErrorBoundary, Trackable } = logger;
return (
<ErrorBoundary logger={logger}>
<View>
<Trackable
event="press"
context={{ screen: 'home' }}
data={{ action: 'signup' }}>
<TouchableOpacity>
<Text>Get Started</Text>
</TouchableOpacity>
</Trackable>
</View>
</ErrorBoundary>
);
}App ID Required
The appid should be your app's bundle identifier (e.g., com.yourcompany.app for Android or your iOS bundle ID). This is already defined in your app configuration.
Configuration
logstyx(options)
Initializes the Logstyx SDK and returns the logger instance with React Native components.
Required Options
projectId (string)
Your Logstyx project identifier.
projectId: 'proj_abc123xyz'appid (string)
Your app's bundle identifier. Use your existing Android package name or iOS bundle identifier.
Android: com.yourcompany.appname
iOS: com.yourcompany.appname
appid: 'com.yourcompany.myapp'Finding Your Bundle ID
- Android: Check
android/app/build.gradle→applicationId - iOS: Check
ios/YourApp.xcodeproj→ Bundle Identifier
Optional Options
endpoint (string)
Your Logstyx API endpoint.
endpoint: 'https://logs.yourcompany.com/api/v1/logs'captureUncaught (boolean)
Automatically capture uncaught JavaScript exceptions.
Default: false
captureUncaught: truecaptureUnhandledRejections (boolean)
Automatically capture unhandled Promise rejections.
Default: false
captureUnhandledRejections: trueErrorBoundary Component
React component that catches errors in child components and logs them to Logstyx. Prevents your entire app from crashing when an error occurs.
Basic Usage
import logstyx from 'logstyx-js-react-native';
import { View, Text } from 'react-native';
function App() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app',
endpoint: 'https://logs.example.com/api/v1/logs'
});
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger}>
<YourApp />
</ErrorBoundary>
);
}With Custom Fallback UI
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
function CustomFallbackUI({ error, errorInfo }) {
return (
<View style={styles.errorContainer}>
<Text style={styles.errorTitle}>Something went wrong</Text>
<Text style={styles.errorMessage}>
{error?.message || 'An unknown error occurred'}
</Text>
<TouchableOpacity
style={styles.reloadButton}
onPress={() => {
// Reload app or navigate to safe screen
}}>
<Text style={styles.reloadText}>Reload App</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#fff'
},
errorTitle: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 10,
color: '#d32f2f'
},
errorMessage: {
fontSize: 14,
color: '#666',
marginBottom: 20,
textAlign: 'center'
},
reloadButton: {
backgroundColor: '#2196F3',
paddingHorizontal: 20,
paddingVertical: 10,
borderRadius: 5
},
reloadText: {
color: '#fff',
fontWeight: 'bold'
}
});
function App() {
const logger = logstyx({ projectId: 'proj_abc123', appid: 'com.example.app' });
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger} fallbackUI={CustomFallbackUI}>
<YourApp />
</ErrorBoundary>
);
}Multiple Error Boundaries
Use multiple ErrorBoundary components to isolate errors to specific screens:
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
const Stack = createStackNavigator();
function App() {
const logger = logstyx({ projectId: 'proj_abc123', appid: 'com.example.app' });
const { ErrorBoundary } = logger;
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home">
{() => (
<ErrorBoundary logger={logger}>
<HomeScreen />
</ErrorBoundary>
)}
</Stack.Screen>
<Stack.Screen name="Profile">
{() => (
<ErrorBoundary logger={logger}>
<ProfileScreen />
</ErrorBoundary>
)}
</Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
);
}Props
| Prop | Type | Required | Description |
|---|---|---|---|
logger | object | Yes | The logger instance from logstyx() |
fallbackUI | component | No | Custom error UI component |
children | node | Yes | Child components to protect |
Trackable Component
Declarative component for tracking touch interactions in React Native.
Basic Usage
import logstyx from 'logstyx-js-react-native';
import { TouchableOpacity, Text } from 'react-native';
function MyComponent() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
const { Trackable } = logger;
return (
<Trackable event="press" data={{ action: 'button_press' }}>
<TouchableOpacity>
<Text>Press Me</Text>
</TouchableOpacity>
</Trackable>
);
}With Context
Add persistent context that applies to the event:
<Trackable
event="press"
context={{ screen: 'checkout', step: 'payment' }}
data={{ method: 'credit_card', amount: 99.99 }}>
<TouchableOpacity>
<Text>Complete Purchase</Text>
</TouchableOpacity>
</Trackable>Multiple Events
Track multiple touch events on a single element:
<Trackable
event="press longPress"
context={{ component: 'product_card' }}
data={{ productId: 'prod_123' }}>
<TouchableOpacity>
<Text>Product Name</Text>
</TouchableOpacity>
</Trackable>Custom Log Level
<Trackable
event="press"
level="warning"
data={{ action: 'delete_account' }}>
<TouchableOpacity>
<Text>Delete Account</Text>
</TouchableOpacity>
</Trackable>Supported Events
React Native touch events that can be tracked:
press- When user taps the elementlongPress- When user press and holdspressIn- When touch startspressOut- When touch ends
<Trackable
event="press longPress pressIn pressOut"
data={{ button: 'cta' }}>
<TouchableOpacity>
<Text>Interactive Button</Text>
</TouchableOpacity>
</Trackable>Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
event | string | Yes | - | Space-separated touch events |
context | object | No | {} | Context metadata |
data | object | No | {} | Event-specific data |
level | string | No | "info" | Log level: "info", "warning", "error", "critical" |
children | node | Yes | - | Single child component |
Single Child Required
Trackable must have exactly one child component. Wrap multiple components in a View if needed.
Manual Logging
Use the logger instance directly for manual logging:
Log Levels
import { useEffect } from 'react';
function MyScreen() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
useEffect(() => {
logger.info({
message: 'Screen mounted',
screen: 'HomeScreen'
});
return () => {
logger.info({
message: 'Screen unmounted',
screen: 'HomeScreen'
});
};
}, []);
const handleAction = async () => {
try {
logger.info({ message: 'Action started' });
const result = await performAction();
logger.info({
message: 'Action completed',
result: result.status
});
} catch (error) {
logger.error({
message: 'Action failed',
error: error.message
});
}
};
return (
<TouchableOpacity onPress={handleAction}>
<Text>Perform Action</Text>
</TouchableOpacity>
);
}Available Methods
// Info level
logger.info({ message: 'User logged in', userId: '123' });
// Warning level
logger.warning({ message: 'Low storage space' });
// Error level
logger.error({ message: 'Network request failed', error: err.message });
// Critical level
logger.critical({ message: 'App crash prevented' });
// Custom level
logger.send('custom', { message: 'Custom event' });Context Management
Set and clear context for multiple logs:
import { useEffect } from 'react';
function UserProfileScreen({ route }) {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
const { userId } = route.params;
useEffect(() => {
// Set context when screen mounts
logger.setContext({
userId: userId,
screen: 'UserProfile',
platform: Platform.OS
});
// Clear context when screen unmounts
return () => logger.clearContext();
}, [userId]);
const handleUpdate = () => {
// This log will include the context
logger.info({ message: 'Profile updated' });
};
return (
<TouchableOpacity onPress={handleUpdate}>
<Text>Update Profile</Text>
</TouchableOpacity>
);
}Complete Examples
Navigation Tracking
import { NavigationContainer } from '@react-navigation/native';
import { useEffect } from 'react';
function App() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app',
endpoint: 'https://logs.example.com/api/v1/logs'
});
const { ErrorBoundary } = logger;
const onNavigationStateChange = (state) => {
const currentRoute = getCurrentRouteName(state);
logger.info({
message: 'Screen view',
screen: currentRoute,
platform: Platform.OS
});
};
return (
<ErrorBoundary logger={logger}>
<NavigationContainer onStateChange={onNavigationStateChange}>
{/* Your navigation */}
</NavigationContainer>
</ErrorBoundary>
);
}
function getCurrentRouteName(state) {
if (!state) return null;
const route = state.routes[state.index];
if (route.state) {
return getCurrentRouteName(route.state);
}
return route.name;
}E-commerce App Tracking
import { View, Text, TouchableOpacity, Image } from 'react-native';
function ProductScreen({ product }) {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
const { Trackable } = logger;
return (
<View>
<Image source={{ uri: product.image }} />
<Text>{product.name}</Text>
<Text>${product.price}</Text>
<Trackable
event="press"
context={{ screen: 'product', productId: product.id }}
data={{ action: 'add_to_cart', price: product.price }}>
<TouchableOpacity style={styles.addButton}>
<Text>Add to Cart</Text>
</TouchableOpacity>
</Trackable>
<Trackable
event="press"
context={{ screen: 'product', productId: product.id }}
data={{ action: 'buy_now', price: product.price }}
level="info">
<TouchableOpacity style={styles.buyButton}>
<Text>Buy Now</Text>
</TouchableOpacity>
</Trackable>
<Trackable
event="press"
context={{ screen: 'product', productId: product.id }}
data={{ action: 'share' }}>
<TouchableOpacity>
<Text>Share</Text>
</TouchableOpacity>
</Trackable>
</View>
);
}Form Tracking
import { useState } from 'react';
import { View, TextInput, TouchableOpacity, Text } from 'react-native';
function SignupScreen() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
const { Trackable } = logger;
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSignup = async () => {
logger.info({
message: 'Signup attempted',
platform: Platform.OS
});
try {
await signup(email, password);
logger.info({
message: 'Signup successful',
method: 'email'
});
} catch (error) {
logger.error({
message: 'Signup failed',
error: error.message
});
}
};
return (
<View>
<Trackable
event="pressIn pressOut"
context={{ field: 'email', form: 'signup' }}>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email"
keyboardType="email-address"
/>
</Trackable>
<Trackable
event="pressIn pressOut"
context={{ field: 'password', form: 'signup' }}>
<TextInput
value={password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry
/>
</Trackable>
<Trackable
event="press"
data={{ form: 'signup', action: 'submit' }}>
<TouchableOpacity onPress={handleSignup}>
<Text>Sign Up</Text>
</TouchableOpacity>
</Trackable>
</View>
);
}App Launch Tracking
import { useEffect } from 'react';
import { Platform, Dimensions } from 'react-native';
function App() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app',
captureUncaught: true,
captureUnhandledRejections: true
});
useEffect(() => {
const { width, height } = Dimensions.get('window');
logger.info({
message: 'App launched',
platform: Platform.OS,
version: Platform.Version,
screen: `${width}x${height}`,
timestamp: Date.now()
});
}, []);
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger}>
<YourApp />
</ErrorBoundary>
);
}Best Practices
1. Initialize Once at App Root
// ✅ Good: Initialize at app root
function App() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
const { ErrorBoundary } = logger;
return (
<ErrorBoundary logger={logger}>
<NavigationContainer>
{/* Your screens */}
</NavigationContainer>
</ErrorBoundary>
);
}
// ❌ Avoid: Re-initializing in every screen
function MyScreen() {
const logger = logstyx({ /* ... */ }); // Don't do this
}2. Use Context for Screen-Specific Logs
function CheckoutScreen() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
useEffect(() => {
logger.setContext({
screen: 'checkout',
platform: Platform.OS
});
return () => logger.clearContext();
}, []);
// All logs will include the context
const handlePayment = () => {
logger.info({ message: 'Payment initiated' });
};
}3. Trackable for Simple Interactions
// ✅ Good: Use Trackable for simple taps
<Trackable event="press" data={{ action: 'download' }}>
<TouchableOpacity>
<Text>Download</Text>
</TouchableOpacity>
</Trackable>
// ✅ Good: Use manual logging for complex logic
const handleComplexAction = async () => {
logger.info({ message: 'Action started' });
try {
const result = await complexOperation();
logger.info({ message: 'Action completed', result });
} catch (error) {
logger.error({ message: 'Action failed', error: error.message });
}
};4. Enable Error Capture in Production
import { __DEV__ } from 'react-native';
const logger = logstyx({
projectId: process.env.LOGSTYX_PROJECT_ID,
appid: 'com.example.app',
endpoint: process.env.LOGSTYX_ENDPOINT,
captureUncaught: !__DEV__, // Only in production
captureUnhandledRejections: !__DEV__
});5. Track App Lifecycle Events
import { AppState } from 'react-native';
function App() {
const logger = logstyx({
projectId: 'proj_abc123',
appid: 'com.example.app'
});
useEffect(() => {
const subscription = AppState.addEventListener('change', (nextAppState) => {
logger.info({
message: 'App state changed',
state: nextAppState,
platform: Platform.OS
});
});
return () => subscription.remove();
}, []);
return <YourApp />;
}6. Use Platform-Specific Context
import { Platform } from 'react-native';
useEffect(() => {
logger.setContext({
platform: Platform.OS,
version: Platform.Version,
...Platform.select({
ios: { device: 'iPhone' },
android: { device: 'Android' }
})
});
}, []);Troubleshooting
Trackable Component Not Working
Issue: Touch events aren't being tracked
Solution: Ensure Trackable has exactly one child:
// ❌ Wrong: Multiple children
<Trackable event="press">
<TouchableOpacity>Button 1</TouchableOpacity>
<TouchableOpacity>Button 2</TouchableOpacity>
</Trackable>
// ✅ Correct: Single child
<Trackable event="press">
<View>
<TouchableOpacity>Button 1</TouchableOpacity>
<TouchableOpacity>Button 2</TouchableOpacity>
</View>
</Trackable>ErrorBoundary Not Catching Errors
Issue: Errors aren't being caught
Solution: ErrorBoundary only catches errors in child components. It cannot catch:
- Errors in event handlers (use try-catch)
- Asynchronous code (use try-catch)
- Errors in ErrorBoundary itself
// ❌ Won't be caught by ErrorBoundary
<TouchableOpacity onPress={() => {
throw new Error('Press error');
}}>
<Text>Press</Text>
</TouchableOpacity>
// ✅ Will be logged
<TouchableOpacity onPress={() => {
try {
riskyOperation();
} catch (error) {
logger.error({ message: 'Error', error: error.message });
}
}}>
<Text>Press</Text>
</TouchableOpacity>Finding Your App ID
Android:
// android/app/build.gradle
android {
defaultConfig {
applicationId "com.yourcompany.app" // This is your appid
}
}iOS:
// In Xcode:
// Target → General → Bundle Identifier
// e.g., com.yourcompany.appNetwork Errors
Issue: Logs not reaching server
Solution:
- Verify
endpointURL is correct - Check network permissions in app config
- Test endpoint accessibility from device/simulator
- Check for HTTPS requirements on iOS
Platform-Specific Notes
iOS
- Ensure App Transport Security (ATS) allows your endpoint
- Add network permission in
Info.plistif needed - Test on real devices for accurate error tracking
Android
- Add internet permission in
AndroidManifest.xml:xml<uses-permission android:name="android.permission.INTERNET" /> - Consider network security config for custom endpoints
- Test on various Android versions