Instrument and configure the React Native SDK

이 페이지는 아직 귀하의 언어로 번역되지 않았습니다. 현재 작업 중이므로 곧 다시 확인해 주십시오.

This page covers what you do after your first event: tracking, identity, sessions, Autocapture, and data delivery. For signatures and every option, go to the React Native SDK reference. For changes between versions, go to the React Native SDK release notes.

The examples import the SDK as amplitude:

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

Track events

Track a custom event

Pass an event name and optional properties:

ts
amplitude.track("Song Played", {
  title: "Happy Birthday",
  duration: 145,
});

logEvent() is an alias of track().

Every event needs device_id or user_id. The SDK sets device_id for you. Amplitude rejects IDs shorter than 5 characters. To accept shorter IDs, set minIdLength. The SDK uses the HTTP V2 API, so its other field limits apply.

Pass the event as an object

Pass an object to set any event field directly, such as event-level groups:

ts
amplitude.track({
  event_type: "Song Played",
  event_properties: { title: "Happy Birthday" },
  groups: { orgId: "15" },
});

Override fields for one event

The third argument, eventOptions, sets fields on this event only. It doesn't change the SDK's stored identity.

ts
amplitude.track("Song Played", { title: "Happy Birthday" }, {
  user_id: "user-67890",
  time: 1793919426000,
});

Set user properties

Build an Identify object, then send it with identify(). The SDK sends it as an $identify event.

ts
const identifyEvent = new amplitude.Identify()
  .set("plan", "premium")
  .setOnce("initial_referrer", "newsletter")
  .add("login_count", 1)
  .append("visited_screens", "Settings")
  .unset("trial_end");

amplitude.identify(identifyEvent);

Each operation applies to one property. Use one operation per property per Identify object: the SDK keeps the first operation for a property and ignores later ones on the same object. clearAll() removes every user property and discards every other operation on the object. You can't undo clearAll(). For each operation, go to Identify.

User property changes apply to events from that point forward. A profile in User Lookup shows the change right away, but charts show it only on events sent after the identify. For details, go to User properties and events.

Assign a user to a group

setGroup() assigns the current user to one or more groups. It also sets groupType as a user property with the group name as its value.

ts
amplitude.setGroup("orgId", "15");
amplitude.setGroup("sport", ["soccer", "tennis"]);

To assign a group to one event only, without changing the user, pass groups in the event object.

Set group properties

groupIdentify() sets properties on a group, not on a user:

ts
const groupProperties = new amplitude.Identify().set("plan", "enterprise");

amplitude.groupIdentify("orgId", "15", groupProperties);

Track revenue

Build a Revenue object and send it with revenue(). The SDK sends it as a revenue_amount event. Revenue is price × quantity, unless you call setRevenue().

ts
const purchase = new amplitude.Revenue()
  .setProductId("com.company.premium")
  .setPrice(3.99)
  .setQuantity(3)
  .setRevenueType("purchase")
  .setCurrency("USD");

amplitude.revenue(purchase);

For revenue verification, also call setReceipt() and setReceiptSig(). For every setter, go to Revenue.

Send events to more than one project

Create an instance for each project. Each instance has its own API key, identity, queue, and plugins. Give each one a unique instanceName so their stored data doesn't collide.

ts
const secondary = amplitude.createInstance();
secondary.init("OTHER_API_KEY", undefined, {
  instanceName: "secondary",
});

secondary.track("Song Played");

Pass the options as the third argument. init() reads the second argument as a user ID.

Identity and sessions

How the SDK chooses identifiers on load

init() restores identity from storage before it tracks anything. For each identifier, the first source that has a value wins.

  • Device ID: the deviceId option, then the stored value, then data from the maintenance SDK when migrateLegacyData is on, then a new random UUID.
  • User ID: the userId argument or option, then the stored value, then maintenance SDK data. If none exists, events have no user_id.
  • Session ID: the stored session, if it's still active. Otherwise a new session that starts at init().

On iOS and Android, the SDK stores identity in AsyncStorage, so it survives app restarts. On react-native-web it uses a cookie, then localStorage. To use other storage, go to Store data somewhere other than AsyncStorage.

