---
title: React Native SDK
description: "Reference for the current React Native SDK with installation, configuration, and platform support."
product: analytics
lang: en
last_updated: 2026-10-22
token_estimate: 16349
---
# React Native SDK

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

- **Package:** `@amplitude/analytics-react-native` ([npm](https://www.npmjs.com/package/@amplitude/analytics-react-native))
- **Latest version:** 1.12.4

The React Native SDK lets you send events to Amplitude.

> **Note:** React Native support
>
> [React-Native](https://github.com/facebook/react-native) doesn't provide stable release versioning, which makes backward compatibility challenging. React-Native itself isn't backward compatible and can introduce breaking changes across versions. Check the React-Native [compatibility list](https://github.com/react-native-community/cli#compatibility) for more details. Amplitude supports only the latest version of React-Native.

## Compatibility matrix

The following matrix lists Amplitude React Native SDK support for [different versions of React Native and React Native CLI](https://github.com/react-native-community/cli).

| @amplitude/analytics-react-native | react-native | Gradle | Android Gradle Plugin |
| --- | --- | --- | --- |
| >= 1.4.0 | >= 0.68 | 7.5.1+ | 7.2.1+ |
| >= 1.0.0, <= 1.3.6 | >= 0.61, <= 0.70 | 3.5.3+ | 3.5.3+ |

Learn more about the Android [Gradle Plugin compatibility](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle).

## Install the SDK

To start using the Amplitude React Native SDK, install the package to your project with npm. The SDK uses `@react-native-async-storage/async-storage` by default to persist identity and the event queue across app launches, so install it alongside the SDK. If you'd rather use your own storage backend, refer to [Opt out of AsyncStorage](#opt-out-of-asyncstorage).

> **Tip:** Web and Expo support
>
> You can use this SDK for react-native apps built for web or built using [Expo](https://expo.dev/) (Expo Go not yet supported).

#### npm

```bash
npm install @amplitude/analytics-react-native
npm install @react-native-async-storage/async-storage
```

#### yarn

```bash
yarn add @amplitude/analytics-react-native
yarn add @react-native-async-storage/async-storage
```

#### expo

```bash
expo install @amplitude/analytics-react-native
expo install @react-native-async-storage/async-storage
```

Install the native modules to run the SDK on iOS.

```bash
cd ios
pod install
```

## Initialize the SDK

Initialize the SDK before any instrumentation. The API key for your Amplitude project is required. You can optionally pass a user ID and config object in this call. After you initialize the SDK, you can use it anywhere in your application.

```ts
import { init } from "@amplitude/analytics-react-native";

// Option 1, initialize with API_KEY only
init(API_KEY);

// Option 2, initialize including user ID if it's already known
init(API_KEY, "user@amplitude.com");

// Option 3, initialize including configuration
init(API_KEY, "user@amplitude.com", {
  disableCookies: true, // Disables the use of browser cookies
});
```

## Configure the SDK

> **Note:** Web vs. mobile
>
> The SDK shares configuration across web and mobile platforms. Many of these options don't apply when you run the SDK on native platforms like iOS or Android. For example, on web, the SDK stores identity in the browser cookie by default. On native platforms, the SDK stores identity in async storage.

#### Configuration options

| Name | Description | Default Value |
| --- | --- | --- |
| `instanceName` | `string`. The instance name. | `$default_instance` |
| `flushIntervalMillis` | `number`. Sets the interval for uploading events to Amplitude in milliseconds. | 1,000 (1 second) |
| `flushQueueSize` | `number`. Sets the maximum number of events that the SDK batches in a single upload attempt. | 30 events |
| `flushMaxRetries` | `number`. Sets the maximum number of retries for failed upload attempts. Only applies to retryable errors. | 5 times. |
| `offline` | `boolean` | `OfflineDisabled`. Whether the device has a network connection. The SDK detects connectivity automatically and queues events while the device is offline. Refer to [Offline mode](#offline-mode). | `false` |
| `logLevel` | `LogLevel.None` or `LogLevel.Error` or `LogLevel.Warn` or `LogLevel.Verbose` or `LogLevel.Debug`. Sets the log level. | `LogLevel.Warn` |
| `loggerProvider ` | `Logger`. Sets a custom `loggerProvider` class from the Logger to emit log messages to your chosen destination. | `Amplitude Logger` |
| `minIdLength` | `number`. Sets the minimum length for the value of `userId` and `deviceId` properties. | `5` |
| `optOut` | `boolean`. Sets permission to track events. Setting a value of `true` prevents Amplitude from tracking and uploading events. | `false` |
| `serverUrl` | `string`. Sets the URL where the SDK uploads events. | `https://api2.amplitude.com/2/httpapi` |
| `serverZone` | `EU` or `US`. Sets the Amplitude server zone. Set this to `EU` for Amplitude projects created in `EU` data center. | `US` |
| `useBatch` | `boolean`. Sets whether to upload events to Batch API instead of the default HTTP V2 API. | `false` |
| `appVersion` | `string`. Sets an app version for events tracked. This can be the version of your application. For example: "1.0.0" | `undefined` |
| `deviceId` | `string`. Sets an identifier for the device running your application. | `UUID()` |
| `cookieExpiration` | `number`. Sets expiration of cookies created in days. | 365 days |
| `cookieSameSite` | `string`. Sets `SameSite` property of cookies created. | `Lax` |
| `cookieSecure` | `boolean`. Sets `Secure` property of cookies created. | `false` |
| `cookieStorage` | `Storage<UserSession>`. Sets a custom implementation of `Storage<UserSession>` to persist user identity. | `MemoryStorage<UserSession>` |
| `cookieUpgrade` | `boolean`. Sets upgrading from cookies created by [maintenance Browser SDK](https://amplitude.com/docs/sdks/analytics/browser/javascript-sdk). If true, the new Browser SDK deletes cookies created by the maintenance Browser SDK. If false, the Browser SDK keeps cookies created by the maintenance Browser SDK. | `true` |
| `disableCookies` | `boolean`. Sets permission to use cookies. If value is `true`, the SDK uses the localStorage API to persist user identity. | Cookies enabled by default. |
| `domain` | `string`. Sets the domain property of cookies created. | `undefined` |
| `partnerId` | `string`. Sets partner ID. Amplitude requires the customer who built an event ingestion integration to add the partner identifier to `partner_id`. | `undefined` |
| `sessionTimeout` | `number`. Sets the period of inactivity from the last tracked event before a session expires in milliseconds. | 1,800,000 milliseconds (30 minutes) |
| `userId` | `number`. Sets an identifier for the tracked user. Must have a minimum length of 5 characters unless overridden with the `minIdLength` option. | `undefined` |
| `trackingOptions` | `TrackingOptions`. Configures tracking of additional properties. Refer to the `Optional tracking` section for more information. | All tracking options enabled by default. |
| `storageProvider` | `Storage<Event[]>`. Implements a custom `storageProvider` class from Storage. | `MemoryStorage` |
| `trackingSessionEvents` | `boolean`. Whether the SDK automatically logs start and end session events that correspond to the start and end of a user's session. Prefer `autocapture.sessions` when you use Autocapture. | `false` |
| `autocapture` | `boolean` | `ReactNativeAutocaptureOptions`. Available in `1.6.8`+. Configures Autocapture tracking. Refer to [Autocapture](#autocapture). | Autocapture disabled by default. |
| `migrateLegacyData` | `boolean`. Available in `1.3.4`+. Whether to migrate [maintenance SDK](https://amplitude.com/docs/sdks/analytics/react-native/react-native-sdk-maintenance) data (events, user/device ID). | `true` |

### Configure batching behavior

To support high-performance environments, the SDK sends events in batches. The `track` method queues every event in memory. The SDK flushes events in batches in the background. You can customize batch behavior with `flushQueueSize` and `flushIntervalMillis`. By default, the serverUrl is `https://api2.amplitude.com/2/httpapi`. To send large batches of data at a time, set `useBatch` to `true` to set `setServerUrl` to the batch event upload API `https://api2.amplitude.com/batch`. Both the regular mode and the batch mode use the same events upload threshold and flush time intervals.

```ts
import * as amplitude from "@amplitude/analytics-react-native";

amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  // Events queued in memory will flush when number of events exceed upload threshold
  // Default value is 30
  flushQueueSize: 50,
  // Events queue will flush every certain milliseconds based on setting
  // Default value is 10000 milliseconds
  flushIntervalMillis: 20000,
});
```

### Offline mode

Beginning with version 1.6.0, the React Native SDK supports offline mode. The SDK detects when the device loses network connectivity and queues events instead of dropping them. While the device is offline, the SDK persists tracked events to storage and stops attempting uploads. When the device reconnects, the SDK flushes the queued events to Amplitude. Offline mode is on by default, so you don't need to configure it.

The SDK detects connectivity through a native module: `NWPathMonitor` on iOS and `ConnectivityManager` on Android. On web (react-native-web), the SDK uses the browser's `navigator.onLine` state and `online` and `offline` events.

The SDK persists events to storage while the device is offline, so the configured `storageProvider` bounds the size of the offline queue. Refer to [Opt out of AsyncStorage](#opt-out-of-asyncstorage) to change where the SDK stores queued events.

#### Native module setup

Connectivity detection relies on the SDK's native modules:

- iOS: The native module links automatically when you run `pod install`. Refer to [Install the SDK](#install-the-sdk). The minimum supported iOS deployment target is 13.0.
- Android: The SDK declares the `ACCESS_NETWORK_STATE` permission in its manifest, which merges into your app's manifest automatically. You don't need to make any manual changes.

#### Disable offline mode

To turn off automatic connectivity detection, set `offline` to `OfflineDisabled` when you initialize the SDK.

```ts
import * as amplitude from "@amplitude/analytics-react-native";

amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  offline: amplitude.Types.OfflineDisabled,
});
```

When you disable offline mode, the SDK flushes events based on `flushIntervalMillis` and `flushQueueSize` only. To implement your own offline logic, disable offline mode as shown, then toggle `config.offline` based on your own network detection.

### EU data residency

You can configure the server zone when you initialize the client to send data to Amplitude's EU servers. The SDK sends data based on the server zone if you set it.

> **Note:**
>
> For EU data residency, set up the project inside Amplitude EU. You must initialize the SDK with the API key from Amplitude EU.

```ts
amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  serverZone: "EU",
});
```

### Debugging

You can control the level of logs printed to the developer console.

- 'None': Suppresses all log messages.
- 'Error': Shows error messages only.
- 'Warn': Shows error messages and warnings. This is the default value if you don't explicitly specify `logLevel`.
- 'Verbose': Shows informative messages.
- 'Debug': Shows error messages, warnings, and informative messages that may help with debugging, including the function context information for all SDK public method invocations. Use this logging mode only in development phases.

Set the log level by configuring the `logLevel` with the level you want.

```ts
amplitude.init(AMPLITUDE_API_KEY, OPTIONAL_USER_ID, {
  logLevel: amplitude.Types.LogLevel.Warn,
});
```

The default logger outputs logs to the developer console. You can provide your own logger implementation based on the `Logger` interface for customization. For example, you can collect error messages from the SDK in a production environment.

Set the logger by configuring the `loggerProvider` with your own implementation.

```ts
amplitude.init(AMPLITUDE_API_KEY, OPTIONAL_USER_ID, {
  loggerProvider: new MyLogger(),
});
```

#### Debug mode

Enable the debug mode by setting the `logLevel` to "Debug", for example:

```ts
amplitude.init(AMPLITUDE_API_KEY, OPTIONAL_USER_ID, {
  logLevel: amplitude.Types.LogLevel.Debug,
});
```

The default logger outputs extra function context information to the developer console when you invoke any SDK public method, including:

- 'type': Category of this context, for example "invoke public method".
- 'name': Name of the invoked function, for example "track".
- 'args': Arguments of the invoked function.
- 'stacktrace': Stacktrace of the invoked function.
- 'time': Start and end timestamp of the function invocation.
- 'states': Useful internal states snapshot before and after the function invocation.

## Autocapture

Available in `@amplitude/analytics-react-native` 1.6.8 and later. Autocapture lets you track sessions, application lifecycle events, screen views, element interactions, frustration interactions, and network requests with minimal instrumentation.

The React Native SDK autocaptures the following event types when you enable them:

- Sessions (`session_start` and `session_end`)
- Application lifecycles (`[Amplitude] Application Opened` and `[Amplitude] Application Backgrounded`)
- Screen views (`[Amplitude] Screen Viewed`), when you call the screen view helpers
- Element interactions (`[Amplitude] Element Pressed`), when you enable element interactions and wrap handlers (manually or with the Babel plugin)
- Frustration interactions (`[Amplitude] Rage Click` and `[Amplitude] Error Click`), when you enable frustration interactions and wrap handlers (manually or with the Babel plugin)
- Network requests (`[Amplitude] Network Request`), when you enable network tracking

#### Autocapture options

| Name | Description |
| --- | --- |
| `config.autocapture.sessions` | Optional. Type: `boolean`. Enables or disables session start and session end events. When `true`, Amplitude tracks the same session events as `trackingSessionEvents: true`. Default when you pass `autocapture: true`: `true`. |
| `config.autocapture.appLifecycles` | Optional. Type: `boolean`. Enables or disables application opened and backgrounded events. Default when you pass `autocapture: true`: `true`. |
| `config.autocapture.screenViews` | Optional. Type: `boolean`. Set to `false` to disable `trackScreenView` and `trackScreenViewOnNavigationStateChange`. Omitting this option or setting it to `true` leaves the helpers enabled. Screen views aren't automatic: wire the helpers into your navigator. |
| `config.autocapture.elementInteractions` | Optional. Type: `boolean`. Enables or disables element interaction tracking. When `true`, Amplitude tracks interactions on handlers wrapped with `ampCapture`. Use the Babel plugin to wrap handlers at compile time, or wrap them in source. Default value is `false`. |
| `config.autocapture.frustrationInteractions` | Optional. Type: `boolean` or object. Enables or disables frustration interaction tracking. When `true`, Amplitude tracks rage clicks and error clicks on handlers wrapped with `ampCapture`. To turn one type off, pass `{ rageClick: boolean, errorClick: boolean }`. Both types stay on unless you set that field to `false`. Default value is `false`. Default when you pass `autocapture: true`: `true`. Available in `1.11.0` and later. Error clicks require `1.12.0` or later. Refer to [Track frustration interactions](#track-frustration-interactions) for more information. |
| `config.autocapture.networkTracking` | Optional. Type: `boolean`. Enables or disables capturing network request events invoked by [XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) and [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). If `true`, Amplitude tracks failed network requests. To configure what Amplitude captures, set this as a network tracking options object. Default value is `false`. Default when you pass `autocapture: true`: `true`. Refer to [Track network requests](#track-network-requests) for more information and configuration options. |

### Enable Autocapture

Pass `autocapture: true` to enable sessions, app lifecycles, screen views, element interactions, frustration interactions, and network tracking together, or pass an options object to choose features.

```ts
import { init } from "@amplitude/analytics-react-native";

// Enable every Autocapture feature
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: true,
});

// Or enable features individually
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    sessions: true,
    appLifecycles: true,
    networkTracking: true,
  },
});
```

To turn Autocapture off, omit `autocapture` or set it to `false`.

```ts
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: false,
});
```

### Track sessions

Set `autocapture.sessions` to `true` (or pass `autocapture: true`) to track `session_start` and `session_end` when the session ID changes. This matches `trackingSessionEvents: true`. Prefer the Autocapture option for new instrumentation.

```ts
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    sessions: true,
  },
});
```

> **Note:**
>
> `trackingSessionEvents` still works. Use `autocapture.sessions` when you adopt Autocapture.

### Track application lifecycles

Set `autocapture.appLifecycles` to `true` to track application foreground and background events from React Native `AppState`.

```ts
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    appLifecycles: true,
  },
});
```

When you enable this setting, Amplitude tracks:

- `[Amplitude] Application Opened`: fires on cold start when the app is already active at init, and again when the app returns to the foreground after a real background.
- `[Amplitude] Application Backgrounded`: fires when `AppState` changes to `background`.

> **Note:**
>
> The SDK doesn't treat `inactive` → `active` (for example, Control Center) as a new open. It emits `[Amplitude] Application Opened` only after a prior background.

### Track screen views

Screen view Autocapture isn't fully automatic. Call `trackScreenView` or `trackScreenViewOnNavigationStateChange` to send `[Amplitude] Screen Viewed` with `[Amplitude] Screen Name`. Set `autocapture.screenViews` to `false` only when you want to disable those helpers.

```ts
import {
  init,
  trackScreenView,
  trackScreenViewOnNavigationStateChange,
} from "@amplitude/analytics-react-native";
import {
  NavigationContainer,
  useNavigationContainerRef,
} from "@react-navigation/native";

init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    sessions: true,
    appLifecycles: true,
  },
});

// Manual screen view
trackScreenView("Home");

// React Navigation: onStateChange doesn't fire for the initial route;
// call the helper from onReady for the cold-start screen.
function App() {
  const navigationRef = useNavigationContainerRef();

  return (
    <NavigationContainer
      ref={navigationRef}
      onReady={() => {
        trackScreenViewOnNavigationStateChange(navigationRef.getRootState());
      }}
      onStateChange={trackScreenViewOnNavigationStateChange}
    >
      {/* navigators */}
    </NavigationContainer>
  );
}
```

`trackScreenViewOnNavigationStateChange` resolves the focused leaf route in nested navigators and skips duplicate callbacks for the same screen name (for example, `onReady` plus `onStateChange`, or param-only updates). Re-init and `reset` clear the dedupe state.

### Track element interactions

Set `autocapture.elementInteractions` to `true` so Amplitude tracks UI interactions on handlers wrapped with `ampCapture`. When a wrapped handler runs, the SDK sends `[Amplitude] Element Pressed` with properties such as `[Amplitude] Target Test ID`, `[Amplitude] Target Accessibility Label`, `[Amplitude] Target Component`, `[Amplitude] Target Element`, and `[Amplitude] Action`.

```ts
import { init } from "@amplitude/analytics-react-native";

init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    elementInteractions: true,
  },
});
```

You can wrap handlers in source with `ampCapture`, or use the Babel plugin so Metro/Babel wraps them at compile time.

```tsx
import { ampCapture } from "@amplitude/analytics-react-native";

<Button
  testID="1234"
  accessibilityLabel="Sign up"
  onPress={ampCapture(
    () => {
      /* your handler */
    },
    {
      testID: "1234",
      accessibilityLabel: "Sign up",
      action: "press",
    },
  )}
/>
```

#### Transpile source with the Babel plugin

Install `@amplitude/babel-plugin-autocapture-transformer` as a dev dependency. The plugin expects `@amplitude/analytics-react-native` in your app; it imports `ampCapture` automatically.

#### npm

```bash
npm install --save-dev @amplitude/babel-plugin-autocapture-transformer
```

#### yarn

```bash
yarn add --dev @amplitude/babel-plugin-autocapture-transformer
```

#### expo

```bash
npx expo install --dev @amplitude/babel-plugin-autocapture-transformer
```

Add the plugin to your Babel config. For Expo or React Native, use `babel.config.js`:

```js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"], // or your existing presets
    plugins: ["@amplitude/babel-plugin-autocapture-transformer"],
  };
};
```

Or in `.babelrc` / `babel.config.json`:

```json
{
  "plugins": ["@amplitude/babel-plugin-autocapture-transformer"]
}
```

At compile time, the plugin rewrites known interactive JSX handlers. For example:

```jsx
// Before transpile
<Button
  accessibilityLabel="Online test label"
  testID="12345"
  title="Online test"
  onPress={func}
/>

// After transpile
import { ampCapture } from "@amplitude/analytics-react-native";

<Button
  accessibilityLabel="Online test label"
  testID="12345"
  title="Online test"
  onPress={ampCapture(func, {
    event: "Press",
    accessibilityLabel: "Online test label",
    testID: "12345",
    element: "Button",
    component: "HomeScreen",
  })}
/>
```

When a file already imports from `@amplitude/analytics-react-native`, the plugin adds `ampCapture` to that import instead of inserting a second one.

The plugin only rewrites known interactive JSX elements that already have an expression handler (for example `onPress={handler}`). It leaves string handlers and elements without handlers unchanged.

| Category | Default elements | Attributes → event |
| --- | --- | --- |
| Pressable | `Button`, `TouchableOpacity`, `TouchableHighlight`, `TouchableWithoutFeedback`, `Pressable`, `Touchable`, `TouchableNativeFeedback`, `Link` | `onPress` → `Press`, `onLongPress` → `LongPress` |
| Value change | `Switch`, `Slider`, `Picker` | `onValueChange` → `ValueChange` |
| Text change | `TextInput` | `onChangeText` → `ChangeText`, `onSubmitEditing` → `SubmitEditing` |

If the element has `accessibilityLabel` or `testID`, the plugin copies those values into the `ampCapture` properties object. It also adds:

- `element`: the JSX tag name (for example `Button`).
- `component`: the enclosing React component or function name when the plugin can resolve it (for example `HomeScreen`).

To include custom components, pass extra element names in the plugin options:

```js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: [
      [
        "@amplitude/babel-plugin-autocapture-transformer",
        {
          pressableElements: ["CustomButton"],
          valueChangeElements: ["Toggle"],
          textChangeElements: ["SearchField"],
        },
      ],
    ],
  };
};
```

#### Babel plugin options

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `pressableElements` | `string[]` | `[]` | Additional JSX component names treated as pressable (`onPress` / `onLongPress`). Merged with the built-in defaults. |
| `valueChangeElements` | `string[]` | `[]` | Additional JSX component names treated as value-change elements (`onValueChange`). Merged with the built-in defaults. |
| `textChangeElements` | `string[]` | `[]` | Additional JSX component names treated as text-change elements (`onChangeText` / `onSubmitEditing`). Merged with the built-in defaults. |

> **Note:**
>
> The plugin transforms only plain JSX identifiers such as `<Button />`. It ignores member expressions like `<RN.Button />` unless you list the local identifier in the matching options array. The plugin doesn't inspect spread attributes (for example `{...props}`) for `accessibilityLabel` or `testID`. It omits `component` when the enclosing function is anonymous.

After you change Babel config, restart Metro so the new plugin loads.

### Track frustration interactions

Available in `@amplitude/analytics-react-native` 1.11.0 and later. Error clicks require 1.12.0 or later.

Set `autocapture.frustrationInteractions` to `true` so Amplitude tracks rage clicks and error clicks on handlers wrapped with `ampCapture`. Use the Babel plugin to wrap handlers at compile time, or wrap them in source. These events use the same wrappers as element interactions.

```ts
import { init } from "@amplitude/analytics-react-native";

init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    frustrationInteractions: true,
  },
});
```

Pass an options object to turn rage clicks or error clicks off individually. Both stay on when you enable frustration interactions and omit the field.

```ts
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    frustrationInteractions: {
      rageClick: true,
      errorClick: false,
    },
  },
});
```

A rage click is four or more presses within 1 second that stay inside a 50-pixel region. Amplitude tracks `[Amplitude] Rage Click` for the burst and includes the element properties from the first press.

#### Rage click event properties

| Event property | Description |
| --- | --- |
| `[Amplitude] Begin Time` | Timestamp of the first press in the burst, in milliseconds since the Unix epoch. |
| `[Amplitude] End Time` | Timestamp of the last press in the burst, in milliseconds since the Unix epoch. |
| `[Amplitude] Duration` | Time from the first press to the last press, in milliseconds. |
| `[Amplitude] Click Count` | Number of presses in the burst. |
| `[Amplitude] Clicks` | Array of presses. Each item includes `x`, `y`, and `time`. |
| `[Amplitude] Action` | The action that triggered the event. Rage clicks use `Press`. |
| `[Amplitude] Target Test ID` | The `testID` of the target element. |
| `[Amplitude] Target Accessibility Label` | The accessibility label of the target element. |
| `[Amplitude] Target Component` | The enclosing React component name, when the Babel plugin can resolve it. |
| `[Amplitude] Target Element` | The JSX tag name of the target element. |
| `[Amplitude] Screen Name` | The current screen name, when a screen view helper has set one. |

An error click is a press or long press followed by an unhandled React Native error within 2 seconds. Amplitude tracks `[Amplitude] Error Click` and includes the same element properties as a rage click.

#### Error click event properties

| Event property | Description |
| --- | --- |
| `[Amplitude] Kind` | The error kind. Unhandled exceptions use `error`. |
| `[Amplitude] Message` | The error message. |
| `[Amplitude] Stack` | The error stack trace. |
| `[Amplitude] Filename` | The source file name, when React Native includes it. |
| `[Amplitude] Line Number` | The line number, when React Native includes it. |
| `[Amplitude] Column Number` | The column number, when React Native includes it. |

### Track network requests

Track when JavaScript `fetch` or XHR network requests fail. By default, Amplitude tracks network requests with a response code in the range `500-599`, excluding requests made to any `amplitude.com` domain. Network tracking observes the JavaScript `fetch` and XHR layer. It doesn't capture HTTP traffic that native modules issue outside JavaScript.

Set `config.autocapture.networkTracking` to `true` to enable network request tracking.

```ts
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    networkTracking: true,
  },
});
```

When you enable this setting, Amplitude tracks the `[Amplitude] Network Request` event whenever the application makes a matching network request.

#### Event Properties Descriptions

| Event property | Description |
| --- | --- |
| `[Amplitude] URL` | The URL of the network request with sensitive information masked. |
| `[Amplitude] URL Query` | The query parameters of the URL. |
| `[Amplitude] URL Fragment` | The fragment identifier of the URL. |
| `[Amplitude] Request Method` | The HTTP method used for the request (GET, POST, and so forth). |
| `[Amplitude] Status Code` | The HTTP status code of the response. |
| `[Amplitude] Error Code` | The local error code if the request failed without a status code. |
| `[Amplitude] Error Message` | The local error message if the request failed without a status code. |
| `[Amplitude] Start Time` | The timestamp when the request started, in milliseconds since Unix epoch. |
| `[Amplitude] Completion Time` | The timestamp when the request completed, in milliseconds since Unix epoch. |
| `[Amplitude] Duration` | The duration of the request in milliseconds. |
| `[Amplitude] Request Body Size` | The size of the request body in bytes. |
| `[Amplitude] Response Body Size` | The size of the response body in bytes. |
| `[Amplitude] Request Body` | The captured JSON request body (when you configure a `requestBody` capture rule). |
| `[Amplitude] Response Body` | The captured JSON response body (when you configure a `responseBody` capture rule). |

#### Advanced configuration for network tracking

Set `config.autocapture.networkTracking` to a `NetworkTrackingOptions` object to configure which network requests Amplitude tracks.

```ts
init(API_KEY, OPTIONAL_USER_ID, {
  autocapture: {
    networkTracking: {
      captureRules: [
        {
          statusCodeRange: "400-599",
        },
      ],
      ignoreHosts: ["*.example.com"],
      ignoreAmplitudeRequests: true,
    },
  },
});
```

This example tracks network requests with status codes from 400-599, ignores requests to `*.example.com` domains, and excludes Amplitude's own requests.

#### NetworkTrackingOptions

| Name | Description | Value |
| --- | --- | --- |
| `captureRules` | The rules for capturing network requests. Always append rules with specific hosts to the bottom of the list. | `undefined` |
| `ignoreHosts` | The hosts to ignore. Supports wildcard characters `*`. For example, `["*"]` to ignore all hosts, `["*.notmyapi.com", "notmyapi.com"]` to ignore `notmyapi.com` and all subdomains. | `[]` |
| `ignoreAmplitudeRequests` | Whether to ignore Amplitude requests. | `true` |

#### NetworkTrackingOptions.NetworkCaptureRule

| Name | Description | Default Value |
| --- | --- | --- |
| `urls` | Defines the URL, URLs, or URL pattern to capture. By default, Amplitude captures all URLs. For example, `[/https:\/\/example.com\/api\/*/, 'https://example.com/api/status']`. | `<any>` |
| `hosts` | The hosts to capture. Supports wildcard characters `*`. For example, `["*"]` to match all hosts, `["*.example.com", "example.com"]` to match `example.com` and all subdomains. Deprecated. Prefer `urls` to filter by hosts. | `none` |
| `methods` | The HTTP methods to capture. For example, `["POST", "PUT", "DELETE"]`. | `['*']` |
| `statusCodeRange` | The status code range to capture. Supports comma-separated ranges or single status codes. For example, `"0,200-299,413,500-599"`. | `"500-599"` |
| `requestBody` | Captures fields in the request body. Refer to `BodyCaptureRule`. | `undefined` |
| `responseBody` | Captures fields in the response body. Refer to `BodyCaptureRule`. | `undefined` |
| `requestHeaders` | Captures request headers. If `true`, captures safe headers. If `false`, captures no headers. If an array of strings, captures the specified headers. | `false` |
| `responseHeaders` | Captures response headers. If `true`, captures safe headers. If `false`, captures no headers. If an array of strings, captures the specified headers. | `false` |

#### BodyCaptureRule

| Name | Description | Default Value |
| --- | --- | --- |
| `allowlist` | Array of JSON property names to capture from request or response bodies. Uses JSON Pointer syntax where leading `/` is optional. Supports wildcards: `*` matches any key, `**` matches any number of keys. Amplitude maintains the structure of the original JSON. | `[]` |
| `blocklist` | Array of JSON property names to exclude from captured request or response bodies. This removes properties that the allowlist would otherwise capture. | `[]` |

#### Safe headers

When you set `requestHeaders: true` or `responseHeaders: true`, Amplitude captures only safe headers and excludes sensitive ones that may contain authentication credentials or personally identifiable information.

#### Safe headers list

- `access-control-allow-origin`
- `access-control-allow-credentials`
- `access-control-expose-headers`
- `access-control-max-age`
- `access-control-allow-methods`
- `access-control-allow-headers`
- `accept-patch`
- `accept-ranges`
- `age`
- `allow`
- `alt-svc`
- `cache-control`
- `connection`
- `content-disposition`
- `content-encoding`
- `content-language`
- `content-length`
- `content-location`
- `content-md5`
- `content-range`
- `content-type`
- `date`
- `delta-base`
- `etag`
- `expires`
- `im`
- `last-modified`
- `link`
- `location`
- `permanent`
- `p3p`
- `pragma`
- `proxy-authenticate`
- `public-key-pins`
- `retry-after`
- `server`
- `status`
- `strict-transport-security`
- `trailer`
- `transfer-encoding`
- `tk`
- `upgrade`
- `vary`
- `via`
- `warning`
- `www-authenticate`
- `x-b3-traceid`
- `x-frame-options`

#### Network body capture

If a network request or response body is in JSON, you can capture part of the response body by configuring `responseBody.allowlist` and `responseBody.blocklist`. You can capture part of the request body by configuring `requestBody.allowlist` and `requestBody.blocklist`.

The allowlist and blocklist are lists of JSON Pointer-like strings that capture specific fields. For example: `['foo/bar', 'hello/**']`. `allowlist` tells the client which fields to capture. `blocklist` tells the client to exclude fields from capture. By default, the SDK captures nothing from the body.

Example request/response body

```json
{
  "a": "A",
  "b": {
    "c": "C",
    "d": {
      "e": "E",
      "f": "F"
    }
  },
  "g": "G"
}
```

| allowlist | Captured Result |
| --- | --- |
| `a` | `{ "a": "A" }` |
| `a/b/*` | `{ "a": { "b": { "c": "C" } } }` |
| `b/c` | `{ "b": { "c": "C" } }` |
| `b/**` | `{ "b": { "c": "C", "d": { "e": "E", "f": "F" } } }` |
| `b/d/*` | `{ "b": { "d": { "e": "E", "f": "F" } } }` |
| `*` | `{ "a": "A", "g": "G" }` |

## Track events

> **Note:**
>
> This SDK uses the [HTTP V2](https://amplitude.com/docs/apis/analytics/http-v2) API and follows the same constraints for events. Make sure that all events you log with the SDK have the `event_type` field and at least one of `deviceId` (included by default) or `userId`, and follow the HTTP API's constraints on each of those fields.
>
> To prevent instrumentation issues, device IDs and user IDs must be strings with a length of 5 characters or more. If an event contains a device ID or user ID that's too short, the SDK removes the ID value from the event. If the event doesn't have a `userId` or `deviceId` value, Amplitude may reject the upload with a 400 status. Override the default minimum length of 5 characters by setting the `minIdLength` config option.

Events represent how users interact with your application. For example, "Button Clicked" may be an action you want to note.

```ts
import { track } from "@amplitude/analytics-react-native";

// Track a basic event
track("Button Clicked");

// Track events with optional properties
const eventProperties = {
  buttonColor: "primary",
};
track("Button Clicked", eventProperties);
```

### Track events to multiple projects

To log events to multiple Amplitude projects, create separate instances for each Amplitude project. Then, pass the instance variables to wherever you want to call Amplitude. Each instance allows for independent `apiKeys`, `userIds`, `deviceIds`, and settings.

```ts
import * as amplitude from "@amplitude/analytics-react-native";

const defaultInstance = amplitude.createInstance();
defaultInstance.init(API_KEY_DEFAULT);

const envInstance = amplitude.createInstance();
envInstance.init(API_KEY_ENV, {
  instanceName: "env",
});
```

## User properties

User properties help you understand your users at the time they performed some action within your app, such as their device details, their preferences, or language.

Use Identify to set the user properties of a particular user without sending any event. The SDK supports the operations `set`, `setOnce`, `unset`, `add`, `append`, `prepend`, `preInsert`, `postInsert`, `remove`, and `clearAll` on individual user properties. You declare the operations through a provided Identify interface. You can chain multiple operations together in a single Identify object. You then pass the Identify object to the Amplitude client to send to the server.

> **Note:**
>
> If you send the Identify call after the event, the results of operations appear immediately in the dashboard user's profile area, but they don't appear in the chart result until you send another event after the Identify call. The identify call only affects events going forward. More details in [User properties and events](https://amplitude.com/docs/data/user-properties-and-events).

### Identify

The Identify object provides controls over setting user properties. First, instantiate an Identify object. Then, call Identify methods on it. Finally, the client makes a call with the Identify object.

```ts
import { identify, Identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identify(identifyObj);
```

#### Identify.set

This method sets the value of a user property. For example, you can set a role property of a user.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.set("location", "LAX");

identify(identifyObj);
```

#### Identify.setOnce

This method sets the value of a user property only once. The SDK ignores subsequent calls using setOnce(). For example, you can set an initial login method for a user. Because the SDK only tracks the initial value, setOnce() ignores subsequent calls.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.setOnce("initial-location", "SFO");

identify(identifyObj);
```

#### Identify.add

This method increments a user property by some numerical value. If the user property doesn't have a value set yet, the SDK initializes it to 0 before incrementing. For example, you can track a user's travel count.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.add("travel-count", 1);

identify(identifyObj);
```

#### Arrays in user properties

You can use arrays as user properties. You can directly set arrays or use `prepend`, `append`, `preInsert`, and `postInsert` to generate an array.

#### `Identify.prepend`

This method prepends a value or values to a user property array. If the user property doesn't have a value set yet, the SDK initializes it to an empty list before prepending the new values.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.prepend("visited-locations", "LAX");

identify(identifyObj);
```

#### `Identify.append`

This method appends a value or values to a user property array. If the user property doesn't have a value set yet, the SDK initializes it to an empty list before appending the new values.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.append("visited-locations", "SFO");

identify(identifyObj);
```

#### `Identify.preInsert`

This method pre-inserts a value or values to a user property if the value doesn't exist in the user property yet. Pre-insert means inserting the value at the beginning of a given list. If the user property doesn't have a value set yet, the SDK initializes it to an empty list before pre-inserting the new values. If the user property has an existing value, the SDK performs no operation.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.preInsert("unique-locations", "LAX");

identify(identifyObj);
```

#### Identify.postInsert

This method post-inserts a value or values to a user property if the value doesn't exist in the user property yet. Post-insert means inserting the value at the end of a given list. If the user property doesn't have a value set yet, the SDK initializes it to an empty list before post-inserting the new values. If the user property has an existing value, the SDK performs no operation.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.postInsert("unique-locations", "SFO");

identify(identifyObj);
```

#### Identify.remove

This method removes a value or values from a user property if the value exists in the user property. Remove means remove the existing values from the given list. If the item doesn't exist in the user property, the SDK performs no operation.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.remove("unique-locations", "JFK");

identify(identifyObj);
```

#### Identify.clearAll

This method removes all user properties from a user. Use `clearAll` with care because the operation is irreversible.

```ts
import { Identify, identify } from "@amplitude/analytics-react-native";

const identifyObj = new Identify();
identifyObj.clearAll();

identify(identifyObj);
```

### User groups

Amplitude supports assigning users to groups and performing queries, such as Count by Distinct, on those groups. If at least one member of the group has performed the specific event, then the count includes the group.

For example, you want to group your users based on what organization they're in by using an 'orgId'. Joe is in 'orgId' '10', and Sue is in 'orgId' '15'. Sue and Joe both perform a certain event. You can query their organizations in the Event Segmentation Chart.

When you set groups, define a `groupType` and `groupName`. In the previous example, 'orgId' is the `groupType`, and '10' and '15' are the values for `groupName`. Another example of a `groupType` could be 'sport' with `groupName` values like 'tennis' and 'baseball'.

Setting a group also sets the `groupType:groupName` as a user property, and overwrites any existing `groupName` value set for that user's groupType, and the corresponding user property value. `groupType` is a string, and `groupName` can be either a string or an array of strings to indicate that a user is in multiple groups.

> **Example:**
>
> If Joe is in 'orgId' '15', then the `groupName` would be '15'.
>
> ```ts
> import { setGroup } from "@amplitude/analytics-react-native";
>
> // set group with single group name
> setGroup("orgId", "15");
> ```
>
> If Joe is in 'sport' 'tennis' and 'soccer', then the `groupName` would be '\["tennis", "soccer"\]'.
>
> ```ts
> import { setGroup } from "@amplitude/analytics-react-native";
>
> // set group with multiple group names
> setGroup("sport", ["soccer", "tennis"]);
> ```

You can also set event-level groups by passing an `Event` Object with `groups` to `track`. With event-level groups, the group designation applies only to the specific event you log, and doesn't persist on the user unless you explicitly set it with `setGroup`.

```ts
import { track } from "@amplitude/analytics-react-native";

track({
  event_type: "event type",
  event_properties: { eventPropertyKey: "event property value" },
  groups: { orgId: "15" },
});
```

## Group properties

Use the Group Identify API to set or update the properties of particular groups. These updates only affect events going forward.

The `groupIdentify()` method accepts a group type and group name string parameter, as well as an Identify object that the SDK applies to the group.

```ts
import { Identify, groupIdentify } from "@amplitude/analytics-react-native";

const groupType = "plan";
const groupName = "enterprise";
const event = new Identify();
event.set("key1", "value1");

groupIdentify(groupType, groupName, identify);
```

## Track revenue

The preferred method of tracking revenue for a user is to use `revenue()` in conjunction with the provided Revenue interface. Revenue instances store each revenue transaction and let you define several special revenue properties (such as "revenueType", "productIdentifier", and so forth) that Amplitude uses in Event Segmentation and Revenue LTV charts. The SDK then passes these Revenue instance objects into `revenue()` to send as revenue events to Amplitude. This lets Amplitude automatically display data relevant to revenue in the platform. You can use this to track both in-app and non-in-app purchases.

To track revenue from a user, call revenue each time a user generates revenue. For example, a user purchases 3 units of a product at $3.99.

```ts
import { Revenue, revenue } from "@amplitude/analytics-react-native";

const event = new Revenue()
  .setProductId("com.company.productId")
  .setPrice(3.99)
  .setQuantity(3);

revenue(event);
```

### Revenue interface

| Name | Description |
| --- | --- |
| `product_id` | Optional. String. An identifier for the product. Amplitude recommends something like the Google Play Store product ID. Defaults to null. |
| `quantity` | Required. Int. The quantity of products purchased. `revenue = quantity * price`. Defaults to 1 |
| `price` | Required. Double. The price of the products purchased, and this can be negative. `revenue = quantity * price`. Defaults to null. |
| `revenue_type` | Optional, but required for revenue verification. String. The revenue type (for example tax, refund, income). Defaults to null. |
| `receipt` | Optional. String. The receipt identifier of the revenue. Defaults to null |
| `receipt_sig` | Optional, but required for revenue verification. String. The receipt signature of the revenue. Defaults to null. |
| `properties` | Optional. JSONObject. An object of event properties to include in the revenue event. Defaults to null. |

## Flush the event buffer

The `flush` method triggers the client to send buffered events.

```typescript
import { flush } from "@amplitude/analytics-react-native";

flush();
```

By default, the SDK calls `flush` automatically in an interval. To flush the events altogether, you can control the async flow with the optional Promise interface, for example:

```typescript
await init(AMPLITUDE_API_KEY).promise;
track("Button Clicked");
await flush().promise;
```

## Custom user ID

If your app has its own login system that you want to track users with, you can call `setUserId` at any time.

TypeScript

```ts
import { setUserId } from "@amplitude/analytics-react-native";

setUserId("user@amplitude.com");
```

You can also assign the User ID as an argument to the init call.

```ts
import { init } from "@amplitude/analytics-react-native";

init(API_KEY, "user@amplitude.com");
```

## Custom session ID

You can assign a new Session ID using `setSessionId`. When you set a custom session ID, make sure the value is in milliseconds since epoch (Unix Timestamp).

TypeScript

```ts
import { setSessionId } from "@amplitude/analytics-react-native";

setSessionId(Date.now());
```

## Custom device ID

You can assign a new device ID using `deviceId`. When you set a custom device ID, make sure the value is sufficiently unique. Amplitude recommends a UUID.

```ts
import { setDeviceId } from "@amplitude/analytics-react-native";
const { uuid } = require("uuidv4");

setDeviceId(uuid());
```

## Reset when a user logs out

`reset` is a shortcut to anonymize users after they log out, by:

- Setting `userId` to `undefined`.
- Setting `deviceId` to a new UUID value.

With an undefined `userId` and a completely new `deviceId`, the current user appears as a brand new user in the dashboard.

```ts
import { reset } from "@amplitude/analytics-react-native";

reset();
```

## Opt users out of tracking

You can turn off logging for a given user by setting `setOptOut` to `true`.

```ts
import { setOptOut } from "@amplitude/analytics-react-native";

setOptOut(true);
```

The SDK doesn't save or send any events to the server while `setOptOut` is enabled, and the setting persists across page loads.

Re-enable logging by setting `setOptOut` to `false`.

```ts
import { setOptOut } from "@amplitude/analytics-react-native";

setOptOut(false);
```

## Optional tracking

By default, the SDK tracks these properties automatically. You can override this behavior by passing a configuration called `trackingOptions` when you initialize the SDK, setting the appropriate options to false.

| Tracking Options | Default |
| --- | --- |
| `adid` | `true` |
| `carrier` | `true` |
| `deviceManufacturer` | `true` |
| `deviceModel` | `true` |
| `ipAddress` | `true` |
| `language` | `true` |
| `osName` | `true` |
| `osVersion` | `true` |
| `platform` | `true` |

```ts
amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  trackingOptions: {
    adid: false,
    appSetId: false,
    carrier: false,
    deviceManufacturer: false,
    deviceModel: false,
    ipAddress: false,
    idfv: false,
    language: false,
    osName: false,
    osVersion: false,
    platform: false,
  },
});
```

## Callback

All asynchronous APIs are optionally awaitable through a Promise interface. The Promise interface also serves as a callback interface.

```ts
import { track } from "@amplitude/analytics-react-native";

// Using async/await
const results = await track("Button Clicked").promise;
result.event; // {...} (The final event object sent to Amplitude)
result.code; // 200 (The HTTP response status code of the request.
result.message; // "Event tracked successfully" (The response message)

// Using promises
track("Button Clicked").promise.then((result) => {
  result.event; // {...} (The final event object sent to Amplitude)
  result.code; // 200 (The HTTP response status code of the request.
  result.message; // "Event tracked successfully" (The response message)
});
```

## Plugins

Plugins let you extend the Amplitude SDK's behavior by, for example, modifying event properties (enrichment type) or sending to third-party APIs (destination type). A plugin is an object with methods `setup()` and `execute()`.

To integrate Experiment as a plugin, install `@amplitude/plugin-experiment-react-native` and use the `experimentPlugin()` function. Refer to [Amplitude Analytics plugin](https://amplitude.com/docs/sdks/experiment-sdks/experiment-react-native#amplitude-analytics-plugin) in the Experiment React Native SDK documentation for setup details.

For Session Replay integration with Segment, refer to the [Session Replay React Native Segment Integration](https://amplitude.com/docs/sdks/session-replay/session-replay-react-native-segment-integration) guide.

### add

The `add` method adds a plugin to Amplitude. Plugins can help process and send events.

```typescript
import { add } from "@amplitude/analytics-react-native";

add(new Plugin());
```

### remove

The `remove` method removes the given plugin name from the client instance if it exists.

```typescript
import { remove } from "@amplitude/analytics-react-native";

remove(plugin.name);
```

### Plugin types

The SDK applies plugins to each event in a fixed order: `before` plugins run first, then `enrichment` plugins, then `destination` plugins.

- A `before` plugin (`type: "before"`) runs ahead of every enrichment plugin. Use it to set or guard event fields early, before other plugins read them. It has the same shape as an enrichment plugin: `execute()` returns the modified event, or `null` to drop it.
- An `enrichment` plugin (`type: "enrichment"`) modifies or enriches each event as it passes through, such as adding an event property. If you don't set `type`, the SDK treats the plugin as an enrichment plugin.
- A `destination` plugin (`type: "destination"`) sends events to a destination, such as a third-party API, and ends the pipeline.

The following `before` plugin lowercases `user_id` so that every enrichment and destination plugin reads the normalized value:

```ts
import { add, init, Types } from "@amplitude/analytics-react-native";

const normalizeUserIdPlugin = (): Types.BeforePlugin => ({
  name: "normalize-user-id",
  type: "before",
  execute: async (event: Types.Event) => {
    if (event.user_id) {
      event.user_id = event.user_id.toLowerCase();
    }
    return event;
  },
});

add(normalizeUserIdPlugin());
init(API_KEY);
```

### Plugin setup

This method contains logic for preparing the plugin for use and has config as a parameter. The expected return value is undefined. A typical use for this method is to copy configuration from config or instantiate plugin dependencies. The SDK calls this method when you register the plugin to the client through `client.add()`.

### Plugin.execute

This method contains the logic for processing events and has event as a parameter. As an enrichment type plugin, the expected return value is the modified or enriched event. As a destination type plugin, the expected return value is a map with keys: `event` (BaseEvent), `code` (number), and `message` (string). The SDK calls this method for each event, including Identify, GroupIdentify, and Revenue events, that you instrument through the client interface.

### Enrichment type plugin example

Here's an example of a plugin that modifies each instrumented event by adding an increment integer to the `event_id` property of an event starting from 100.

```ts
import { init, add } from "@amplitude/analytics-react-native";
import {
  ReactNativeConfig,
  EnrichmentPlugin,
  Event,
  PluginType,
} from "@amplitude/analytics-types";

export class AddEventIdPlugin implements EnrichmentPlugin {
  name = "add-event-id";
  type = PluginType.ENRICHMENT as const;
  currentId = 100;
  config?: ReactNativeConfig;

  /**
   * setup() is called on plugin installation
   * example: client.add(new AddEventIdPlugin());
   */
  async setup(config: ReactNativeConfig): Promise<undefined> {
    this.config = config;
    return;
  }

  /**
   * execute() is called on each event instrumented
   * example: client.track('New Event');
   */
  async execute(event: Event): Promise<Event> {
    event.event_id = this.currentId++;
    return event;
  }
}

init("API_KEY");
add(new AddEventIdPlugin());
```

### Destination type plugin example

Here's an example of a plugin that sends each instrumented event to a target server URL using your preferred HTTP client.

```ts
import { init, add } from "@amplitude/analytics-react-native";
import {
  ReactNativeConfig,
  DestinationPlugin,
  Event,
  PluginType,
  Result,
} from "@amplitude/analytics-types";

export class MyDestinationPlugin implements DestinationPlugin {
  name = "my-destination-plugin";
  type = PluginType.DESTINATION as const;
  serverUrl: string;
  config?: ReactNativeConfig;

  constructor(serverUrl: string) {
    this.serverUrl = serverUrl;
  }

  /**
   * setup() is called on plugin installation
   * example: client.add(new MyDestinationPlugin());
   */
  async setup(config: ReactNativeConfig): Promise<undefined> {
    this.config = config;
    return;
  }

  /**
   * execute() is called on each event instrumented
   * example: client.track('New Event');
   */
  async execute(event: Event): Promise<Result> {
    const payload = { key: "secret", data: event };
    const response = await fetch(this.serverUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Accept: "*/*",
      },
      body: JSON.stringify(payload),
    });
    return {
      code: response.status,
      event: event,
      message: response.statusText,
    };
  }
}

init("API_KEY");
add(new MyDestinationPlugin("https://custom.domain.com"));
```

## Advanced topics

### Opt out of AsyncStorage

The React Native SDK uses `@react-native-async-storage/async-storage` to persist identity and the event queue across app launches. If you'd rather use your own storage backend (for example `react-native-mmkv`, an encrypted store, or SQLite), you can supply your own storage and exclude AsyncStorage from your native build.

The SDK uses two separate storage slots:

- `storageProvider` for the event queue (events waiting to flush to Amplitude).
- `cookieStorage` for identity and session state (device ID, user ID, session ID).

Override both to fully opt out. If you only override `storageProvider`, the SDK still tries to read and write identity through the default chain, which falls back to AsyncStorage on native. If you've also removed AsyncStorage, identity degrades to in-memory and resets on every app launch.

#### Override both storage slots at init

Implement the `Storage` interface and pass both slots. `init`'s signature is `(apiKey, userId, options)` — pass `undefined` or the desired user ID for `userId` so the overrides land in the options slot.

```ts
import { init } from "@amplitude/analytics-react-native";

init(API_KEY, undefined, {
  storageProvider: myEventQueueStorage,
  cookieStorage: myIdentityStorage,
});
```

#### Exclude AsyncStorage from native autolinking

Add the package to `react-native.config.js` with both native platforms set to `null`.

```js
module.exports = {
  dependencies: {
    "@react-native-async-storage/async-storage": {
      platforms: { ios: null, android: null },
    },
  },
};
```

AsyncStorage no longer links into your iOS or Android binaries. The JS package stays in `node_modules` so `require()` still resolves, but because you've overridden both storage slots, the SDK never invokes any AsyncStorage methods.

> **Note:** React Native Web
>
> These steps cover iOS and Android only. React Native Web requires additional bundler configuration to strip AsyncStorage from the web bundle, which isn't yet documented here.

### Custom HTTP client

You can provide an implementation of the `Transport` interface to the `transportProvider` configuration option for customization. For example, you can send requests to your proxy server with customized HTTP request headers.

```ts
import { Transport } from "@amplitude/analytics-types";

class MyTransport implements Transport {
  async send(serverUrl: string, payload: Payload): Promise<Response | null> {
    // check example: https://github.com/amplitude/Amplitude-TypeScript/blob/main/packages/analytics-client-common/src/transports/fetch.ts
  }
}

amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  transportProvider: new MyTransport(),
});
```

### Location

The Amplitude ingestion servers resolve event location in the following order:

1. User-provided `city`, `country`, `region`.
2. Resolved from `location_lat` and `location_lng`.
3. Resolved from `ip`.

By default, the server determines location from the `ip`. To provide more granular location, you can set `city`, `country`, and `region` individually, or set `location_lat` and `location_lng`, which the server then resolves to `city`, `country`, and `region`. Amplitude doesn't set precise location in the SDK to avoid extra permissions that not all customers need.

To set fine-grain location, you can use an enrichment Plugin. Here is an [example](https://github.com/amplitude/Amplitude-TypeScript/blob/v1.x/examples/plugins/react-native-get-location-plugin/LocationPlugin.ts) of how to set `location_lat` and `location_lng`.

Disabling IP tracking with `ipAddress: false` in [TrackingOptions](#optional-tracking) prevents the backend from resolving location. In this case, you may want to create a Plugin like the previous example to set any relevant location information yourself.

### Carrier

Carrier support works on Android, but Apple stopped supporting it in iOS 16. In earlier versions of iOS, the SDK fetches carrier info using `CTCarrier` and `serviceSubscriberCellularProviders`, which are [deprecated](https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/3024511-servicesubscribercellularprovide) with [no replacement](https://developer.apple.com/forums/thread/714876?answerId=728276022#728276022).

### Advertising identifiers

Different platforms have different advertising identifiers. Because of user privacy concerns, Amplitude doesn't automatically collect these identifiers. You can enable them using the following instructions. The platform providers no longer recommend some identifiers for use. Read the notes that follow before you decide to enable them.

| Platform | Advertising Identifier | Recommended | Notes |
| --- | --- | --- | --- |
| Android | AppSetId | Yes | [AppSetId](https://developer.android.com/training/articles/app-set-id) is a unique identifier for the app instance. The system resets it when the user reinstalls the app. |
| Android | ADID | No | [ADID](https://support.google.com/googleplay/android-developer/answer/6048248?hl=en) is a unique identifier for the device. The system resets it when the user opts out of personalized ads. |
| iOS | IDFV | Yes | [IDFV](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor) is a unique identifier for the app instance. The system resets it when the user reinstalls the app. |
| iOS | IDFA | No | [IDFA](https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614151-advertisingidentifier) is a unique identifier for the device. The system resets it when the user opts out of personalized ads. |

#### Android

##### App set ID

App set ID is a unique identifier for each app install on a device. The user resets app set ID manually when they uninstall the app, or after 13 months of not opening the app. Google designed this as a privacy-friendly alternative to Ad ID for users who want to opt out of stronger analytics.

To use App Set ID, follow these steps.

1. Add `play-services-appset` as a dependency to the Android project of your app.

   ```bash
   dependencies {
       implementation 'com.google.android.gms:play-services-appset:16.0.2'
   }
   ```
2. Enable `trackingOptions.appSetId`.

   ```ts
   amplitude.init(API_KEY, OPTIONAL_USER_ID, {
     trackingOptions: {
       appSetId: true,
     },
   });
   ```

##### Android Ad ID

Android Ad ID is a unique identifier for each device. The user resets Android Ad ID manually when they opt out of personalized ads.

To use Android Ad ID, follow these steps.

1. Add `play-services-ads-identifier` as a dependency to the Android project of your app. The [latest Android SDK docs](https://amplitude.com/docs/sdks/analytics/android/android-kotlin-sdk#advertiser-id) describe the more detailed setup.

   ```bash
   dependencies {
     implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
   }
   ```

Android Ad ID is enabled by default. To disable it, set `trackingOptions.adId` to `false`.

```ts
amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  trackingOptions: {
    adId: false,
  },
});
```

#### iOS

##### IDFV

IDFV is a unique identifier for the app instance. The system resets IDFV when the user reinstalls the app.

To enable IDFV on iOS devices, set `trackingOptions.idfv` to `true`.

```ts
amplitude.init(API_KEY, OPTIONAL_USER_ID, {
  trackingOptions: {
    idfv: true,
  },
});
```

##### IDFA

> **Warning:**
>
> Amplitude no longer recommends IDFA. Consider using IDFV instead when possible.

IDFA is a unique identifier for the device. The system resets IDFA when the user opts out of personalized ads.

The React Native SDK doesn't directly access the IDFA because it requires adding the `AdSupport.framework` to your app. Instead, you can use an Enrichment Plugin to set the IDFA yourself.

Here is an [example Plugin that sets the IDFA](https://github.com/amplitude/Amplitude-TypeScript/blob/main/examples/plugins/react-native-idfa-plugin/idfaPlugin.ts) using a third-party library.

### Over the air updates (OTA)

If you use a platform like Expo that supports OTA updates, note that the SDK has both native and JS code. With OTA updates, you also need to make sure the native code updates. Refer to Expo's documentation on [publishing](https://docs.expo.dev/eas-update/introduction/) and [runtime versions](https://docs.expo.dev/eas-update/runtime-versions/) for more details.

The following table lists versions of the SDK with the native code changes:

| @amplitude/analytics-react-native |
| --- |
| [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/releases/tag/%40amplitude%2Fanalytics-react-native%401.3.0) |
| [1.6.0](https://github.com/amplitude/Amplitude-TypeScript/releases/tag/%40amplitude%2Fanalytics-react-native%401.6.0) |

