Use onedollarstats/expo to track screen views and custom events in apps that use Expo Router. The same integration works on iOS, Android and the web. Screen views appear as page views in OneDollarStats.
Requirements:expo-router 3 or later, react-native 0.73 or later, and React 18 or later.
Installation
In your Expo project, install the package:
npm
yarn
pnpm
bun
npm i onedollarstats
yarn add onedollarstats
pnpm add onedollarstats
bun add onedollarstats
Setup
Add a site in OneDollarStats, or use an existing site. Set hostname to that site’s domain. This required value determines where the app’s events are recorded: a native app has no domain of its own.
In app/_layout.tsx, wrap your root layout in OneDollarStatsProvider. Replace mydomain.com with your site’s domain:
import { Stack } from "expo-router";import { OneDollarStatsProvider } from "onedollarstats/expo";export default function RootLayout() { return ( <OneDollarStatsProvider config={{ hostname: "mydomain.com" }}> <Stack /> </OneDollarStatsProvider> );}
Screen paths are added to hostname. For example, the /settings screen is recorded as mydomain.com/settings.
Dev mode
By default, development builds do not send events or page views. This includes Expo Go and apps run with npx expo start on iOS, Android and the web. Expo web apps served from localhost are also excluded.
To test tracking during development, add devmode: true to the provider’s config:
Start the app and navigate between screens. The console shows a connection message and logs each event sent. To see these debug events in your dashboard, open your site in OneDollarStats and enable Dev Mode. See Dev mode for details.
In release builds, devmode is ignored and events are sent as production traffic.
What is tracked automatically
With autocollect: true, the default, the tracker sends page views for:
The first screen and screen changes. A page view is sent when the tracked path changes.
Returns from the background. The current screen is counted again when the app returns from the background. Opening and closing system overlays such as Face ID, permission prompts or Control Center does not count as a return.
By default, dynamic routes use their file names as templates: /profile/abc123 is sent as /profile/[id]. This groups all profiles under one page. Route groups are removed, so app/(tabs)/feed.tsx is sent as /feed.
Re-rendering a screen does not send another page view. Neither does moving between screens with the same tracked path, such as /profile/a and /profile/b when dynamic routes are grouped. See Dynamic routes to track each profile separately.
Send events and page views manually
Call useAnalytics() in a component inside OneDollarStatsProvider. The hook returns event() for custom events and view() for page views:
Both functions accept an optional path and custom properties, as in the NPM package. Without a path, they use the current screen’s tracked path. Property values must be strings.
The following calls show the argument combinations. Obtain event and view from useAnalytics() inside your component:
view() skips a page view if its path matches the last page view sent, whether automatic or manual. For example, view({ campaign: "spring" }) sends nothing if automatic tracking has just counted the current screen.
Consecutive calls for the same tracked path are skipped even with autocollect: false. Custom events are not deduplicated.
Paths are normalized before sending and comparison: "/landing", "landing/" and "/landing?ref=ad" all become /landing. Query strings, URL fragments and trailing slashes are removed.
Dynamic routes
By default, app/profile/[id].tsx is tracked as /profile/[id], regardless of the profile ID. To track each profile by its actual path, such as /profile/abc123, set collapseDynamicRoutes: false:
Each entry matches a path and its subpaths. For example, "/admin" matches /admin and /admin/users, but not /administrator. Wildcards are not supported.
The lists have these rules:
If includePages contains at least one path, excludePages is ignored. This differs from the web tracker, which applies both lists.
includePages: ["/"] matches every screen.
With collapseDynamicRoutes: true, use route templates such as "/profile/[id]" in the lists.
Manual view() and event() calls ignore both lists.
Devices, browsers and OS
For iOS and Android apps, the dashboard shows the operating system and device type (phone or tablet). Native apps do not report a browser. Expo web reports the same device, browser and OS information as other websites. See Devices, browsers and OS.
Configuration
Option
Type
Default
Description
hostname
string
—
Required. Domain under which the app’s events are recorded
collectorUrl
string
https://collector.onedollarstats.com/events
URL to send analytics events
autocollect
boolean
true
Track the first screen, screen changes and returns from the background as page views
devmode
boolean
false
Send development events as debug events; ignored in release builds
collapseDynamicRoutes
boolean
true
Send dynamic routes as templates (/profile/[id])
excludePages
string[]
—
Paths and subpaths to skip during automatic tracking
includePages
string[]
—
Track only these paths and subpaths; overrides excludePages when nonempty
Differences from the web tracker
Clicks are not captured automatically, including on Expo web. Use event() to track interactions.