Set the user ID

Call setUserId() when a user signs in. Every later event carries the ID.

ts
amplitude.setUserId("user-12345");

If you already know the user ID at startup, pass it to init() instead.

Reset identity when a user signs out

reset() clears the user ID and generates a new device ID, so the next user on the device appears as a new user. The session continues.

ts
amplitude.reset();

Set the device ID

The SDK generates a random UUID as the device ID. To use your own identifier, call setDeviceId() with a value unique to the device, such as a UUID:

ts
amplitude.setDeviceId("8d8a2e3c-2b6f-4f7e-9c1e-3a5b0c6d7e8f");

How sessions work

A session ID is the session's start time in milliseconds since the Unix epoch. All events in the session carry it as session_id.

The SDK starts a new session when:

  • init() runs and no stored session is still active.
  • The app returns to the foreground more than sessionTimeout (5 minutes by default) after the last event.
  • The app tracks an event while it's in the background or inactive, more than sessionTimeout after the last event.

While the app stays in the foreground, the session doesn't time out.

The SDK sends session_start and session_end events only when you turn on session Autocapture. session_end carries the previous session's ID.

Application lifecycle events in 1.13.0

In version 1.13.0, when autocapture.appLifecycles is on, returning to the foreground after sessionTimeout doesn't start a new session. The SDK tracks [Amplitude] Application Opened first, which refreshes the session before the timeout check. If you need session rollover on foreground, turn off appLifecycles, or start a session yourself with setSessionId().

Keep a session alive without an event

extendSession() records activity without sending an event, so the session's timeout starts over:

ts
amplitude.extendSession();

Start a session with a specific ID

setSessionId() ends the current session and starts one with the ID you pass. Use a timestamp in milliseconds.

ts
amplitude.setSessionId(Date.now());

After you call setSessionId(), the SDK keeps that session ID until you call it again or the app restarts. Sessions don't time out on their own in the meantime.

Opt users out of tracking

setOptOut(true) stops the SDK from sending events. The SDK stores the setting with identity, so it persists across app launches until you call setOptOut(false).

ts
amplitude.setOptOut(true);

To start opted out, pass optOut: true to init().

Autocapture

Choose a starting point

Autocapture is off by default. Pass autocapture: true to turn on every feature, or an object to choose features. Features you leave out of the object stay off.

ts
// Every Autocapture feature
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: true,
});

// Only the features you list
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: {
    sessions: true,
    appLifecycles: true,
    screenViews: true,
  },
});

Autocapture requires 1.6.6 or later. Some features require later versions. Go to Autocapture options.

Let Amplitude settings control Autocapture

To manage Autocapture from Amplitude's Autocapture settings instead of only in code, turn on remote configuration:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: true,
  remoteConfig: { fetchRemoteConfig: true },
});

The SDK fetches the settings during init() and merges them over your local autocapture value. Remote settings apply only when local autocapture is true or an object. If you omit autocapture or set it to false, remote settings can't turn it on. Remote configuration is off by default in the React Native SDK. Requires 1.10.0 or later.

Features and events

For each event's properties, go to Autocaptured event properties.

Sessions

autocapture.sessions sends session_start and session_end whenever the session ID changes. For when that happens, go to How sessions work.

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: { sessions: true },
});

The older trackingSessionEvents: true option does the same thing. Use autocapture.sessions for new code.

Application lifecycles

autocapture.appLifecycles tracks app state changes from React Native's AppState:

  • [Amplitude] Application Installed: The first launch for which the SDK has no stored app build (Android) or version and build (iOS). That includes the first launch after you turn on appLifecycles for existing users. Includes [Amplitude] Version and [Amplitude] Build. Requires 1.6.8 or later.
  • [Amplitude] Application Updated: The first launch after an update. On iOS, a change in version or build counts as an update. On Android, only a change in build does. Includes the current and previous version and build. Requires 1.6.8 or later.
  • [Amplitude] Application Opened: The app is in the foreground at init(), or returns to the foreground after it was in the background.
  • [Amplitude] Application Backgrounded: The app moves to the background.

