Skip to the page
Docs
React Native and Expo

Docs SDKs

Version 0.x

React Native and Expo

One package, apparent-expo, for Expo (managed or prebuild) and bare React Native. No native code of its own.

Install

Expo:

Terminal
npx expo install apparent-expo @react-native-async-storage/async-storage expo-application expo-localization

Bare React Native:

Terminal
npm install apparent-expo @react-native-async-storage/async-storage && npx pod-install

Only react-native and @react-native-async-storage/async-storage are required. expo-application, expo-localization, react-native-device-info and expo-router are used when the app has them.

Start it

In the root layout (app/_layout.tsx) or App.tsx, once:

TypeScript
import { Apparent } from "apparent-expo";

Apparent.init({ apiUrl: "https://in.apparent.fyi", app: "<app id>", key: "<write key>" });

Add disabled: __DEV__ if you don't want development builds counted at all. You usually don't need to: simulators and test phones are left out of the numbers by themselves.

Screens

expo-router, in the root layout:

TypeScript
import { useApparentScreens } from "apparent-expo/router";

useApparentScreens();

React Navigation:

TypeScript
import { apparentScreens } from "apparent-expo/navigation";
import { NavigationContainer, useNavigationContainerRef } from "@react-navigation/native";

export default function App() {
  const ref = useNavigationContainerRef();
  return <NavigationContainer ref={ref} {...apparentScreens(ref)}>{/* … */}</NavigationContainer>;
}

Any other navigator: Apparent.screen("settings").

Events and users

TypeScript
Apparent.track("paywall_view", { source: "onboarding" });
Apparent.setProperties({ plan: "free" });   // added to every later event
Apparent.identify(user.id);                 // after sign-in
Apparent.reset();                           // on sign-out

More in Events and users.

Purchases

TypeScript
await Apparent.linkRevenueCat(Purchases);   // after Purchases.configure

See RevenueCat.

Errors and opting out

  • Crashes and unhandled promise rejections are caught by themselves (release builds).
  • Errors you catch: Apparent.captureError(error).
  • Someone declines analytics: Apparent.optOut(), and Apparent.optIn() to start again. Remembered.
  • Ask for consent first? Start with optOutByDefault: true and call Apparent.optIn() once they agree. Nothing is collected before that.
  • Nothing showing up? In a debug build the SDK prints Apparent: app id or key is wrong — events are not being saved once when the app id or key doesn't match. Copy both again from Connect.
  • Simulators and emulators say so themselves (simulator in each batch), so they're never counted, even in a release build.
  • Links. When a link opens the app, the SDK sends deep_link_opened with the link (secrets like token= or code= replaced by [redacted]) and its utm_source, utm_medium and utm_campaign. A campaign link that opens the app on its first day counts as where that person came from. Turn it off with trackDeepLinks: false.
  • Notifications. With expo-notifications in the app, a tap sends push_opened with the campaign and title you put in the notification's data. Never the text people saw. Turn it off with trackPushOpens: false.
  • Your own filter. beforeSend sees every event before it is saved. Return it changed, or null to drop it:
TypeScript
Apparent.init({
  apiUrl: "https://in.apparent.fyi", app: "<app id>", key: "<write key>",
  beforeSend: (event) => {
    if (event.name === "debug_tap") return null;
    const { email, ...props } = event.props ?? {};
    return { ...event, props };
  },
});

Bare React Native: versions

Without expo-application or react-native-device-info the SDK can't read your app's version. Pass it, or app updates can't be noticed:

TypeScript
import { version } from "./package.json";

Apparent.init({ apiUrl: "https://in.apparent.fyi", app: "<app id>", key: "<write key>", appVersion: version });

What it promises

  • Every event is saved on the phone within a quarter second, and right away when the app goes to the background or crashes.
  • Up to 1,000 events wait offline for a week. Nothing is sent twice by mistake: the server ignores repeats.
  • One request at a time, 10 seconds each, retries that wait longer each time.

Automatic events: first_open, app_open, app_updated, app_background, screen_view, error, deep_link_opened, push_opened (with expo-notifications), and install_source on Android.

Updated 2026-10-24 · Markdown · Report a mistake