---
modificationDate: June 18, 2026
title: Using PostHog
description: A guide on installing and configuring PostHog for product analytics, session replay, and error tracking.
platforms: ['android', 'ios']
---

<AgentInstructions>

## Submitting Feedback

If this page contains errors, outdated information, or gaps that blocked you from completing a task, report it so the docs can be improved:

curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/guides/using-posthog/","feedback":"🤖 Agent feedback for docs: <specific, actionable description> (<model>, <harness>)"}'

Only submit when you have something specific and actionable to report. Replace <model> with the model you are running as and <harness> with the tool you are running in (for example, Claude Code, Cursor, Codex CLI).

## Navigation

When answering a related or follow-up question, fetch the relevant page below as Markdown (.md) instead of guessing; use llms.txt for the full map.

You are here: Guides > Integrations > Analytics and error reports
Pages in this section:
- [Using Analytics](https://docs.expo.dev/guides/using-analytics.md)
- [Using Sentry](https://docs.expo.dev/guides/using-sentry.md)
- [Using BugSnag](https://docs.expo.dev/guides/using-bugsnag.md)
- [Using LogRocket](https://docs.expo.dev/guides/using-logrocket.md)
- [Using Vexo](https://docs.expo.dev/guides/using-vexo.md)
- [Using PostHog](https://docs.expo.dev/guides/using-posthog.md) (this page)
Full documentation tree: [llms.txt](https://docs.expo.dev/llms.txt)

</AgentInstructions>

# Using PostHog

A guide on installing and configuring PostHog for product analytics, session replay, and error tracking.
Android, iOS

[PostHog](https://posthog.com/) is a product analytics platform with session replay, feature flags, and error tracking.

The EAS CLI integration automates the standard PostHog React Native setup: installing the SDK, creating a PostHog organization and project, and configuring your environment variables. You can also [set it up manually](/guides/using-posthog.md#manual-setup) and use the rest of this guide unchanged.

#### Prerequisites

##### Expo account

Sign up for an [Expo account](https://expo.dev/signup).

##### EAS CLI

Install EAS CLI globally with `npm install -g eas-cli`.

##### Expo project linked to EAS

Create an Expo project and link it to EAS with `eas init`.

## What you'll learn

This guide covers integrating PostHog with your Expo project:

-   [Install and configure PostHog](/guides/using-posthog.md#install-and-configure-posthog) in your React Native app
-   [Error tracking](/guides/using-posthog.md#error-tracking) with source maps and native crash symbolication
-   [Release tagging](/guides/using-posthog.md#release-tagging), [feature flags](/guides/using-posthog.md#feature-flags), and [troubleshooting](/guides/using-posthog.md#troubleshooting)

## Install and configure PostHog

### Run the `connect` command

Run the following command in your project directory:

```sh
eas integrations:posthog:connect
```

This command:

-   Prompts for a PostHog **region** (US or EU). The region sets your data residency and can't be changed after connecting.
-   Creates a PostHog organization and project for you, or reuses the existing one if you've already connected. (New PostHog accounts only; see [Troubleshooting](/guides/using-posthog.md#troubleshooting).)
-   Asks which features to set up: a multiselect of **Analytics**, **Session replay**, and **Error tracking**, all enabled by default.
-   If you enable **error tracking**, prompts you to paste a PostHog **personal API key**. Create one in PostHog under **Settings → Personal API keys** with the "Source map upload" preset. (Non-interactively, pass it with `--posthog-cli-api-key`.)
-   Installs the PostHog SDK and required Expo modules (plus the session-replay package if you keep that feature).
-   Adds the `posthog-react-native/expo` config plugin to your app config. The plugin wires up the native modules that PostHog's SDK, session replay, and error symbolication rely on. It edits a static [app config](/workflow/configuration.md) file for you, but it can't edit a [dynamic app config](/workflow/configuration.md#dynamic-configuration), so it prints the plugin entry for you to add.
-   Writes `EXPO_PUBLIC_POSTHOG_API_KEY` and `EXPO_PUBLIC_POSTHOG_HOST` to **.env.local** and to your EAS environment variables across Production, Preview, and Development environments. With error tracking enabled it also stores the personal API key as `POSTHOG_CLI_API_KEY` (with [sensitive visibility](/eas/environment-variables.md#visibility-settings-for-environment-variables)) and the public `POSTHOG_CLI_PROJECT_ID` and `POSTHOG_CLI_HOST`.

Re-running `connect` is safe: it reuses your existing organization and project and prompts before overwriting environment variables.

#### Running in CI or non-interactively

Pass `--non-interactive` with `--region US` or `--region EU` (required, since there's no safe default for data residency). Control features with `--session-replay` / `--no-session-replay` and `--error-tracking` / `--no-error-tracking`; error tracking also needs `--posthog-cli-api-key`. Use `--overwrite` to replace existing environment variables without prompting.

### Wrap your app in `<PostHogProvider>`

In your root layout file (**src/app/_layout.tsx** with Expo Router), wrap your app in `<PostHogProvider>`, reading the keys from the environment variables the command wrote. See the [PostHog React Native docs](https://posthog.com/docs/libraries/react-native) for all options, including [error-tracking autocapture](https://posthog.com/docs/error-tracking/installation/react-native).

```tsx
import { PostHogProvider } from 'posthog-react-native';
import { Slot } from 'expo-router';

export default function RootLayout() {
  return (
    <PostHogProvider
      apiKey={process.env.EXPO_PUBLIC_POSTHOG_API_KEY}
      options={{
        host: process.env.EXPO_PUBLIC_POSTHOG_HOST,
        enableSessionReplay: false, // set to true if you enabled session replay
        // Capture JS exceptions (remove if you didn't enable error tracking):
        errorTracking: {
          autocapture: { uncaughtExceptions: true, unhandledRejections: true },
        },
        // disabled: __DEV__, // uncomment to stop sending events from development builds
      }}>
      <Slot />
    </PostHogProvider>
  );
}
```

### Create a development build

Session replay and native crash symbolication require a [development build](/develop/development-builds/introduction.md) since they don't work in Expo Go. Product analytics works in Expo Go.

```sh
eas build --profile development
```

### Verify the configuration

Add a temporary button to capture a test event, run your development build, and tap it:

```tsx
import { Button } from 'react-native';
import { usePostHog } from 'posthog-react-native';

// Inside a component
const posthog = usePostHog();
<Button title="Send test event" onPress={() => posthog?.capture('test_event')} />
```

Open your PostHog project (at `https://us.posthog.com` or `https://eu.posthog.com`, depending on your region) and confirm the event arrives.

## Error tracking

If you enabled error tracking, PostHog symbolicates two separate things, and you set them up independently:

-   **JavaScript source maps** for JS/TS exceptions, including Hermes bytecode. See [Source maps](/guides/using-posthog.md#source-maps).
-   **Native debug symbols** for native Android and iOS crashes (ProGuard/R8 mappings and dSYMs). Optional. See [Native crash symbolication](/guides/using-posthog.md#native-crash-symbolication).

### Source maps

Source maps make JavaScript stack traces (including Hermes bytecode) point to your original source instead of minified output.

First, set up injection so each bundle is tagged for upload. Add this to **metro.config.js** in your project root (create the file if it doesn't exist):

```js
const { getPostHogExpoConfig } = require('posthog-react-native/metro');

const config = getPostHogExpoConfig(__dirname);

module.exports = config;
```

If you already customize your Metro config (for example, with NativeWind or in a monorepo), apply your changes to the `config` object that `getPostHogExpoConfig` returns instead of calling `getDefaultConfig` yourself.

PostHog's CLI authenticates with the `POSTHOG_CLI_*` environment variables that `connect` set. To upload from your own machine, run `posthog-cli login` instead.

**On EAS Build**, the `posthog-react-native/expo` config plugin uploads source maps automatically during the Android (Gradle) and iOS (Xcode) build phases, so there's no extra command to run.

**On EAS Update**, over-the-air updates ship only JavaScript, so upload just their source maps after each update (native symbols are fixed at build time). [Install PostHog's CLI](https://posthog.com/docs/error-tracking/upload-source-maps/cli), then:

```sh
eas update
posthog-cli hermes upload --directory dist
```

`dist` is the default EAS Update output directory.

#### Automate uploads with EAS Workflows

EAS Build uploads source maps as part of the native build, so a build workflow needs nothing extra. For updates, add a job that re-exports and uploads after publishing:

```yaml
name: Publish update
on:
  push:
    branches: ['main']
jobs:
  publish_update:
    name: Publish update
    type: update
    params:
      channel: production
  upload_update_sourcemaps:
    name: Upload OTA source maps to PostHog
    needs: [publish_update]
    environment: production
    steps:
      - uses: eas/checkout
      - uses: eas/install_node_modules
      - name: Export JS bundle and source maps
        run: npx expo export --dump-sourcemap --output-dir dist
      - name: Upload source maps to PostHog
        run: npx --yes @posthog/cli@latest hermes upload --directory dist
```

`environment: production` gives the job the `POSTHOG_CLI_*` variables that `connect` stored. The chunk IDs injected by `getPostHogExpoConfig` let the re-exported source maps match the bundle the update published. For external CI, set the `POSTHOG_CLI_*` variables yourself.

### Native crash symbolication

Optional. Native crashes (as opposed to JavaScript exceptions) need native debug symbols uploaded at build time. The `posthog-react-native/expo` plugin can do this during EAS Build once you opt in:

```json
{
  "expo": {
    "plugins": [["posthog-react-native/expo", { "uploadNativeSymbols": true }]]
  }
}
```

This is one of three pieces required end to end: build-time symbol upload (above), native crash autocapture in your provider, and the exception-autocapture setting in your PostHog project. See [PostHog's native crash autocapture](https://posthog.com/docs/libraries/react-native#native-crash-autocapture) for the full setup.

## Release tagging

Map each captured event back to a specific over-the-air update by registering [super properties](https://posthog.com/docs/libraries/react-native#super-properties) from [`expo-updates`](/versions/latest/sdk/updates.md):

```tsx
import { useEffect } from 'react';
import * as Updates from 'expo-updates';
import { usePostHog } from 'posthog-react-native';

function ReleaseTagger() {
  const posthog = usePostHog();

  useEffect(() => {
    posthog?.register({
      expo_update_id: Updates.updateId,
      expo_channel: Updates.channel,
      expo_runtime_version: Updates.runtimeVersion,
    });
  }, [posthog]);

  return null;
}
```

Render `<ReleaseTagger />` inside `<PostHogProvider>`. Every subsequent `capture()` carries these properties, so you can filter or group events by `expo_update_id` in PostHog.

## Feature flags

Once the provider is set up, feature flags work with no extra configuration. See [PostHog's feature flags for React Native](https://posthog.com/docs/feature-flags/installation/react-native) and [bootstrapping](https://posthog.com/docs/feature-flags/bootstrapping) to avoid a network round-trip on app start.

## Manage the integration

Use these commands to manage the integration later:

```sh
eas integrations:posthog:dashboard
eas integrations:posthog:disconnect
```

`dashboard` opens your linked PostHog project. `disconnect` removes the Expo-side link only. Your PostHog organization, project, and data are left intact.

## Manual setup

`connect` is a shortcut for the standard PostHog React Native setup. To do it manually, follow [PostHog's React Native installation guide](https://posthog.com/docs/libraries/react-native), then set `EXPO_PUBLIC_POSTHOG_API_KEY` and `EXPO_PUBLIC_POSTHOG_HOST` (plus the `POSTHOG_CLI_*` variables for source maps). Wrap your app in `<PostHogProvider>` as shown in [Step 2](/guides/using-posthog.md#wrap-your-app-in-posthogprovider). For source maps, see [Source maps](/guides/using-posthog.md#source-maps).

## Troubleshooting

#### No events arriving

Confirm `EXPO_PUBLIC_POSTHOG_API_KEY` is set in the environment profile your build uses. Note that `disabled: __DEV__` stops events from development builds, so test in a preview or production build (or remove it temporarily). If a dev server was already running when `connect` wrote your environment variables, do a full reload (not Fast Refresh) so the app picks up the new `EXPO_PUBLIC_*` values.

#### Session replay isn't working

Session replay requires a development build since it doesn't work with Expo Go. If your project uses [Continuous Native Generation](/workflow/continuous-native-generation.md), create one with `npx expo run:android` or `npx expo run:ios` locally, or with `eas build --profile development`.

#### Source maps aren't symbolicating

Confirm your **metro.config.js** is wrapped with `getPostHogExpoConfig` (see [Source maps](/guides/using-posthog.md#source-maps)) and that the `POSTHOG_CLI_*` environment variables are set (`connect` adds them when error tracking is enabled). For over-the-air updates, make sure you ran `posthog-cli hermes upload --directory dist` after `eas update`.

#### 'You already have a PostHog account'

The integration connects new PostHog accounts. If your email already has a PostHog account, set it up using the [manual steps](/guides/using-posthog.md#manual-setup) instead.

## Learn more

-   [PostHog React Native library](https://posthog.com/docs/libraries/react-native)
-   [Product analytics for React Native](https://posthog.com/docs/product-analytics/installation/react-native)
-   [Error tracking for React Native](https://posthog.com/docs/error-tracking/installation/react-native)
-   [Session replay for React Native](https://posthog.com/docs/session-replay/installation/react-native)
-   [Upload source maps for React Native](https://posthog.com/docs/error-tracking/upload-source-maps/react-native)
-   [Feature flags for React Native](https://posthog.com/docs/feature-flags/installation/react-native)