A change from inactive to active, such as closing Control Center on iOS, doesn't count as an open. The SDK doesn't track Installed and Updated events on react-native-web.

Screen views

Screen views aren't automatic. Call the helpers from your navigation code. Each call sends [Amplitude] Screen Viewed with the screen name in [Amplitude] Screen Name. Element interaction and frustration events also include the last screen name.

To track a screen by name:

ts
amplitude.trackScreenView("Home");

With React Navigation, pass the navigation state to trackScreenViewOnNavigationStateChange(). onStateChange doesn't fire for the first screen, so also call it from onReady:

tsx
import {
  NavigationContainer,
  useNavigationContainerRef,
} from "@react-navigation/native";
import * as amplitude from "@amplitude/analytics-react-native";

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

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

The helper finds the focused screen in nested navigators. It skips a call when the focused screen hasn't changed, such as onReady followed by onStateChange, or a change to route params only. reset() and a new init() clear that memory, so the current screen can send again.

The helpers work without autocapture.screenViews. To turn them off, for example in a build where you don't want screen views, set screenViews: false.

Element interactions

autocapture.elementInteractions sends [Amplitude] Element Interacted each time a handler wrapped with ampCapture() runs. Wrap handlers yourself, or let the Babel plugin wrap them at build time. Requires 1.6.8 or later.

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: { elementInteractions: true },
});
tsx
import { Button } from "react-native";
import { ampCapture } from "@amplitude/analytics-react-native";

<Button
  title="Sign up"
  testID="sign-up"
  accessibilityLabel="Sign up"
  onPress={ampCapture(handleSignUp, {
    action: "Press",
    testID: "sign-up",
    accessibilityLabel: "Sign up",
    element: "Button",
    component: "SignUpScreen",
  })}
/>;

Each property you pass becomes an event property: action becomes [Amplitude] Action, testID becomes [Amplitude] Target Test ID, and so on. Use the action names the Babel plugin uses, such as Press and LongPress, with that capitalization. Frustration interactions count only Press and LongPress.

Wrap handlers with the Babel plugin

The @amplitude/babel-plugin-autocapture-transformer plugin wraps handlers on common interactive components with ampCapture() at build time, and adds the ampCapture import for you.

  1. Install the plugin as a dev dependency:

    bash
    npm install --save-dev @amplitude/babel-plugin-autocapture-transformer
    
  2. Add it to 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"],
      };
    };
    
  3. Restart Metro with a clean cache, for example npx react-native start --reset-cache or npx expo start --clear.

The plugin rewrites a handler like this:

jsx
// Your code
<Button testID="12345" accessibilityLabel="Sign up" title="Sign up" onPress={handleSignUp} />

// After the plugin runs, inside a component named SignUpScreen
<Button
  testID="12345"
  accessibilityLabel="Sign up"
  title="Sign up"
  onPress={ampCapture(handleSignUp, {
    action: "Press",
    accessibilityLabel: "Sign up",
    testID: "12345",
    element: "Button",
    component: "SignUpScreen",
  })}
/>

The plugin wraps these components and handlers:

To include your own components, list their names in the plugin options:

js
plugins: [
  [
    "@amplitude/babel-plugin-autocapture-transformer",
    {
      pressableElements: ["CustomButton"],
      valueChangeElements: ["Toggle"],
      textChangeElements: ["SearchField"],
    },
  ],
],

The plugin matches plain JSX names only. It skips <RN.Button>-style member names, handlers written as strings, and testID or accessibilityLabel passed through a spread such as {...props}. It leaves out component when the enclosing function is anonymous.

Frustration interactions

autocapture.frustrationInteractions detects two patterns on handlers wrapped with ampCapture():

  • Rage clicks: Four or more presses within 1 second, all within 50 pixels of each other. The SDK sends one [Amplitude] Rage Click with the element properties from the first press. Requires 1.11.0 or later.
  • Error clicks: A press or long press followed by an unhandled JavaScript error within 2 seconds. The SDK sends [Amplitude] Error Click with the error details. Experimental. Requires 1.12.0 or later.
ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: {
    frustrationInteractions: true,
  },
});

Both detectors are on when you pass true. To turn one off, pass an object:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: {
    frustrationInteractions: { rageClick: true, errorClick: false },
  },
});

