Skip to content

React Navigation Integration ​

Integrate the Tappd Mobile SDK with React Navigation for automatic screen tracking.

Overview ​

React Navigation is the most popular navigation library for React Native. This guide shows how to integrate the Tappd SDK for automatic screen tracking.

Installation ​

If you haven't already, install React Navigation:

bash
npm install @react-navigation/native @react-navigation/native-stack
npm install react-native-screens react-native-safe-area-context

Basic Setup ​

Using useFocusEffect Hook ​

The simplest way is to use the useFocusEffect hook in each screen:

javascript
import React from 'react';
import { View, Text } from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import { useTappd } from '../contexts/TappdContext';

function HomeScreen() {
  const tappd = useTappd();

  useFocusEffect(
    React.useCallback(() => {
      // Screen comes into focus
      tappd.trackScreen('HomeScreen', {
        category: 'main',
        section: 'dashboard'
      });

      return () => {
        // Screen goes out of focus (optional cleanup)
      };
    }, [])
  );

  return (
    <View>
      <Text>Home Screen</Text>
    </View>
  );
}

Create Navigation Helper ​

Create a helper to track all screen changes:

javascript
// utils/navigationTracker.js
import { useEffect, useRef } from 'react';
import { useNavigationContainerRef } from '@react-navigation/native';

export function useNavigationTracking(tappd) {
  const navigationRef = useNavigationContainerRef();
  const routeNameRef = useRef();

  useEffect(() => {
    if (!navigationRef || !tappd) return;

    const onStateChange = async () => {
      const previousRouteName = routeNameRef.current;
      const currentRouteName = navigationRef.getCurrentRoute()?.name;

      if (previousRouteName !== currentRouteName) {
        // Track screen view
        await tappd.trackScreen(currentRouteName, {
          previousScreen: previousRouteName
        });
      }

      routeNameRef.current = currentRouteName;
    };

    navigationRef.addListener('state', onStateChange);

    return () => {
      navigationRef.removeListener('state', onStateChange);
    };
  }, [navigationRef, tappd]);
}

Use in App ​

javascript
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useTappd } from './contexts/TappdContext';
import { useNavigationTracking } from './utils/navigationTracker';

const Stack = createNativeStackNavigator();

function App() {
  const tappd = useTappd();
  const navigationRef = React.useRef();

  useNavigationTracking(tappd);

  return (
    <NavigationContainer ref={navigationRef}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Advanced: Custom Navigator ​

Create a wrapper that automatically tracks screens:

javascript
// components/TrackedStackNavigator.js
import React from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useNavigationContainerRef } from '@react-navigation/native';
import { useTappd } from '../contexts/TappdContext';

const Stack = createNativeStackNavigator();

export function TrackedStackNavigator({ screens }) {
  const tappd = useTappd();
  const navigationRef = useNavigationContainerRef();
  const routeNameRef = React.useRef();

  React.useEffect(() => {
    if (!navigationRef || !tappd) return;

    const unsubscribe = navigationRef.addListener('state', async (e) => {
      const previousRouteName = routeNameRef.current;
      const currentRouteName = navigationRef.getCurrentRoute()?.name;

      if (previousRouteName !== currentRouteName) {
        await tappd.trackScreen(currentRouteName, {
          previousScreen: previousRouteName,
          timestamp: new Date().toISOString()
        });
      }

      routeNameRef.current = currentRouteName;
    });

    return unsubscribe;
  }, [navigationRef, tappd]);

  return (
    <Stack.Navigator>
      {screens.map((screen) => (
        <Stack.Screen
          key={screen.name}
          name={screen.name}
          component={screen.component}
          options={screen.options}
        />
      ))}
    </Stack.Navigator>
  );
}

// Usage
<TrackedStackNavigator
  screens={[
    { name: 'Home', component: HomeScreen },
    { name: 'Profile', component: ProfileScreen }
  ]}
/>

Tab Navigation ​

For Tab Navigators, track when tabs are focused:

javascript
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { useFocusEffect } from '@react-navigation/native';

const Tab = createBottomTabNavigator();

function HomeTab() {
  const tappd = useTappd();

  useFocusEffect(
    React.useCallback(() => {
      tappd.trackScreen('HomeTab');
    }, [])
  );

  return <HomeScreen />;
}

function ProfileTab() {
  const tappd = useTappd();

  useFocusEffect(
    React.useCallback(() => {
      tappd.trackScreen('ProfileTab');
    }, [])
  );

  return <ProfileScreen />;
}

function TabNavigator() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="HomeTab" component={HomeTab} />
      <Tab.Screen name="ProfileTab" component={ProfileTab} />
    </Tab.Navigator>
  );
}

