React Native UI State Snapshot & Replay SDK - Reproduce any UI bug exactly as the user saw it
npm install @ui-snapshot-replay/react-nativeReproduce any UI bug exactly as the user saw it — without guessing.
A lightweight React Native SDK that captures UI state, navigation, and user actions to enable exact bug reproduction. No video recording required — lighter, safer, and cheaper.
- ✅ React Component State Capture - Capture props, state, and component hierarchy
- ✅ Navigation Stack Snapshot - Track current route, params, and navigation history
- ✅ User Action Tracking - Record taps, scrolls, inputs, focus, and blur events
- ✅ Device & OS Metadata - Collect platform, OS version, device model, and screen dimensions
- ✅ PII Redaction - Built-in rules to safely mask or remove sensitive data
- ✅ State Replay - Restore UI state and replay user actions for debugging
``bash`
npm install @ui-snapshot-replay/react-nativeor
yarn add @ui-snapshot-replay/react-native
- react-native-device-info - For device metadata collection
`bash`
npm install react-native-device-info
`typescript
import UISnapshotReplaySDK from '@ui-snapshot-replay/react-native';
import { NavigationContainerRef } from '@react-navigation/native';
// Create SDK instance
const sdk = new UISnapshotReplaySDK({
maxUserActions: 50, // Keep last 50 actions
captureInterval: 1000, // Capture state every second
enabled: true,
redactionRules: [
{
path: 'props.email',
type: 'mask',
pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
},
],
});
// Initialize with navigation ref (if using React Navigation)
const navigationRef = useRef
sdk.initialize(navigationRef.current);
`
`typescript
import { ComponentStateCapture } from '@ui-snapshot-replay/react-native';
// In your component
const MyComponent = ({ email, password }) => {
const [state, setState] = useState({ count: 0 });
// Capture state when needed (e.g., on error)
const captureState = () => {
const componentState = new ComponentStateCapture().captureComponentState(
'MyComponent',
{ email, password },
state
);
// Add to snapshot
sdk.captureSnapshot([componentState]);
};
return
};
`
`typescript
import { TouchableOpacity, TextInput, ScrollView } from 'react-native';
// Get action tracker
const actionTracker = sdk.getActionTracker();
// Track taps
actionTracker.trackTap(
{ componentName: 'SubmitButton', testID: 'submit-btn' },
{ x: 100, y: 200 }
);
// Your handler
}}
>
Submit
// Track inputs
actionTracker.trackInput(text, {
componentName: 'EmailInput',
testID: 'email-input',
});
// Your handler
}}
/>
// Track scrolls
const { contentOffset } = event.nativeEvent;
actionTracker.trackScroll(
{ x: contentOffset.x, y: contentOffset.y },
{ componentName: 'ProductList' }
);
}}
>
{/ content /}
`
`typescript
// Capture complete UI state
const snapshot = await sdk.captureSnapshot([
// Component states (optional - can be empty)
]);
// Export to JSON
const json = UISnapshotReplaySDK.exportSnapshot(snapshot);
console.log(json);
// Save to file or send to server
`
`typescript
// Import from JSON
const snapshot = UISnapshotReplaySDK.importSnapshot(jsonString);
// Set up replay callbacks
sdk.setStateRestoreCallback((componentName, props, state) => {
// Restore component state
console.log(Restoring ${componentName}:, props, state);
});
sdk.setActionReplayCallback((action) => {
// Replay action
console.log('Replaying action:', action);
});
// Replay the snapshot
await sdk.replaySnapshot(snapshot, {
restoreNavigation: true,
restoreComponentState: true,
replayUserActions: true,
speed: 1.0, // 1x speed
});
`
Protect sensitive data with redaction rules:
`typescript
// Add custom redaction rules
sdk.addRedactionRule({
path: 'props.apiKey',
type: 'remove', // 'mask', 'remove', or 'hash'
});
sdk.addRedactionRule({
path: 'state.userToken',
type: 'mask',
});
sdk.addRedactionRule({
path: 'value',
type: 'remove',
pattern: /password/i, // Only redact if pattern matches
});
`
The SDK includes default rules for common PII:
- Email addresses (masked)
- Passwords (removed)
- Credit card numbers (masked)
- Phone numbers (masked)
- SSN (removed)
Main SDK class.
#### Constructor
`typescript`
new UISnapshotReplaySDK(config?: SnapshotConfig)
#### Methods
- initialize(navigationRef?) - Initialize with navigation refcaptureSnapshot(componentStates?)
- - Capture UI snapshotreplaySnapshot(snapshot, options?)
- - Replay a snapshotgetActionTracker()
- - Get user action trackeraddRedactionRule(rule)
- - Add PII redaction rulesetEnabled(enabled)
- - Enable/disable captureupdateConfig(config)
- - Update configurationsetStateRestoreCallback(callback)
- - Set component state restore callbacksetActionReplayCallback(callback)
- - Set action replay callbackdestroy()
- - Cleanup resources
Track user interactions.
#### Methods
- trackTap(target?, coordinates?, metadata?) - Track taptrackScroll(coordinates, target?, metadata?)
- - Track scrolltrackInput(value, target?, metadata?)
- - Track inputtrackFocus(target?, metadata?)
- - Track focustrackBlur(target?, metadata?)
- - Track blurgetActions()
- - Get all actionsgetLastActions(count)
- - Get last N actionsclear()
- - Clear all actionssetMaxActions(max)
- - Set max actions to keepsetEnabled(enabled)
- - Enable/disable tracking
`typescript
import { ErrorBoundary } from 'react-error-boundary';
const ErrorFallback = ({ error, resetErrorBoundary }) => {
const handleReport = async () => {
// Capture snapshot when error occurs
const snapshot = await sdk.captureSnapshot();
// Send to your error reporting service
await fetch('https://your-api.com/errors', {
method: 'POST',
body: JSON.stringify({
error: error.message,
stack: error.stack,
snapshot: UISnapshotReplaySDK.exportSnapshot(snapshot),
}),
});
resetErrorBoundary();
};
return (
);
};
// Use in your app
`
Full TypeScript definitions are included. Import types as needed:
`typescript``
import type {
UISnapshot,
SnapshotConfig,
ReplayOptions,
UserAction,
ComponentState,
NavigationState,
DeviceMetadata,
RedactionRule,
} from '@ui-snapshot-replay/react-native';
- Component state capture requires manual integration or React DevTools protocol
- Navigation tracking works best with React Navigation
- Action replay requires custom implementation for your UI components
- Large component trees may impact performance
MIT
Contributions welcome! Please open an issue or PR.