Rage clicks need the press position, so the wrapped handler must receive the press event (with nativeEvent.pageX and nativeEvent.pageY), and action must be Press. Error clicks hook React Native's global error handler and pass each error on to the handler you had before.

Network tracking

autocapture.networkTracking sends [Amplitude] Network Request for failed requests your JavaScript makes with fetch or XMLHttpRequest. With networkTracking: true, the SDK tracks responses with status codes 500 to 599 and ignores requests to Amplitude. The SDK doesn't capture requests that native modules make outside JavaScript. Requires 1.6.7 or later.

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: { networkTracking: true },
});

To choose which requests to track and what to capture, pass an options object:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  autocapture: {
    networkTracking: {
      ignoreHosts: ["*.example.com"],
      captureRules: [
        {
          statusCodeRange: "400-599",
          responseHeaders: true,
          responseBody: { allowlist: ["error/**"] },
        },
      ],
    },
  },
});

The SDK evaluates captureRules from last to first, so put rules for specific URLs or hosts at the end. Header capture with true records only safe headers. Body capture works on JSON bodies only and records nothing until you set an allowlist. For every option, go to NetworkTrackingOptions.

allowlist and excludelist take JSON pointer paths with an optional leading /. * matches one key, and ** matches any number of keys. The captured body keeps the original structure. For example, with this response body:

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

allowlist: ["b/**"] captures {"b":{"c":"C","d":{"e":"E","f":"F"}}}.

Plugins

Add a plugin

A plugin is an object with a name, a type, and an execute() method. The SDK runs plugins in a fixed order: before plugins, then enrichment plugins (the default type), then destination plugins. A before or enrichment plugin returns the event, changed or not, or null to drop it.

This before plugin lowercases the user ID so every later plugin reads the normalized value:

ts
amplitude.add({
  name: "normalize-user-id",
  type: "before",
  execute: async (event) => {
    if (event.user_id) {
      event.user_id = event.user_id.toLowerCase();
    }
    return event;
  },
});

A destination plugin sends events somewhere else. It returns a result instead of an event:

ts
amplitude.add({
  name: "my-destination",
  type: "destination",
  execute: async (event) => {
    const response = await fetch("https://example.com/events", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(event),
    });
    return { event, code: response.status, message: response.statusText };
  },
});

Remove a plugin by name with amplitude.remove("my-destination"). For setup() and teardown(), go to Plugin.

Amplitude publishes plugins for other products:

To add every product with one package, use the Unified SDK for React Native.

Set location

Amplitude resolves an event's location in this order:

  1. city, country, and region on the event.
  2. location_lat and location_lng on the event.
  3. The request's IP address.

The SDK doesn't collect precise location, because that needs permissions not every app has. To add it, set the fields in an enrichment plugin. For an example, go to the location plugin example.

If you set trackingOptions.ipAddress to false, Amplitude can't resolve location from IP. Set location fields yourself in that case.

Device properties

Control which device properties the SDK collects

The SDK adds device properties to every event. On iOS and Android its native module reads them. Turn individual properties off with trackingOptions:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  trackingOptions: {
    ipAddress: false,
    carrier: false,
    adid: false,
  },
});

Every option except country is on by default. For the list, go to trackingOptions.

carrier works on Android. On iOS 16 and later, Apple returns no carrier information and has no replacement API.

Advertising identifiers

The Android identifiers come from Google Play services, which the SDK loads only if your app includes them. Add the libraries you need to android/app/build.gradle:

groovy
dependencies {
  implementation "com.google.android.gms:play-services-appset:16.0.2"
  implementation "com.google.android.gms:play-services-ads-identifier:18.0.1"
}

For ADID, also follow the Advertising ID setup for Android. To turn an identifier off, set its option to false in trackingOptions.

Amplitude no longer recommends IDFA. If you need it, use an enrichment plugin that reads it with a third-party library. Go to the IDFA plugin example.

Data delivery

How the SDK uploads events

The SDK queues each event, then uploads the queue flushIntervalMillis (1 second by default) after the first event enters it. Each request carries up to flushQueueSize (30 by default) events. Failed uploads retry up to flushMaxRetries (5) times. For results and retries, go to Read the upload result.

