Installing Activity Flow in React Native apps
In this guide, you'll learn how to install and use the Activity Flow SDK in React Native apps for Android and iOS. By following these steps, you'll be able to track user navigation, order events, deep links, and ad events in your app.
Before you begin
Use React Navigation or Expo Router in your project
To manage navigation between different screens of your app, you must use either React Navigation or Expo Router. This is important because Activity Flow relies on the useFocusEffect hook from React Navigation to detect changes in pages. For more information, refer to the React Navigation guide.
Install the Activity Flow package
Activity Flow depends on @react-native-async-storage/async-storage to store navigation data locally. This ensures events are captured even when the device is offline.
To install the library, follow these steps:
- In your project directory, run:
_10yarn add @vtex/activity-flow @react-native-async-storage/async-storage
or
_10npm install @vtex/activity-flow @react-native-async-storage/async-storage
- For iOS, sync native dependencies:
_10 cd ios && pod install && cd ../
This process installs the Activity Flow script in your app by adding a new dependency in the package.json file.
Instructions
Step 1 - Importing the Activity Flow plugin
In your app's main file (for example, App.js or App.tsx), import the plugin as follows:
_10import { initActivityFlow } from '@vtex/activity-flow';
Step 2 - Creating an Activity Flow instance
Set the account name to create an instance of the main package class:
_10function App() {_10 // Initialize the Activity Flow plugin with your VTEX account name_10 initActivityFlow({_10 accountName: 'your-account-name', // Replace with your VTEX account name_10 });_10 // ...rest of your app_10}
Usage
Tracking page views automatically
To track navigation state changes, integrate the usePageViewObserver hook with the NavigationContainer, the root component of React Navigation, in your app's main file. To do so, follow these steps:
-
Import the observer hook:
_10import { usePageViewObserver } from '@vtex/activity-flow'; -
Create a reference for the
NavigationContainer:_10const navigationRef = useRef(null); -
Pass the reference to
NavigationContainer:_10<NavigationContainer ref={navigationRef}>_10{/* Stack configurations */}_10</NavigationContainer> -
Use the observer hook to track page views:
_10usePageViewObserver({ navigationRef });
Activity Flow now automatically tracks page transitions. When you navigate between screens, it records each page view and sends event data.
Tracking order group
The Activity Flow SDK can automatically capture order details from navigation parameters, such as orderGroup or orderPlaced, and any query parameters from the navigator stack. These parameters help validate checkout events and confirm successful purchases.
To enable this feature, include the required parameter in your page redirect configuration. See the example below:
When a user completes a purchase, Activity Flow automatically captures orderGroup and other query parameters during the screen transition.
Tracking deep links
The Activity Flow SDK automatically captures deep-link query parameters from the usePageViewObserver hook and includes them in page view events. To enable this feature, configure deep linking in your app according to its platform: Android or iOS.
Android
To enable deep-link handling in your Android app, add intent filters to the AndroidManifest.xml file for each route that can be accessed via a deep link. See the example below:
This AndroidManifest adds two intent filters for deep linking:
- One for HTTPS URLs starting with
"https://example.com/{APP_ROUTE}". - One for a custom scheme
"{YOUR_CUSTOM_SCHEME}". Both useaction.VIEW,category_DEFAULT, andcategory_BROWSABLE, allowing the Activity Flow to launch from browsers or other apps. The data tag for deep link via HTTP specifies thescheme,host, and an optionalpathPrefix, matching any path that begins with that prefix (for example, "/products/42" if{APP_ROUTE}is "/products"). The main difference between intent filters for different routes is theandroid:pathPrefixattribute, which specifies the app route. For a deep link via a custom scheme, the data tag sets the scheme, matching any URL that starts with that scheme (for example, myapp://... if{YOUR_CUSTOM_SCHEME}is myapp).
iOS
To enable deep-link handling in your iOS app, add your URL scheme to the Info.plist file and handle incoming URLs in the AppDelegate file:
- Register your custom URL scheme by adding the following configuration to your
Info.plistfile:
In the info.plist configuration, {YOUR_BUNDLE_URL_SCHEME} is the custom URL scheme your app will handle, that is, the prefix before :// in deep links. For example, setting it to myapp makes links like myapp://path open your app. Enter only the scheme name, without ://. The {YOUR_BUNDLE_URL_NAME} label is a unique identifier for this URL type entry, typically in reverse-DNS format, used to distinguish the configuration and doesn't affect routing. For example, com.example.appname.
- Handle incoming deep links by modifying your
AppDelegate.swift(orAppDelegate.mm) file. The following example handles deep links for cold starts, when the app isn't running, and warm starts, when the app is already running.
Your Android app can now be launched from both web links (https://mystore.com/products/42) and custom scheme links: (myapp://products/42).
Tracking ad events
Ad tracking is available only for accounts that use VTEX Ads. If you're interested in this feature, open a ticket with VTEX Support.
To configure ad tracking, follow these steps:
- Create the ad object
To track events, provide an object containing all information relevant to the ad event. The accountName field is mandatory.
_10const adParams = {_10 accountName: 'your-account-name',_10 adId: 'main-banner-01',_10 // ...other parameters_10};
- Integrate the ad tracker into your components
There are two methods to integrate the ad tracker into your components: Using the AFAdsTracker Wrapper component or using the useAdsTracker hook.
Using the AFAdsTracker wrapper component
To track ad events with the AFAdsTracker, wrap your ad component with it and provide the necessary tracking parameters. The wrapper will automatically manage all required event handlers.
Use this method when your entire child component represents a clickable ad. See the example below:
_10<AFAdsTracker params={adParams}>_10 <TouchableOpacity_10 style={styles.button}_10 onPress={() => {_10 navigation.navigate('/checkout');_10 }}_10 >_10 <Text style={styles.buttonText}>Buy</Text>_10 </TouchableOpacity>_10</AFAdsTracker>
The example below shows a React Native app that uses @vtex/activity-flow with React Navigation to track navigation across multiple screens and ad events from a single location.
_97// App.tsx_97import React, { useRef, useEffect } from 'react';_97import { View, Text, Button, TouchableOpacity, StyleSheet } from 'react-native';_97import { NavigationContainer } from '@react-navigation/native';_97import { createNativeStackNavigator } from '@react-navigation/native-stack';_97import {_97 initActivityFlow,_97 usePageViewObserver,_97 AFAdsTracker,_97} from '@vtex/activity-flow';_97_97type NavProps = { navigation: any };_97_97const HomeScreen = ({ navigation }: NavProps) => {_97 return (_97 <View>_97 <Text>Home</Text>_97 <Button title="Go to Profile" onPress={() => navigation.navigate('Profile')} />_97 <View />_97 <Button title="Go to Ads" onPress={() => navigation.navigate('Ads')} />_97 </View>_97 );_97};_97_97const ProfileScreen = ({ navigation }: NavProps) => (_97 <View>_97 <Text>Profile</Text>_97 <Button title="Go to Details" onPress={() => navigation.navigate('Details')} />_97 </View>_97);_97_97const DetailsScreen = ({ navigation }: NavProps) => {_97 return (_97 <View>_97 <Text>Details</Text>_97 <Button title="Go Back" onPress={() => navigation.goBack()} />_97 </View>_97 );_97};_97_97const AdsScreen = () => {_97 // Include your VTEX accountName here (required for sending ad events)_97 const adParams = {_97 accountName: 'your-account-name',_97 adId: '12345',_97 campaign: 'summer_campaign',_97 };_97_97 return (_97 <View>_97 <Text>Ads</Text>_97 {/* Wrap your ad with AFAdsTracker. The wrapper wires impression/view/click. */}_97 <AFAdsTracker params={adParams}>_97 <TouchableOpacity_97 onPress={() => {_97 // Your CTA action goes here (e.g., navigate, open link)_97 console.log('Ad clicked — navigate or handle CTA');_97 }}_97 >_97 <Text>Sponsored Ad</Text>_97 <Text>Check out our new campaign!</Text>_97 <Text>Buy now</Text>_97 </TouchableOpacity>_97 </AFAdsTracker>_97 </View>_97 );_97};_97_97const Stack = createNativeStackNavigator();_97_97export default function App() {_97 const navigationRef = useRef(null);_97_97 // Initialize Activity Flow once with your VTEX account name_97 useEffect(() => {_97 initActivityFlow({_97 accountName: 'your-account-name',_97 });_97 }, []);_97_97 // Track page views automatically (attach to the navigation ref)_97 usePageViewObserver({ navigationRef });_97_97 return (_97 <NavigationContainer ref={navigationRef as any}>_97 <Stack.Navigator initialRouteName="Home">_97 <Stack.Screen name="Home" component={HomeScreen} />_97_97 <Stack.Screen name="Profile" component={ProfileScreen} />_97_97 <Stack.Screen name="Details" component={DetailsScreen} />_97_97 <Stack.Screen name="Ads" component={AdsScreen} />_97 </Stack.Navigator>_97 </NavigationContainer>_97 );_97}
The app initializes tracking via initActivityFlow with your VTEX account name, and enables automatic page view tracking by calling usePageViewObserver with a NavigationContainer ref.
On the Ads screen, ad parameters (including the required accountName) are passed to the AFAdsTracker wrapper, which wraps a fully clickable child to automatically fire impression, view, and click events without manual handler wiring.
The wrapper detects clicks via onTouchEndCapture. If your ad interaction isn't based on it or can't be wrapped, use the useAdsTracker hook instead.
To use this example in your project, remember to replace
accountNamebased on your scenario.
Using the useAdsTracker hook
The useAdsTracker hook provides more control over how events are attached. It returns handlers and a ref that you must apply manually to your components.
Use this method when:
- You can't use an extra
<View>to wrap your component. - The component that receives events (for example, a
TouchableOpacity) is different from the component that defines the visibility area. - You integrate with third-party component libraries that don’t allow a generic wrapper.
- The click property isn't
onTouchEnd, since the AFAdsTracker wrapper usesonTouchEndCapture.
Follow the steps below to use this hook:
- Import and call the hook:
_10import { useAdsTracker } from '@vtex/activity-flow';_10_10const { handleLayout, handlePress, viewRef } = useAdsTracker(adParams);
- Attach the handlers and ref to your component. See the example below:
_10<TouchableOpacity_10 ref={viewRef} // Attach the ref to track visibility (view)_10 onLayout={handleLayout} // Attach the layout handler (impression)_10 onPress={handlePress} // Attach the click handler (click)_10>_10 <Image source={{}} />_10</TouchableOpacity>
The hook returns an object with three properties:
handleLayout: A function to be passed to your component'sonLayoutprop. It fires the impression event.handlePress: A function to be passed to a touch prop, likeonPressoronTouchEndCapture. It fires the click event.viewRef: Arefthat must be attached to therefprop of the ad's main component. It monitors visibility and fires the view event.
Below is an implementation example of a React Native code that defines a CustomAd component. This component uses the useAdsTracker hook from the @vtex/activity-flow library to integrate with an ad tracking system for visibility and interaction.
_24import { useAdsTracker } from "@vtex/activity-flow";_24import { Image, TouchableOpacity } from "react-native";_24_24export const CustomAd = () => {_24 // 1. Define the parameters_24 const adParams = {_24accountName: 'my-company-x',_24adId: 'sidebar-banner-02',_24 };_24_24// 2. Call the hook to get the handlers and the ref_24const { handleLayout, handlePress, viewRef } = useAdsTracker(adParams);_24_24return (_24 // 3. Attach the handlers and ref to your component_24 <TouchableOpacity_24ref={viewRef} // Attach the ref to track visibility (view)_24onLayout={handleLayout} // Attach the layout handler (impression)_24onPress={handlePress} // Attach the click handler (click)_24 >_24<Image source={{}} />_24 </TouchableOpacity>_24 );_24};
The component's purpose is to render an ad inside a touchable container and report three key events to the tracking system: impression, view, and click.