# Events & screen tracking

> Track custom events and React Navigation screen views in your React Native app with the Grovs SDK.

Source: https://docs.grovs.io/docs/sdk/react-native/analytics

Requires `react-native-grovs-wrapper` **3.0** or later (native SDKs 3.0).

## Tracking custom events

`track` records an event with optional properties and tags:

```typescript
import Grovs from 'react-native-grovs-wrapper';

Grovs.track('checkout_completed', { sku: 'abc', total: 42 }, ['shop']);
Grovs.track('level_complete', { level: 5, score: 1200 });
Grovs.track('button_tap');
```

The native SDK validates, stores and batches the event. Events stay on the device until delivered and are held during install attribution so they credit the right link. Details: [Android](https://docs.grovs.io/docs/sdk/android/analytics#tracking-custom-events) and [iOS](https://docs.grovs.io/docs/sdk/ios/analytics#tracking-custom-events).

### Event name rules

Names can't be empty or a reserved system name:

`view`, `open`, `install`, `reinstall`, `app_open`, `time_spent`, `reactivation`, `user_referred`, `custom`, `screen_view`

From 3.1.0 (native SDKs 3.1), the in-app, push and journey event names are reserved too:

`in_app_viewed`, `in_app_clicked`, `in_app_dismissed`, `in_app_answered`, `in_app_commented`, `in_app_held`, `push_open`, `push_delivered`, `push_held`, `journey_entered`, `journey_held`, `journey_path`

Rejected events are logged natively and dropped; `track` doesn't throw. Use [`trackScreenView`](#tracking-screen-views) for screen views, not `track('screen_view')`.

### Property values

Properties are `{ [key: string]: Any }`, where `Any` is a string, number, boolean or flat array of those. Nested objects, `null` and `Date` aren't part of the type. Native limits apply: over 8 KB serialized drops all properties, and the event is still recorded. On Android, values the bridge can't represent as `Serializable` are dropped.

### Tags

Tags are strings: up to 20 per event, each up to 255 characters. Global tags attach to every later event:

```typescript
Grovs.setGlobalTags(['beta', 'experiment-A']);

Grovs.setGlobalTags(); // clear
```

Global and per-event tags are merged, up to 20 combined.

## Tracking screen views

```typescript
Grovs.trackScreenView('Checkout', { section: 'payment' });
```

The same screen name sent twice within one second is dropped natively, so re-renders and quick tab switches don't flood the dashboard. A genuine later return still counts.

## Automatic screen tracking with React Navigation

The wrapper can report every React Navigation route change as a screen view. Pass the container ref from `onReady`:

```tsx
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
import Grovs from 'react-native-grovs-wrapper';

function App() {
  const navigationRef = useNavigationContainerRef();

  return (
    <NavigationContainer
      ref={navigationRef}
      onReady={() => Grovs.startScreenTracking(navigationRef)}>
      {/* navigators */}
    </NavigationContainer>
  );
}
```

`startScreenTracking` reports the current route immediately, then each `state` change whose route name differs from the last. Navigating away and back reports the screen again. The name is the route name from `getCurrentRoute()`; rename with [aliases](#screen-name-aliases).

It returns an unsubscribe function. Calling it again replaces the previous subscription, so a container remount never double-tracks. A ref without `getCurrentRoute` and `addListener` is rejected with a logged error and a no-op unsubscribe.

The wrapper doesn't depend on `@react-navigation/native`. Any object matching `NavigationContainerRefLike` works:

```typescript
interface NavigationContainerRefLike {
  getCurrentRoute(): { name: string } | undefined;
  addListener(type: 'state', callback: () => void): () => void;
}
```

A ref from `createNavigationContainerRef()` works like one from the hook.

### Expo Router and other navigators

With Expo Router or custom navigation, call `trackScreenView` when the visible screen changes:

```typescript
Grovs.trackScreenView('Checkout');
```

### Turn off native automatic screen tracking

Native automatic tracking (on by default in 3.0) only sees the one Activity or view controller hosting React Native. Pass `autoTrackScreenViews: false` in the native `configure` calls, as in the [Quick Start](https://docs.grovs.io/docs/sdk/react-native/quick-start), and track from JavaScript. The Expo config plugin injects this; when upgrading an Expo project, re-run `npx expo prebuild --clean` to regenerate the `configure` line.

Screen views and events you track from JavaScript also trigger [in-app messages](https://docs.grovs.io/docs/sdk/react-native/in-app-messages#triggers), and the screen names are what `setInAppExcludedScreens` matches.

`Grovs.setSDK(false)` stops all collection natively, including screen views from JavaScript. See [Privacy & Consent](https://docs.grovs.io/docs/sdk/react-native/privacy).

## Screen name aliases

Map reported screen names to friendlier dashboard names:

```typescript
Grovs.setScreenAliases({ Home: 'Home Page', ProductDetail: 'Product' });
```

Keys are names passed to `trackScreenView` or read by `startScreenTracking` from your routes. Only string values are forwarded. Aliases sync natively after authentication and are held while the SDK is disabled.

## What the wrapper does not expose

Android `trackNavigation(navController)` and iOS `screenNameProvider` and `.grovsScreen()` are for native UI, with no React Native equivalent. Use `startScreenTracking` or `trackScreenView`.

## Next steps

- [Track revenue and purchases →](https://docs.grovs.io/docs/sdk/react-native/revenue)
- [Gate collection on consent →](https://docs.grovs.io/docs/sdk/react-native/privacy)
- [Full API reference →](https://docs.grovs.io/docs/sdk/react-native/api-reference)
