@adopture/react-native
v0.1.2
Published
Privacy-first mobile analytics SDK for React Native & Expo
Maintainers
Readme
Features
- Privacy by design -- device IDs are hashed daily/monthly with rotating salts. Raw IDs never leave the device.
- Offline-first -- events are queued in AsyncStorage and sent in batches with automatic retry.
- Auto-capture -- app installs, updates, opens, backgrounds, and sessions are tracked automatically.
- Revenue tracking -- purchases, renewals, trials, cancellations, and refunds with store detection.
- React hooks --
useTrack,useScreen,useIdentifywith a simple Provider pattern. - React Navigation -- automatic screen tracking with intelligent path normalization.
- Tiny footprint -- zero native modules, works with Expo out of the box.
- Full TypeScript -- strict types, declaration files, and IntelliSense support.
Install
npx expo install @adopture/react-native @react-native-async-storage/async-storage react-native-get-random-valuesnpm install @adopture/react-native @react-native-async-storage/async-storage react-native-get-random-values
cd ios && pod installOptional dependencies
| Package | Purpose |
|---------|---------|
| @react-native-community/netinfo | Pause sending when offline, auto-flush on reconnect |
| @react-navigation/native | Automatic screen tracking via useAdoptureNavigationTracking |
| expo-localization | Detect device locale |
| expo-constants | Detect app version |
Quick start
With React hooks (recommended)
import { AdoptureProvider } from '@adopture/react-native/react';
export default function App() {
return (
<AdoptureProvider appKey="ak_your_app_key_here_000000">
<MainApp />
</AdoptureProvider>
);
}import { useTrack, useIdentify } from '@adopture/react-native/react';
function MainApp() {
const track = useTrack();
const identify = useIdentify();
const handleSignIn = async (userId: string) => {
await identify(userId);
track('signed_in', { method: 'email' });
};
return <Button title="Sign In" onPress={() => handleSignIn('user-123')} />;
}Without React hooks
import { Adopture } from '@adopture/react-native';
// Initialize once at app startup
await Adopture.init({ appKey: 'ak_your_app_key_here_000000' });
// Track events
Adopture.track('button_pressed', { screen: 'home' });
// Track screen views
Adopture.screen('settings');
// Identify users (hashed automatically)
await Adopture.identify('user-123');Screen tracking with React Navigation
import { useRef } from 'react';
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
import { AdoptureProvider, useAdoptureNavigationTracking } from '@adopture/react-native/react';
function AppNavigator() {
const navigationRef = useNavigationContainerRef();
useAdoptureNavigationTracking(navigationRef);
return (
<NavigationContainer ref={navigationRef}>
{/* your screens */}
</NavigationContainer>
);
}
export default function App() {
return (
<AdoptureProvider appKey="ak_your_app_key_here_000000">
<AppNavigator />
</AdoptureProvider>
);
}Revenue tracking
import { Adopture } from '@adopture/react-native';
// Initial purchase
Adopture.trackPurchase({
productId: 'pro_monthly',
price: 9.99,
currency: 'USD',
transactionId: 'txn_abc123',
});
// Subscription renewal
Adopture.trackRenewal({
productId: 'pro_monthly',
price: 9.99,
currency: 'USD',
});
// Trial started
Adopture.trackTrialStarted({
productId: 'pro_monthly',
expirationAt: '2026-05-08T00:00:00Z',
});
// Trial converted to paid
Adopture.trackTrialConverted({
productId: 'pro_monthly',
price: 9.99,
currency: 'USD',
});
// Cancellation
Adopture.trackCancellation({ productId: 'pro_monthly' });
// Refund
Adopture.trackRefund({
productId: 'pro_monthly',
price: 9.99,
currency: 'USD',
});Configuration
await Adopture.init({
appKey: 'ak_your_app_key_here_000000',
debug: false, // Enable verbose logging + immediate sends
autoCapture: true, // Track lifecycle events automatically
flushIntervalMs: 30000, // Send batches every 30s
flushAt: 20, // Send when 20 events are queued
maxQueueSize: 1000, // Max events stored locally
hashUserIds: true, // Hash user IDs before sending
appVersion: '1.2.0', // Override auto-detected version
});Super properties
Attach properties to every event:
// Set global properties
await Adopture.registerSuperProperties({
app_variant: 'premium',
build: 'production',
});
// Set only if not already set
await Adopture.registerSuperPropertiesOnce({
first_open_date: new Date().toISOString(),
});
// Remove a property
await Adopture.unregisterSuperProperty('build');
// Clear all
await Adopture.clearSuperProperties();Opt-out / opt-in
// Disable tracking (clears queue)
await Adopture.disable();
// Re-enable tracking
Adopture.enable();API reference
Core
| Method | Description |
|--------|-------------|
| Adopture.init(options) | Initialize the SDK |
| Adopture.track(name, properties?) | Track a custom event |
| Adopture.screen(name, properties?) | Track a screen view |
| Adopture.identify(userId) | Associate a user ID (hashed by default) |
| Adopture.logout() | Clear user identity |
| Adopture.flush() | Send all queued events immediately |
| Adopture.reset() | Clear identity, queue, and session |
| Adopture.disable() / enable() | Opt-out / opt-in |
| Adopture.shutdown() | Flush and tear down the SDK |
Revenue
| Method | Description |
|--------|-------------|
| Adopture.trackPurchase(opts) | Initial or first subscription purchase |
| Adopture.trackOneTimePurchase(opts) | Non-recurring purchase |
| Adopture.trackRenewal(opts) | Subscription renewal |
| Adopture.trackTrialStarted(opts) | Free trial started |
| Adopture.trackTrialConverted(opts) | Trial converted to paid |
| Adopture.trackCancellation(opts) | Subscription cancelled |
| Adopture.trackRefund(opts) | Refund processed |
React hooks
import {
AdoptureProvider,
useAdopture,
useTrack,
useScreen,
useIdentify,
useAdoptureNavigationTracking,
} from '@adopture/react-native/react';| Hook | Returns |
|------|---------|
| useAdopture() | The Adopture class for direct access |
| useTrack() | Stable (name, properties?) => void |
| useScreen() | Stable (name, properties?) => void |
| useIdentify() | Stable (userId) => Promise<void> |
| useAdoptureNavigationTracking(ref) | Void -- auto-tracks screen changes |
Auto-captured events
These events are tracked automatically when autoCapture is enabled (default):
| Event | When |
|-------|------|
| app_installed | First launch (no stored version) |
| app_updated | Launch with new app version |
| app_opened | App returns from background |
| app_backgrounded | App enters background |
| session_start | New session after 30 min inactivity |
How privacy works
Adopture never sends raw device IDs or user IDs off-device. Instead, it generates three rotating hashes per device:
| Hash | Rotation | Used for | |------|----------|----------| | Daily | Every day | DAU counting | | Monthly | Every month | MAU and retention | | Retention | Every quarter | 90-day cohort analysis |
User IDs passed to identify() are hashed with SHA-256 before transmission (configurable via hashUserIds).
Requirements
- React Native >= 0.70
- React >= 18
- Expo SDK 50+ (if using Expo)
