# Quickstart: RN / Expo (https://www.getfounderhq.com/docs/analytics/getting-started/quickstart-react-native-expo)

Install the SDK, create the client once, and see your first event in
FounderHQ. About 5 minutes.

<Callout title="Before you start">
You need a FounderHQ account and a publishable key. In the app, open
**Sequences → Settings → Event API keys**, create a key for
**Browser/mobile**, and copy it. The full key is shown only once.
</Callout>

## 1. Install the SDK

```bash
npx expo install @founderhq/events-react-native \
  @react-native-async-storage/async-storage \
  expo-application expo-device expo-localization
```

The three Expo packages let the SDK report app version, device model,
locale, and time zone. Building bare React Native? Install
`@founderhq/events-react-native` and
`@react-native-async-storage/async-storage` with npm, and skip them.

## 2. Create the client once

Create one module and import it everywhere.

```ts
// lib/analytics.ts
import { createFounderHqExpoClient } from "@founderhq/events-react-native/expo";

export const events = createFounderHqExpoClient("fhq_pk_XXXX");
```

Bare React Native uses the same API without the Expo context:

```ts
import { FounderHqReactNativeClient } from "@founderhq/events-react-native";

export const events = new FounderHqReactNativeClient("fhq_pk_XXXX");
```

App lifecycle, sessions, and on-device queuing start immediately. The
queue survives a restart, so events captured offline still arrive.

## 3. Track screens

Expo Router:

```tsx
import { usePathname } from "expo-router";
import { useEffect, useMemo } from "react";
import { createExpoRouterTracker } from "@founderhq/events-react-native";
import { events } from "./lib/analytics";

export function ScreenTracker() {
  const pathname = usePathname();
  const trackScreen = useMemo(() => createExpoRouterTracker(events), []);
  useEffect(() => {
    trackScreen(pathname);
  }, [pathname, trackScreen]);
  return null;
}
```

React Navigation instead? Pass your `navigationRef` to
`createReactNavigationTracker(events, navigationRef)` and spread the
returned `onReady` and `onStateChange` onto `<NavigationContainer>`.

## 4. Identify and capture

```ts
events.identify("user_8421", { email: "jane@acme.com", plan: "pro" });
events.capture("trial.started", { plan: "pro" });
```

Pass your own stable user ID, not an email. Call `events.reset()` on
sign-out.

## Verify

1. Run the app on a simulator or device and trigger the event.
2. In FounderHQ, open **Sequences → Events**.
3. You see `trial.started` with `plan: pro`, a `$session_start`, and a
   `$screen` for the screen you opened.
4. Open **Sequences → Contacts**. Jane is there with her email.

Events can take a few seconds to appear. The SDK batches them. To send
immediately, `await events.flush()`.

## Troubleshoot

### Events only appear after a restart

That is the queue doing its job. It flushes on a timer, on batch size,
and when the app goes to the background.

### Purchases are not attributed

In-app purchases need the purchase claim flow, not `capture`. See
[Mobile purchase claims](/analytics/revenue/mobile-purchase-claims).

## Next

- [React Native SDK reference](/analytics/sdks/react-native)
- [Identity and contacts](/analytics/concepts/identity-and-contacts)
