The Formo React Native SDK is designed for mobile dApps and implements the standard Events API with rich mobile context including device information, network status, and app metadata.
Installation
Install the SDK and required peer dependencies:
npm install @formo/react-native-analytics @react-native-async-storage/async-storage react-native-device-info @react-native-community/netinfo
iOS Setup
After installing, run pod install:
Android Setup
No additional setup required. The native modules are automatically linked.
Quick Start
Basic Setup
Wrap your app with the FormoAnalyticsProvider:
import AsyncStorage from '@react-native-async-storage/async-storage';
import { FormoAnalyticsProvider } from '@formo/react-native-analytics';
function App() {
return (
<FormoAnalyticsProvider
writeKey="<YOUR_WRITE_KEY>"
asyncStorage={AsyncStorage}
>
<YourApp />
</FormoAnalyticsProvider>
);
}
With Wagmi
For apps using Wagmi, enable native integration for automatic wallet event tracking:
import AsyncStorage from '@react-native-async-storage/async-storage';
import { WagmiProvider, createConfig } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { FormoAnalyticsProvider } from '@formo/react-native-analytics';
import { mainnet } from 'wagmi/chains';
const wagmiConfig = createConfig({
chains: [mainnet],
// ... your transports
});
const queryClient = new QueryClient();
function App() {
return (
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<FormoAnalyticsProvider
writeKey="<YOUR_WRITE_KEY>"
asyncStorage={AsyncStorage}
options={{
wagmi: {
config: wagmiConfig,
queryClient: queryClient,
},
}}
>
<YourApp />
</FormoAnalyticsProvider>
</QueryClientProvider>
</WagmiProvider>
);
}
Track screen views
Use the screen() method to track screen views - the mobile equivalent of page views:
import { useFormo } from '@formo/react-native-analytics';
import { useEffect } from 'react';
function WalletScreen() {
const formo = useFormo();
useEffect(() => {
formo.screen('Wallet', { category: 'Main' });
}, [formo]);
return <View>...</View>;
}
Include formo in the dependency array. The SDK initializes asynchronously, so including it ensures the screen event fires once initialization completes.
With React Navigation
Automatically track all screen transitions:
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
import { useFormo } from '@formo/react-native-analytics';
import { useRef } from 'react';
function App() {
const analytics = useFormo();
const navigationRef = useNavigationContainerRef();
const routeNameRef = useRef<string>();
return (
<NavigationContainer
ref={navigationRef}
onReady={() => {
routeNameRef.current = navigationRef.getCurrentRoute()?.name;
}}
onStateChange={() => {
const previousRouteName = routeNameRef.current;
const currentRouteName = navigationRef.getCurrentRoute()?.name;
if (previousRouteName !== currentRouteName && currentRouteName) {
analytics.screen(currentRouteName);
}
routeNameRef.current = currentRouteName;
}}
>
{/* Your navigation stack */}
</NavigationContainer>
);
}
Identify users
Call identify() after a user connects their wallet:
const formo = useFormo();
formo.identify({
address: '0x1234...abcd',
userId: 'optional-user-id',
providerName: 'MetaMask',
});
When using Wagmi integration, wallet connections are automatically tracked. You only need to call identify() manually if you want to associate additional user data or use a custom user ID.
Track custom events
Track custom events with the track() method:
const formo = useFormo();
// Basic custom event
formo.track('Swap Completed', {
from_token: 'ETH',
to_token: 'USDC',
amount: '1.5',
});
// With reserved properties for analytics
formo.track('Purchase Completed', {
productId: 'premium-nft-001',
revenue: 99.99, // Reserved: revenue tracking
currency: 'USD', // Reserved: currency for revenue
});
formo.track('Achievement Unlocked', {
achievementId: 'first_transaction',
points: 500, // Reserved: points tracking
});
formo.track('Swap Executed', {
fromToken: 'ETH',
toToken: 'USDC',
volume: 1.5, // Reserved: volume tracking
});
Code examples
Deep link attribution
Parse UTM parameters and referral codes from deep links:
import { Linking } from 'react-native';
import { useFormo } from '@formo/react-native-analytics';
import { useEffect } from 'react';
function App() {
const formo = useFormo();
useEffect(() => {
// Handle initial deep link (app opened via link)
Linking.getInitialURL().then((url) => {
if (url) formo.setTrafficSourceFromUrl(url);
});
// Handle deep links while app is open
const subscription = Linking.addEventListener('url', (event) => {
formo.setTrafficSourceFromUrl(event.url);
});
return () => subscription.remove();
}, [formo]);
return <YourApp />;
}
The SDK automatically extracts and stores:
- UTM parameters (
utm_source, utm_medium, utm_campaign, utm_term, utm_content)
- Referral codes (
ref, referral, refcode, referrer_code)
Example deep link: myapp://home?utm_source=twitter&utm_campaign=launch&ref=friend123
Configuration
Provider props
| Prop | Type | Required | Description |
|---|
writeKey | String | Yes | Your Formo project write key. |
asyncStorage | AsyncStorage | Yes | AsyncStorage instance for persistent storage. |
options | Object | No | Configuration options (see below). |
disabled | Boolean | No | Disable the SDK entirely. |
onReady | Function | No | Callback when SDK is initialized. |
onError | Function | No | Callback when initialization fails. |
Options
<FormoAnalyticsProvider
writeKey="<YOUR_WRITE_KEY>"
asyncStorage={AsyncStorage}
options={{
// Wagmi integration
wagmi: {
config: wagmiConfig,
queryClient: queryClient,
},
// App metadata (enriches all events)
app: {
name: 'MyDeFiApp',
version: '2.1.0',
build: '42',
bundleId: 'com.example.mydefiapp',
},
// Batching configuration
flushAt: 20, // Batch size (default: 20, max: 20)
flushInterval: 30000, // Auto-flush interval in ms (default: 30s)
// Retry configuration
retryCount: 3, // Retry attempts (default: 3, max: 5)
maxQueueSize: 500000, // Max queue size in bytes (default: 500KB)
// Tracking control
tracking: true, // Enable/disable tracking
// Autocapture control
autocapture: true, // Enable/disable wallet autocapture
// Logging
logger: {
enabled: true,
levels: ['error', 'warn', 'info'],
},
// Custom API endpoint
apiHost: 'https://your-proxy.com/api/ingest',
}}
>
The SDK automatically detects app information from your app’s native configuration:
app_name - from your app’s display name
app_version - from your app’s version (e.g., 2.1.0)
app_build - from your app’s build number (e.g., 42)
app_bundle_id - from your bundle/package identifier
To override the auto-detected values, provide custom app information:
options={{
app: {
name: 'MyDeFiApp', // Override detected app name
version: '2.1.0', // Override detected version
build: '42', // Override detected build
bundleId: 'com.example.mydefiapp',
},
}}
Tracking control
Control tracking behavior for different environments or chains:
// Disable tracking entirely
options={{
tracking: false,
}}
// Exclude specific chains (e.g., testnets)
options={{
tracking: {
excludeChains: [5, 11155111], // Goerli, Sepolia
},
}}
Autocapture
Control which wallet events are automatically captured:
// Enable all autocapture (default)
options={{
autocapture: true,
}}
// Disable specific events
options={{
autocapture: {
connect: true,
disconnect: true,
signature: false, // Disable signature tracking
transaction: false, // Disable transaction tracking
chain: true,
},
}}
// Disable all autocapture
options={{
autocapture: false,
}}
Logging
Enable debug logging during development:
options={{
logger: {
enabled: __DEV__,
levels: ['error', 'warn', 'info', 'debug'],
},
}}
| Log Level | Description |
|---|
error | Error messages only. |
warn | Warning and error messages. |
info | Informative messages about normal operation. |
debug | Detailed diagnostic information. |
trace | Most detailed tracing information. |
Ready callback
Execute code when the SDK is fully initialized:
<FormoAnalyticsProvider
writeKey="<YOUR_WRITE_KEY>"
asyncStorage={AsyncStorage}
onReady={(sdk) => {
console.log('Formo SDK ready!');
// Auto-identify or perform other initialization
}}
onError={(error) => {
console.error('Formo SDK failed to initialize:', error);
}}
>
Consent management
Comply with privacy regulations using built-in consent management:
const formo = useFormo();
// Check if user has opted out
if (formo.hasOptedOutTracking()) {
console.log('User has opted out');
}
// Opt out of tracking (stops all tracking, clears queue)
formo.optOutTracking();
// Opt back into tracking
formo.optInTracking();
When opting out, track the opt-out event before calling optOutTracking() so it gets recorded. When opting in, call optInTracking() first, then track the opt-in event.
Wagmi integration
When Wagmi integration is enabled, the SDK automatically tracks:
| Event Type | Without QueryClient | With QueryClient |
|---|
| Connect | Tracked | Tracked |
| Disconnect | Tracked | Tracked |
| Chain Change | Tracked | Tracked |
| Signatures | Not tracked | Tracked |
| Transactions | Not tracked | Tracked |
Use the same QueryClient instance for both Wagmi and Formo to avoid creating multiple cache instances.
Mobile context
The SDK automatically enriches every event with mobile-specific context:
| Field | Description |
|---|
os_name | Operating system (iOS, Android). |
os_version | OS version number. |
device_model | Device model (iPhone 14 Pro, Pixel 8). |
device_manufacturer | Device manufacturer (Apple, Google, Samsung). |
device_type | Device type (mobile, tablet). |
screen_width | Screen width in pixels. |
screen_height | Screen height in pixels. |
screen_density | Pixel density (devicePixelRatio). |
locale | Device language setting. |
timezone | Device timezone. |
wifi | Whether connected to WiFi. |
cellular | Whether connected to cellular. |
carrier | Mobile carrier name (when available). |
app_name | Your app name. |
app_version | Your app version. |
app_build | Your app build number. |
Session management
Reset the current user session:
const formo = useFormo();
// Clear current user session (anonymous_id, user_id, etc.)
formo.reset();
Manual event flushing
Force flush pending events (useful before app backgrounding):
const formo = useFormo();
await formo.flush();
The SDK automatically flushes events when the app goes to background.
Verification
To verify the SDK is working:
- Enable debug logging in development
- Trigger a screen view or custom event
- Check the console for event logs
- Verify events appear in the Activity page on your Formo dashboard
Peer dependencies
| Package | Version | Required |
|---|
react | >=18.0.0 | Yes |
react-native | >=0.70.0 | Yes |
@react-native-async-storage/async-storage | >=1.17.0 | Yes |
wagmi | >=2.0.0 | No (for Wagmi integration) |
@tanstack/react-query | >=5.0.0 | No (for signature/transaction tracking) |