Skip to main content
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:
cd ios && 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

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

PropTypeRequiredDescription
writeKeyStringYesYour Formo project write key.
asyncStorageAsyncStorageYesAsyncStorage instance for persistent storage.
optionsObjectNoConfiguration options (see below).
disabledBooleanNoDisable the SDK entirely.
onReadyFunctionNoCallback when SDK is initialized.
onErrorFunctionNoCallback 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',
  }}
>

App metadata

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 LevelDescription
errorError messages only.
warnWarning and error messages.
infoInformative messages about normal operation.
debugDetailed diagnostic information.
traceMost 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);
  }}
>
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 TypeWithout QueryClientWith QueryClient
ConnectTrackedTracked
DisconnectTrackedTracked
Chain ChangeTrackedTracked
SignaturesNot trackedTracked
TransactionsNot trackedTracked
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:
FieldDescription
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:
  1. Enable debug logging in development
  2. Trigger a screen view or custom event
  3. Check the console for event logs
  4. Verify events appear in the Activity page on your Formo dashboard

Peer dependencies

PackageVersionRequired
react>=18.0.0Yes
react-native>=0.70.0Yes
@react-native-async-storage/async-storage>=1.17.0Yes
wagmi>=2.0.0No (for Wagmi integration)
@tanstack/react-query>=5.0.0No (for signature/transaction tracking)