For tracking users actions in an Expo app I use Firebase and Google Analytics. Firebase is a good choice because it integrates well with Expo and supports Google Analytics out of the box.
Ask the user if you can track
If you track user activity in your app, you need to be transparent about it. For iOS, you must ask for permission using App Tracking Transparency. Android doesn’t require asking directly, but you do need to declare what data you collect and why before publishing your app. Both the App Store and Play Store will also require a privacy policy, where you outline your tracking practices.
Custom events - choosing what you track
Google Analytics offers a predefined set of custom events and they are enumerated in this list. Take a look if you're covered before you decide to create a custom event.

To create a custom event, just start sending one. For example, for my other app I'm interested how often does the user press on that specific button. Let's call it interpret_ai_click
. It's found in multiple places, my sidebar, more menu, bottom bar. I want to get a feel how the user uses my app to make improvements on my UX for the next version. I could then call:
# native firebase
analytics().logEvent("interpret_at_click", { location: "sidebar" })
# web firebase
const analytics = getAnalytics(app);
logEvent(fbAnalytics, event, params)
Once you click on that button, it will send the event to google analytics. Your event should be visible in the "Realtime overview", in the Event count by Event name.

As far as I'm aware, filtering reports by today won't show your event right away. Only the realtime overview works for today.
Configure React Native Firebase Analytics
React native firebase analytics is well documented, so I'll just summarize it here:
npx expo install @react-native-firebase/app @react-native-firebase/analytics
Have firebase googleServices file(s) in the path and defined in the app.config.
Analytics is already initialized, so you just call analytics().logEvent
etc.
See my GitHub repository for more details.
Debugging Analytics in Android
If for any reason analytics doesn't work from android, adb logcat
and this command might help in debugging:
adb shell setprop debug.firebase.analytics.app <yourpackage>
adb logcat -s FA FA-SVC
Configure Web Firebase Analytics
You need to initialize analytics to use it and be careful in expo because you might get a window is undefined - rendering on the server before the client.
And no, expo 52 does not yet support use client
directive.
My solution is to wrap the analytics in a function.
const analytics = () => getAnalytics(app)
Gluing Native and Web Analytics
First of, I have a glue module which enables me to call firebase on both native, web and expo go. To make it work, my firebase web follows the interface of react native firebase, but only for parts that I need in my app:
const analytics = () => {
const fbAnalytics = getAnalytics(app);
return {
logScreenView: (params) => logEvent(fbAnalytics, 'screen_view', params),
setAnalyticsCollectionEnabled: (enabled: boolean) => setAnalyticsCollectionEnabled(fbAnalytics, enabled),
logEvent: (event: string, params: Record<string, any>) => logEvent(fbAnalytics, event, params),
};
};
GitHub: https://github.com/amarjanica/firebase-expo-demo
Screen Tracking for Analytics in Expo Router
Expo gives pointers on how you can track users if your app is set in expo router, but you should know that screen views are automatically collected on iOS and Android. Take a look at Firebase documentation. That's what FirebaseScreenReportingEnabled
in plist and google_analytics_automatic_screen_reporting_enabled
in AndroidManifest.xml are for.
React native firebase also provides defaults to disabling user tracking, so you don't need to worry about it:
// <project-root>/firebase.json
{
"react-native": {
"google_analytics_automatic_screen_reporting_enabled": false
}
}
To configure web part to manually track, I add this part of code somewhere in my _layout.tsx
import firebase from '@/src/firebase';
export default function Layout() {
const pathname = usePathname();
const params = useLocalSearchParams();
useEffect(() => {
if (Platform.OS === 'web') {
void firebase.analytics().logScreenView({
screen_name: pathname,
screen_class: pathname,
params: JSON.stringify(params),
});
}
}, [pathname, params]);
//...
}
And it should cover static and dynamic routes like [slug].tsx
.
Youtube: https://youtu.be/U9HSJesbD9E
GitHub: https://github.com/amarjanica/firebase-expo-demo