Tracking Navigation Events ​

Track navigation actions:

javascript
import { useNavigation } from '@react-navigation/native';

function MyScreen() {
  const navigation = useNavigation();
  const tappd = useTappd();

  const handleNavigate = async (screenName, params) => {
    // Track navigation event
    await tappd.track('navigation.navigated', {
      from: 'CurrentScreen',
      to: screenName,
      params: params
    });

    // Navigate
    navigation.navigate(screenName, params);
  };

  return (
    <Button
      title="Go to Profile"
      onPress={() => handleNavigate('Profile')}
    />
  );
}

Deep Linking ​

The SDK automatically tracks deep links. For manual tracking:

javascript
import { Linking } from 'react-native';
import { useTappd } from '../contexts/TappdContext';

function App() {
  const tappd = useTappd();

  useEffect(() => {
    // Get initial URL
    Linking.getInitialURL().then((url) => {
      if (url) {
        // SDK automatically tracks deep_link.opened
        // But you can track additional info:
        tappd.track('deep_link.handled', {
          url: url,
          source: 'cold_start'
        });
      }
    });

    // Listen for deep links
    const subscription = Linking.addEventListener('url', (event) => {
      tappd.track('deep_link.handled', {
        url: event.url,
        source: 'warm_start'
      });
    });

    return () => {
      subscription.remove();
    };
  }, []);

  return (
    // Your app
  );
}

Screen Tracking with Params ​

Track screen with navigation parameters:

javascript
function ProductScreen({ route }) {
  const tappd = useTappd();
  const { productId } = route.params;

  useFocusEffect(
    React.useCallback(() => {
      tappd.trackScreen('ProductScreen', {
        productId: productId,
        category: 'ecommerce'
      });
    }, [productId])
  );

  return (
    // Screen content
  );
}

Best Practices ​

  1. Use useFocusEffect - Tracks screen when it comes into focus
  2. Track with context - Include navigation params in screen tracking
  3. Track navigation actions - Track user navigation behavior
  4. Handle deep links - SDK handles automatically, but track additional info if needed
  5. Consistent naming - Use consistent screen names across your app

Example: Complete Setup ​

javascript
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import TappdSDK from '@tappd/mobile-sdk';
import { TappdProvider } from './contexts/TappdContext';
import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';

const Stack = createNativeStackNavigator();

const tappd = new TappdSDK({
  appId: 'YOUR_APP_ID',
  enableAutoScreenTracking: true
});

function App() {
  return (
    <TappdProvider value={tappd}>
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
          <Stack.Screen name="Profile" component={ProfileScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    </TappdProvider>
  );
}

export default App;
javascript
// screens/HomeScreen.js
import React from 'react';
import { View, Button } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { useFocusEffect } from '@react-navigation/native';
import { useTappd } from '../contexts/TappdContext';

function HomeScreen() {
  const navigation = useNavigation();
  const tappd = useTappd();

  useFocusEffect(
    React.useCallback(() => {
      tappd.trackScreen('HomeScreen');
    }, [])
  );

  const handleNavigate = async () => {
    await tappd.track('navigation.button_pressed', {
      buttonId: 'go_to_profile',
      from: 'HomeScreen'
    });
    navigation.navigate('Profile');
  };

  return (
    <View>
      <Button title="Go to Profile" onPress={handleNavigate} />
    </View>
  );
}

export default HomeScreen;

Next Steps ​

Released under the MIT License.