The mobile SDK is still in active development.
Contact support to get access.
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 its required peer dependency:
npm install @formo/analytics-react-native @react-native-async-storage/async-storage
Optional dependencies
For automatic device info detection (version, build number, device model), install one of:
# Expo projects (recommended)
npx expo install expo-application expo-device
# Bare React Native projects
npm install react-native-device-info
If neither is installed, provide app metadata via the app option instead.
iOS Setup (bare React Native only)
If you’re using bare React Native (not Expo), run pod install after adding native dependencies:
Expo projects handle native linking automatically — no pod install needed.
Quick Start
Basic Setup
Wrap your app with the FormoAnalyticsProvider:
import AsyncStorage from '@react-native-async-storage/async-storage' ;
import { FormoAnalyticsProvider } from '@formo/analytics-react-native' ;
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/analytics-react-native' ;
import { mainnet } from 'wagmi/chains' ;
const wagmiConfig = createConfig ({
chains: [ mainnet ],
// Required for React Native — MIPD uses browser APIs (window.addEventListener)
// that don't exist in the React Native environment
multiInjectedProviderDiscovery: false ,
// ... your connectors and 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/analytics-react-native' ;
import { useEffect } from 'react' ;
function WalletScreen () {
const formo = useFormo ();
useEffect (() => {
formo . screen ( 'Wallet' , 'Main' );
}, [ formo ]);
return < View > ... </ View > ;
}
The screen() method signature is:
formo . screen ( name : string , category ?: string , properties ?: object )
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/analytics-react-native' ;
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 >
);
}
Mobile lifecycle events
The SDK automatically tracks application lifecycle events following the Segment/RudderStack specification:
Event When Properties Application InstalledFirst app launch (no stored version) version, buildApplication UpdatedApp version or build changed since last launch version, build, previous_version, previous_buildApplication OpenedEvery cold start and return from background version, build, from_background, url (if deep linked)Application BackgroundedApp transitions to background version, build
Lifecycle events are enabled by default and require asyncStorage to be provided for accurate install/update detection. To disable:
options = {{
autocapture : {
lifecycle : false ,
},
}}
The SDK detects app version and build from expo-application, react-native-device-info, or the app option (in that order). If none are available, version and build will be empty strings.
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
React Native examples/react-native
Deep link attribution
Parse UTM parameters and referral codes from deep links:
import { Linking } from 'react-native' ;
import { useFormo } from '@formo/analytics-react-native' ;
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 writeKeyString Yes Your Formo project write key. asyncStorageAsyncStorage Yes AsyncStorage instance for persistent storage. optionsObject No Configuration options (see below). disabledBoolean No Disable the SDK entirely. onReadyFunction No Callback when SDK is initialized. onErrorFunction 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 ,
lifecycle : true , // Application lifecycle events
},
}}
// Disable all autocapture
options = {{
autocapture : false ,
}}
Logging
Enable debug logging during development:
options = {{
logger : {
enabled : __DEV__ ,
levels : [ 'error' , 'warn' , 'info' , 'debug' ],
},
}}
Log Level Description errorError messages only. warnWarning and error messages. infoInformative messages about normal operation. debugDetailed diagnostic information. logGeneral log messages.
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_nameOperating system (iOS, Android). os_versionOS version number. device_modelDevice model (iPhone 14 Pro, Pixel 8). device_manufacturerDevice manufacturer (Apple, Google, Samsung). device_typeDevice type (mobile, tablet). screen_widthScreen width in pixels. screen_heightScreen height in pixels. screen_densityPixel density (devicePixelRatio). localeDevice language setting. timezoneDevice timezone. wifiWhether connected to WiFi. cellularWhether connected to cellular. carrierMobile carrier name (when available). app_nameYour app name. app_versionYour app version. app_buildYour 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) expo-application>=5.0.0 No (for auto version/build detection in Expo) expo-device>=5.0.0 No (for device info in Expo) react-native-device-info>=10.0.0 No (for auto version/build detection in bare RN)