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.