To tune the upload interval and batch size:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  flushIntervalMillis: 20000,
  flushQueueSize: 50,
});

flushQueueSize caps the batch size. It doesn't trigger an early upload.

Flush queued events

flush() sends every queued event now:

ts
await amplitude.flush().promise;

Choose a data region

Set serverZone to "EU" for projects in Amplitude's EU data center. Use the API key from the EU project.

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  serverZone: "EU",
});

To send to the Batch API instead of HTTP V2, set useBatch: true. For each combination's URL, go to Check what the SDK sent.

Send events through a proxy

To send events to your own server, set serverUrl:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  serverUrl: "https://analytics-proxy.example.com/2/httpapi",
});

When you set serverUrl, the SDK ignores serverZone and useBatch.

To control the request itself, for example to add headers, pass a transportProvider. Its send() method receives the URL and payload, and returns the parsed response:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  transportProvider: {
    async send(serverUrl, payload) {
      const response = await fetch(serverUrl, {
        method: "POST",
        headers: { "Content-Type": "application/json", "X-Proxy-Token": "TOKEN" },
        body: JSON.stringify(payload),
      });
      const body = await response.json();
      return {
        status: response.ok ? "success" : "failed",
        statusCode: response.status,
        body: {
          eventsIngested: body.events_ingested,
          payloadSizeBytes: body.payload_size_bytes,
          serverUploadTime: body.server_upload_time,
        },
      };
    },
  },
});

For a full implementation that handles every status, go to the SDK's FetchTransport source.

Work offline

The SDK detects connectivity and holds events while the device is offline, then uploads them when it reconnects. Offline detection is on by default. Requires 1.6.0 or later.

  • iOS: The native module uses NWPathMonitor. pod install links it.
  • Android: The native module uses ConnectivityManager. The SDK's manifest adds the ACCESS_NETWORK_STATE permission to your app.
  • react-native-web: The SDK uses navigator.onLine and the browser's online and offline events.

Queued events stay in the storageProvider, so they survive an app restart while offline.

To turn off detection, set offline to null. The SDK then uploads on its normal schedule, regardless of connection status:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  offline: null,
});

Don't use OfflineDisabled

amplitude.Types.OfflineDisabled is undefined in the React Native SDK, so offline: amplitude.Types.OfflineDisabled leaves detection on. Use null.

With detection off, you can set offline yourself from your own network logic. Set it to true to hold uploads and false to resume.

Store data somewhere other than AsyncStorage

The SDK keeps two kinds of data, each in its own storage option:

  • storageProvider: The queue of events waiting to upload.
  • cookieStorage: Identity and session state, such as the device ID, user ID, and session ID.

Both default to AsyncStorage on iOS and Android. To use another store, such as MMKV, SQLite, or an encrypted store, implement the Storage interface and pass both options:

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  storageProvider: myEventQueueStorage,
  cookieStorage: myIdentityStorage,
});

If you override only storageProvider, identity still goes to AsyncStorage. If AsyncStorage isn't available either, the SDK keeps identity in memory, so every launch gets a new device ID.

To leave AsyncStorage out of your native build, exclude it from autolinking in react-native.config.js:

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

The JavaScript package stays installed, so imports still resolve, but the SDK never calls it after you override both options. These steps cover iOS and Android only.

Send SDK logs to your own logger

Pass a loggerProvider to send SDK logs somewhere other than console, for example to collect errors in production. The logger must implement disable(), enable(logLevel), log(), warn(), error(), and debug().

ts
amplitude.init("AMPLITUDE_API_KEY", undefined, {
  logLevel: amplitude.Types.LogLevel.Error,
  loggerProvider: {
    disable: () => {},
    enable: () => {},
    log: () => {},
    debug: () => {},
    warn: (...args) => console.warn(...args),
    error: (...args) => reportToErrorService(args),
  },
});

The SDK calls your logger's enable() with logLevel during init(), and then sends it messages at every level. Filter by level in your logger.

이 내용이 도움이 되었나요?

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

이 페이지에서