
The Kotlin Android SDK lets you send events to Amplitude.

{% accordion title="Recent features" %}

- Frustration Analytics (v1.22.0+): Automatically detect and track rage clicks and dead clicks to identify areas of user frustration in your app. Configure tracking for both Android Views and Jetpack Compose, with options to [ignore specific elements](#ignore-specific-elements-from-frustration-analytics). Refer to [Track frustration interactions](#track-frustration-interactions).
- Network Tracking Plugin (v1.21.0+): Automatically track network requests and responses with OkHttp integration, including request/response sizes, status codes, and timing information. Refer to [Network Tracking Plugin](#network-tracking-plugin).
- Enhanced Jetpack Compose support (v1.21.3+): Full autocapture support for all clickable Compose elements with improved element identification. Refer to [Track element interactions](#track-element-interactions).
- Element Interactions Autocapture (v1.17.0+): Track user interactions with clickable UI elements in both Android Views and Jetpack Compose automatically. Refer to [Track element interactions](#track-element-interactions).
- Fragment Autocapture (v1.18.0+): Automatically capture fragment views with detailed fragment properties including class, identifier, and tag. Refer to [Track screen views](#track-screen-views).
- Advanced Identify operations: Full support for user property operations including `clearAll()` to remove all user properties. Refer to [Identify](#identify).

{% callout type="note" heading="Location tracking default change" %}
As of v1.20.7, the SDK disables location tracking by default. Call `enableLocationListening()` to track location data. [Learn more](#location-tracking).
{% /callout %}
{% /accordion %}

## System requirements

The Android Kotlin SDK supports Android API level 21 (Android 5.0 Lollipop) and higher.

## Install the SDK

Amplitude recommends using Android Studio as an IDE and Gradle to manage dependencies.

{% tabs tabs="Gradle, Maven" %}
{% tab name="Gradle" %}
If you use Gradle in your project, add the following dependency to `build.gradle`, and sync your project with the updated file.

```groovy
dependencies {
    implementation 'com.amplitude:analytics-android:1.+'
}
```

{% /tab %}
{% tab name="Maven" %}
If you use Maven in your project, the .jar is available on Maven Central with the following configuration in `pom.xml`.

```xml
<dependency>
    <groupId>com.amplitude</groupId>
    <artifactId>analytics-android</artifactId>
    <version>[1.0,2.0]</version>
</dependency>
```

{% /tab %}
{% /tabs %}

## Configure the SDK

{% accordion title="Configuration options" %}
| Name | Description | Default Value |
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deviceId` | `String?`. The device ID to use for this device. If no deviceID is provided, the SDK generates one automatically. Learn more in [Device ID lifecycle](#device-id-lifecycle). | `null` |
| `flushIntervalMillis` | `Int`. The amount of time the SDK waits before attempting to upload unsent events to the server or reach the `flushQueueSize` threshold. The value is in milliseconds. | `30000` |
| `flushQueueSize` | `Int`. The SDK attempts to upload after the unsent event count exceeds the event upload threshold or reaches the `flushIntervalMillis` interval. | `30` |
| `flushMaxRetries` | `Int`. Maximum retry times. | `5` |
| `minIdLength` | `Int`. The minimum length for user id or device id. | `5` |
| `partnerId` | `Int`. The partner id for partner integration. | `null` |
| `identifyBatchIntervalMillis` | `Long`. The amount of time the SDK waits before batching intercepted identify events. The value is in milliseconds. | `30000` |
| `flushEventsOnClose` | `Boolean`. Flushing of unsent events on app close. | `true` |
| `callback` | `EventCallBack`. Callback function after event sent. | `null` |
| `optOut` | `Boolean`. Opt the user out of tracking. | `false` |
| ~`trackingSessionEvents`~ (Deprecated. Use [`autocapture`](#autocapture) instead.) | `Boolean`. Automatic tracking of "Start Session" and "End Session" events that count toward event volume. | `false` |
| ~`defaultTracking`~ (Deprecated. Use [`autocapture`](#autocapture) instead.) | `DefaultTrackingOptions`. Enable tracking of default events for sessions, app lifecycles, screen views, and deep links. | `DefaultTrackingOptions(sessions = true)` |
| `autocapture` | `Set<AutocaptureOption>`. A `Set` of Options to enable tracking of default events for sessions, application lifecycles, screen and fragment views, deep links, and element interactions. | If the parameter isn't set, `AutocaptureOption.SESSIONS` is added to the `Set` by default. For more information, refer to [Autocapture](#autocapture). |
| `interactionsOptions` | `InteractionsOptions`. Configuration for granular control over frustration interaction tracking types (rage clicks and dead clicks). | `InteractionsOptions(rageClick = RageClickOptions(enabled = true), deadClick = DeadClickOptions(enabled = true))` |
| `minTimeBetweenSessionsMillis` | `Long`. The amount of time for session timeout. The value is in milliseconds. | `300000` |
| `sessionId` | `Long?`. Initial session ID to use. If not set, session management handles ID generation automatically. | `null` |
| `serverUrl` | `String`. The server url events upload to. | `https://api2.amplitude.com/2/httpapi` |
| `serverZone` | `ServerZone.US` or `ServerZone.EU`. The server zone to send to. The SDK adjusts the server URL based on this config. | `ServerZone.US` |
| `httpClient` | `HttpClientInterface?`. Custom HTTP client implementation for event uploads. Implement the `HttpClientInterface` to use your own HTTP client. | `null` |
| `useBatch` | `Boolean` Whether to use batch API. | `false` |
| `useAdvertisingIdForDeviceId` | `Boolean`. Whether to use advertising id as device id. For more information, refer to [Advertiser ID](#advertiser-id) for required module and permission. | `false` |
| `useAppSetIdForDeviceId` | `Boolean`. Whether to use app set id as device id. For more information, refer to [Application ID](#app-set-id) for required module and permission. | `false` |
| `trackingOptions` | `TrackingOptions`. Options to control the values tracked in SDK. | `enable` |
| `enableCoppaControl` | `Boolean`. Whether to enable COPPA control for tracking options. | `false` |
| `instanceName` | `String`. The name of the instance. Instances with the same name share storage and identity. For isolated storage and identity, use a unique `instanceName` for each instance. | `$default_instance` |
| `migrateLegacyData` | `Boolean`. Available in `1.9.0`+. Whether to migrate [maintenance Android SDK](/docs/sdks/analytics/android/android-sdk) data (events, user/device ID). For more information, refer to the [Amplitude-Kotlin RemnantDataMigration source](https://github.com/amplitude/Amplitude-Kotlin/blob/main/android/src/main/java/com/amplitude/android/migration/RemnantDataMigration.kt#L9-L16). | `true` |
| `offline` | `Boolean \| AndroidNetworkConnectivityCheckerPlugin.Disabled`. Whether the SDK is connected to network. For more information, refer to [Offline mode](#offline-mode). | `false` |
| `storageProvider` | `StorageProvider`. Implements `StorageProvider` interface to store events. | `AndroidStorageProvider` |
| `identifyInterceptStorageProvider` | `StorageProvider`. Implements `StorageProvider` interface for identify event interception and volume optimization. | `AndroidStorageProvider` |
| `identityStorageProvider` | `IdentityStorageProvider`. Implements `IdentityStorageProvider` to store user id and device id. | `FileIdentityStorageProvider` |
| `loggerProvider` | `LoggerProvider`. Implements the `LoggerProvider` interface to emit log messages to the destination you choose. | `AndroidLoggerProvider` |
| `newDeviceIdPerInstall` | Whether to generate a different device id every time the app is installed, regardless of devices. This legacy configuration exists to keep compatibility with the old Android SDK. It works the same as `useAdvertisingIdForDeviceId`. | `false` |
| `locationListening` | Whether to enable Android location service. For more information, refer to [Location tracking](#location-tracking). | `true` |
| `enableAutocaptureRemoteConfig` | `Boolean`. Whether to enable remote configuration for autocapture options. | `true` |

{% /accordion %}

### Configure batching behavior

To support high-performance environments, the SDK sends events in batches. The SDK queues every event logged by the `track` method in memory and flushes them in batches in the background. Customize batch behavior with `flushQueueSize` and `flushIntervalMillis`. By default, `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 regular mode and batch mode use the same event upload threshold and flush time intervals.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    flushIntervalMillis = 50000
    flushQueueSize = 20
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setFlushIntervalMillis(1000);
configuration.setFlushQueueSize(10);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

### EU data residency

Configure the server zone when initializing the client to send data to Amplitude's EU servers. The SDK sends data based on the server zone if you set it.

{% callout type="note" heading="" %}
For EU data residency, set up the project inside Amplitude EU. Initialize the SDK with the API key from Amplitude EU.
{% /callout %}

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    serverZone = ServerZone.EU
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setServerZone(ServerZone.EU);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

### Custom HTTP client

The SDK uses `HttpURLConnection` by default for network requests. To use a custom HTTP client, implement `HttpClientInterface` and pass it to the `httpClient` configuration option.

#### OkHttp with gzip compression

The sample app demonstrates how to create a custom OkHttp client with gzip compression for event uploads:

- [GzipRequestInterceptor](https://github.com/amplitude/Amplitude-Kotlin/blob/main/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/GzipRequestInterceptor.kt) - OkHttp interceptor that compresses request bodies.
- [CustomOkHttpClient](https://github.com/amplitude/Amplitude-Kotlin/blob/main/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/CustomOkHttpClient.kt) - `HttpClientInterface` implementation using OkHttp.

To use the custom client:

{% code-group %}
```kotlin Kotlin
val httpClient = CustomOkHttpClient()

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    this.httpClient = httpClient
}

httpClient.initialize(amplitude.configuration)
```

```java Java
CustomOkHttpClient httpClient = new CustomOkHttpClient();
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setHttpClient(httpClient);

Amplitude amplitude = new Amplitude(configuration);
httpClient.initialize(configuration);
```
{% /code-group %}

{% callout type="note" heading="" %}
The SDK's default HTTP client already compresses request bodies using gzip. Use a custom OkHttp client when you need additional features like custom timeouts, certificate pinning, or logging interceptors.
{% /callout %}

## Track

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

```kotlin
amplitude.track("Song Played")

```

You can also optionally include event properties.

```kotlin
amplitude.track(
  "Song Played",
  mutableMapOf<String, Any?>("title" to "Happy Birthday")
)

```

For more complex events you can [create and track a `BaseEvent` object](https://github.com/amplitude/Amplitude-Kotlin/blob/8c3c39ce1f79485a0ce716bbf01de464a9afe9a8/core/src/main/java/com/amplitude/core/Amplitude.kt#L112).

```kotlin
var event = BaseEvent()
event.eventType = "Song Played"
event.eventProperties = mutableMapOf<String, Any?>("title" to "Happy Birthday")
event.groups = mutableMapOf<String, Any?>("test-group-type" to "test-group-value")
event.insertId = 1234
amplitude.track(event)

```

## Identify

{% callout type="note" heading="" %}
Starting in release v1.7.0, the SDK batches `identify` events that contain only `set` operations. This batching reduces the number of sent events and doesn't affect how `set` operations run. Use the `identifyBatchIntervalMillis` configuration setting to manage the interval at which the SDK flushes batched identify intercepts.
{% /callout %}

Identify sets 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. Use the Identify interface to declare the operations. You can chain multiple operations in a single Identify object, then pass the Identify object to the Amplitude client to send to the server.

{% callout type="note" heading="" %}
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 chart results until the SDK sends another event after the Identify call. The identify call only affects events going forward.
{% /callout %}

Use the identify methods to handle a user's identity. Proper use of these methods connects events to the correct user as they move across devices, browsers, and other platforms. Send an identify call containing those user property operations to the Amplitude server to tie a user's events to specific user properties.

```kotlin
val identify = Identify()
identify.set("color", "green")
amplitude.identify(identify)

```

### Identify operations

The `Identify` object supports the following operations:

| Operation    | Description                                                                                      |
| ------------ | ------------------------------------------------------------------------------------------------ |
| `set`        | Sets the value of a user property. Overwrites existing values.                                   |
| `setOnce`    | Sets the value of a user property only once. Subsequent calls don't overwrite the initial value. |
| `add`        | Adds a numeric value to a numeric user property.                                                 |
| `append`     | Appends a value to a user property array.                                                        |
| `prepend`    | Prepends a value to a user property array.                                                       |
| `preInsert`  | Adds a value to the beginning of a user property array if it doesn't already exist in the array. |
| `postInsert` | Adds a value to the end of a user property array if it doesn't already exist in the array.       |
| `remove`     | Removes a value from a user property array.                                                      |
| `unset`      | Removes a user property.                                                                         |
| `clearAll`   | Clears all user properties.                                                                      |

{% code-group %}
```kotlin Kotlin
val identify = Identify()
identify
    .set("color", "green")
    .setOnce("initial_source", "organic")
    .add("login_count", 1)
    .append("visited_pages", "home")
    .prepend("notifications", "new_feature")
    .unset("temporary_property")

amplitude.identify(identify)

```

```java Java
Identify identify = new Identify();
identify
    .set("color", "green")
    .setOnce("initial_source", "organic")
    .add("login_count", 1)
    .append("visited_pages", "home")
    .prepend("notifications", "new_feature")
    .unset("temporary_property");

amplitude.identify(identify);

```
{% /code-group %}

### Clear all user properties

Use `clearAll()` to clear all user properties for the current user. This operation is irreversible.

{% callout type="warning" heading="Use with caution" %}
The `clearAll()` operation removes all user properties. This action is permanent. You can't undo it.
{% /callout %}

{% code-group %}
```kotlin Kotlin
val identify = Identify()
identify.clearAll()
amplitude.identify(identify)

```

```java Java
Identify identify = new Identify();
identify.clearAll();
amplitude.identify(identify);

```
{% /code-group %}

## Autocapture

Starting from release v1.18.0, the SDK can track more events without manual instrumentation. Configure the SDK to track the following events automatically:

- Sessions.
- App lifecycles.
- Screen views.
- Deep links.
- Element interactions.
- Frustration interactions:
  - Rage clicks.
  - Dead clicks.

{% accordion title="Autocapture options" %}
| Name | Type | Enabled by default | Description |
| ---------------------- | ------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SESSIONS` | `AutocaptureOption` | Yes | Enables session tracking. When the option is set, Amplitude tracks session start and session end events. Otherwise, Amplitude doesn't track session events. When you don't set this option, Amplitude tracks `sessionId` only. Refer to [Track sessions](#track-sessions) for more information. |
| `APP_LIFECYCLES` | `AutocaptureOption` | No | Enables application lifecycle events tracking. If the option is set, Amplitude tracks application installed, application updated, application opened, and application backgrounded events. Tracked event properties include: `[Amplitude] Version`, `[Amplitude] Build`, `[Amplitude] Previous Version`, `[Amplitude] Previous Build`, `[Amplitude] From Background`. Refer to [Track application lifecycles](#track-application-lifecycles) for more information. |
| `SCREEN_VIEWS` | `AutocaptureOption` | No | Enables screen and fragment views tracking. If the option is set, Amplitude tracks screen viewed and fragment viewed events. Tracked event properties include: `[Amplitude] Screen Name`, `[Amplitude] Fragment Class`, `[Amplitude] Fragment Identifier`, `[Amplitude] Fragment Tag`. Refer to [Track screen views](#track-screen-views) for more information. |
| `DEEP_LINKS` | `AutocaptureOption` | No | Enables deep link tracking. If the option is set, Amplitude tracks deep link opened events. Tracked event properties include: `[Amplitude] Link URL`, `[Amplitude] Link Referrer`. Refer to [Track deep links](#track-deep-links) for more information. |
| `ELEMENT_INTERACTIONS` | `AutocaptureOption` | No | Enables element interaction tracking. If the option is set, Amplitude tracks user interactions with clickable elements. Tracked event properties include: `[Amplitude] Action`, `[Amplitude] Target Class`, `[Amplitude] Target Resource`, `[Amplitude] Target Tag`, `[Amplitude] Target Source`, `[Amplitude] Hierarchy`, `[Amplitude] Screen Name`. Refer to [Track element interactions](#track-element-interactions) for more information. |
| `FRUSTRATION_INTERACTIONS` | `AutocaptureOption` | No | Enables frustration interaction tracking. When you enable the option, Amplitude tracks frustration interactions (rage clicks and dead clicks) with clickable UI elements. Rage clicks generate the `[Amplitude] Rage Click` event, and dead clicks generate the `[Amplitude] Dead Click` event. Refer to [Track frustration interactions](#track-frustration-interactions) for more information. |

{% /accordion %}

Configure Amplitude to start tracking Autocapture events. Otherwise, omit the configuration to keep only session tracking enabled.

{% tabs tabs="Kotlin, Java" %}
{% tab name="Kotlin" %}
The `autocapture` configuration accepts a `Set` of `AutocaptureOption` values. To create the Autocapture options, use the `autocaptureOptions` helper function and add the options to the set with a unary plus sign (`+`) before each option.

```kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +sessions               // or `+AutocaptureOption.SESSIONS`
        +appLifecycles          // or `+AutocaptureOption.APP_LIFECYCLES`
        +deepLinks              // or `+AutocaptureOption.DEEP_LINKS`
        +screenViews            // or `+AutocaptureOption.SCREEN_VIEWS`
        +elementInteractions    // or `+AutocaptureOption.ELEMENT_INTERACTIONS`
        +frustrationInteractions // or `+AutocaptureOption.FRUSTRATION_INTERACTIONS`
    }
}
```

To enable all autocapture options, use `AutocaptureOption.ALL` or the `addAll()` method:

```kotlin
import com.amplitude.android.Amplitude
import com.amplitude.android.AutocaptureOption

// Using AutocaptureOption.ALL constant
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = AutocaptureOption.ALL
}

// Or using addAll() method with builder
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        addAll()
    }
}
```

By default, if you don't explicitly set the `autocapture` configuration during initialization, `configuration.autocapture` automatically includes `AutocaptureOption.SESSIONS`.

To prevent automatic session event capture, set `autocapture` without the `AutocaptureOption.SESSIONS` option.

```kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = setOf(AutocaptureOption.APP_LIFECYCLES)  // or use `setOf()` to disable autocapture.
}
```

{% /tab %}
{% tab name="Java" %}
The `autocapture` configuration accepts a `Set` of `AutocaptureOption` values.

```java
import com.amplitude.android.Amplitude;

import java.util.Arrays;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().addAll(Arrays.asList(
    AutocaptureOption.SESSIONS,
    AutocaptureOption.APP_LIFECYCLES,
    AutocaptureOption.DEEP_LINKS,
    AutocaptureOption.SCREEN_VIEWS,
    AutocaptureOption.ELEMENT_INTERACTIONS,
    AutocaptureOption.FRUSTRATION_INTERACTIONS
));

Amplitude amplitude = new Amplitude(configuration);
```

To enable all autocapture options, use `AutocaptureOption.ALL`:

```java
import com.amplitude.android.Amplitude;
import com.amplitude.android.AutocaptureOption;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().addAll(AutocaptureOption.ALL);

Amplitude amplitude = new Amplitude(configuration);
```

By default, if you don't explicitly set the `autocapture` configuration during `Configuration` initialization, `configuration.getAutocapture()` automatically includes `AutocaptureOption.SESSIONS`.

To prevent automatic session event capture, remove the `AutocaptureOption.SESSIONS` option from `autocapture`.

```java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().remove(AutocaptureOption.SESSIONS);

Amplitude amplitude = new Amplitude(configuration);
```

{% /tab %}
{% /tabs %}

### Track sessions

Amplitude enables session tracking by default. Include `AutocaptureOption.SESSIONS` in the `autocapture` configuration to explicitly configure the SDK to track session events, or to enable session event tracking along with other Autocapture configurations.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +sessions    // or `+AutocaptureOption.SESSIONS`
    }
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
// `AutocaptureOption.SESSION` is automatically set in `configuration.autocapture`.

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

For more information about session tracking, refer to [User sessions](#user-sessions).

### Track application lifecycles

Enable application lifecycle event tracking by including `AutocaptureOption.APP_LIFECYCLES` in the `autocapture` configuration. Refer to the following code sample.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +appLifecycles    // or `+AutocaptureOption.APP_LIFECYCLES`
    }
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().add(AutocaptureOption.APP_LIFECYCLES);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

After you enable this setting, Amplitude tracks the following events:

- `[Amplitude] Application Installed`: fires when a user opens the application for the first time right after installation.
- `[Amplitude] Application Updated`: fires when a user opens the application after updating the application.
- `[Amplitude] Application Opened`: fires when a user launches or foregrounds the application after the first open.
- `[Amplitude] Application Backgrounded`: fires when a user backgrounds the application.

### Track screen views

Enable screen and fragment view event tracking by including `AutocaptureOption.SCREEN_VIEWS` in the `autocapture` configuration. Refer to the following code sample.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +screenViews    // or `+AutocaptureOption.SCREEN_VIEWS`
    }
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().add(AutocaptureOption.SCREEN_VIEWS);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

After you enable this setting, Amplitude tracks both `[Amplitude] Screen Viewed` and `[Amplitude] Fragment Viewed` events. Both events include a screen name property. For `[Amplitude] Fragment Viewed` events, Amplitude captures additional fragment-specific properties.

{% accordion title="Event properties descriptions" %}
| Event property | Description |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `[Amplitude] Screen Name` | The activity title, activity label, activity name, activity class name, or application name (in order of priority). |
| `[Amplitude] Fragment Class` | The fully qualified class name of the viewed fragment. |
| `[Amplitude] Fragment Identifier` | The resource ID of the fragment as defined in the layout XML. |
| `[Amplitude] Fragment Tag` | The unique identifier assigned to the fragment during a transaction. |

{% /accordion %}

### Track deep links

Enable deep link event tracking by including `AutocaptureOption.DEEP_LINKS` in the `autocapture` configuration. Refer to the following code sample.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +deepLinks    // or `+AutocaptureOption.DEEP_LINKS`
    }
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().add(AutocaptureOption.DEEP_LINKS);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

After you enable this setting, Amplitude tracks the `[Amplitude] Deep Link Opened` event with the URL and referrer information.

#### Handle deep links in single-task activities

If your activity uses `singleTop`, `singleTask`, or `singleInstance` launch mode, Android delivers deep links that arrive while the activity is already running to `onNewIntent()` instead of creating a new activity. In this case, call `setIntent()` to update the activity's intent so Amplitude can track the deep link.

{% code-group %}
```kotlin Kotlin
override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    setIntent(intent) // Required for Amplitude to track the deep link
}
```

```java Java
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent); // Required for Amplitude to track the deep link
}
```
{% /code-group %}

{% callout type="note" heading="" %}
Without calling `setIntent()`, `getIntent()` continues to return the original intent that started the activity, and Amplitude doesn't detect the new deep link.
{% /callout %}

### Track element interactions

Amplitude can track user interactions with clickable elements, with support for both classic Android Views and Jetpack Compose. To enable this option, include `AutocaptureOption.ELEMENT_INTERACTIONS` in the `autocapture` configuration.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +elementInteractions    // or `+AutocaptureOption.ELEMENT_INTERACTIONS`
    }
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().add(AutocaptureOption.ELEMENT_INTERACTIONS);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

When you enable this setting, Amplitude tracks the `[Amplitude] Element Interacted` event whenever a user interacts with an element in the application.

{% accordion title="Event properties descriptions" %}
| Event property | Description |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `[Amplitude] Action` | The action that triggered the event. Defaults to `touch`. |
| `[Amplitude] Target Class` | The canonical name of the target view class. |
| `[Amplitude] Target Resource` | The resource entry name for the target view identifier within the context the view is running in. |
| `[Amplitude] Target Tag` | The tag of the target view if the value is of primitive type, or the `Modifier.testTag` of the target `@Composable` function if provided. This property is optional for Compose elements. |
| `[Amplitude] Target Text` | The text of the target view if the view is a `Button` instance. |
| `[Amplitude] Target Source` | The underlying framework of the target element, either `Android Views` or `Jetpack Compose`. |
| `[Amplitude] Hierarchy` | A nested hierarchy of the target view's class inheritance, from the most specific to the most general. |
| `[Amplitude] Screen Name` | Refer to [Track screen views](#track-screen-views). |

{% /accordion %}

{% callout type="info" heading="Support for Jetpack Compose" %}
Amplitude tracks user interactions with all clickable UI elements implemented in Jetpack Compose. `Modifier.testTag` is optional. Add it to `@Composable` functions to provide additional identification in the `[Amplitude] Target Tag` property. If no `testTag` is provided, Amplitude tracks the element with other available properties.

#### Use testTag for better element identification

While `testTag` is optional, Amplitude recommends that you identify specific Compose views that users clicked. The `testTag` property provides several benefits:

- Precise element identification: helps distinguish between similar UI elements (like multiple buttons or cards) in your analytics data.
- Stable tracking: provides a consistent identifier that doesn't change when you update or modify the UI structure or styling.
- Easier analysis: enables easier filtering and analysis of interactions with specific elements in Amplitude charts.
- Cross-platform consistency: helps you maintain consistent element naming across different platforms.

```kotlin
// Example: Adding testTag for better identification
Button(
    onClick = { /* handle click */ },
    modifier = Modifier.testTag("login_button")
) {
    Text("Log In")
}

Card(
    onClick = { /* handle click */ },
    modifier = Modifier.testTag("product_card_${product.id}")
) {
    // Card content
}
```

When a user clicks these elements, the `[Amplitude] Target Tag` property contains the `testTag` value, making it easy to identify which specific element the user interacted with in your analytics data.
{% /callout %}

### Track frustration interactions

Amplitude can track frustration interactions (Rage Clicks and Dead Clicks) with clickable UI elements in both Android Views and Jetpack Compose. To enable this option, include `AutocaptureOption.FRUSTRATION_INTERACTIONS` in the `autocapture` configuration.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +frustrationInteractions    // or `+AutocaptureOption.FRUSTRATION_INTERACTIONS`
    }
}
```

```java Java
import com.amplitude.android.Amplitude;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().add(AutocaptureOption.FRUSTRATION_INTERACTIONS);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

A rage click occurs when a user clicks the same element 4 or more times within 1 second, with each click no more than 50 device-independent pixels apart.

When a Rage Click occurs, Amplitude tracks the `[Amplitude] Rage Click` event.

{% accordion title="Event properties descriptions" %}
| Event property | Description |
| --- | --- |
| `[Amplitude] Begin Time` | The timestamp when the interaction began in ISO 8601 format. |
| `[Amplitude] End Time` | The timestamp when the interaction ended in ISO 8601 format. |
| `[Amplitude] Duration` | The duration of the interaction in milliseconds. |
| `[Amplitude] Click Count` | The number of clicks that occurred. |
| `[Amplitude] Clicks` | The array of clicks that occurred. |
| `[Amplitude] Clicks[].X` | The x-coordinate of the click from the top-left corner of the screen. |
| `[Amplitude] Clicks[].Y` | The y-coordinate of the click from the top-left corner of the screen. |
| `[Amplitude] Clicks[].Time` | The timestamp of the click in ISO 8601 format. |
| `[Amplitude] Action` | The action that triggered the event. Defaults to `touch`. |
| `[Amplitude] Target Class` | The canonical name of the target view class. |
| `[Amplitude] Target Resource` | The resource entry name for the target view identifier within the context the view is running in. |
| `[Amplitude] Target Tag` | The tag of the target view if the value is of primitive type, or the `Modifier.testTag` of the target `@Composable` function if provided. |
| `[Amplitude] Target Text` | The text of the target view if the view is a `Button` instance. |
| `[Amplitude] Target Source` | The underlying framework of the target element, either `Android Views` or `Jetpack Compose`. |
| `[Amplitude] Hierarchy` | A nested hierarchy of the target view's class inheritance, from the most specific to the most general. |
| `[Amplitude] Screen Name` | Refer to [Track screen views](#track-screen-views). |

{% /accordion %}

A dead click is a user interaction on an interactive element that produces no visible change in the following 3 seconds.

When a Dead Click occurs, Amplitude tracks the `[Amplitude] Dead Click` event.

{% accordion title="Event properties descriptions" %}
| Event property | Description |
| --- | --- |
| `[Amplitude] X` | The x-coordinate of the click from the top-left corner of the screen. |
| `[Amplitude] Y` | The y-coordinate of the click from the top-left corner of the screen. |
| `[Amplitude] Action` | The action that triggered the event. Defaults to `touch`. |
| `[Amplitude] Target Class` | The canonical name of the target view class. |
| `[Amplitude] Target Resource` | The resource entry name for the target view identifier within the context the view is running in. |
| `[Amplitude] Target Tag` | The tag of the target view if the value is of primitive type, or the `Modifier.testTag` of the target `@Composable` function if provided. |
| `[Amplitude] Target Text` | The text of the target view if the view is a `Button` instance. |
| `[Amplitude] Target Source` | The underlying framework of the target element, either `Android Views` or `Jetpack Compose`. |
| `[Amplitude] Hierarchy` | A nested hierarchy of the target view's class inheritance, from the most specific to the most general. |
| `[Amplitude] Screen Name` | Refer to [Track screen views](#track-screen-views). |

{% /accordion %}

### Configure frustration interaction types

Enabling `FRUSTRATION_INTERACTIONS` tracks both rage clicks and dead clicks. Use the `interactionsOptions` parameter to enable or disable each type individually.

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude
import com.amplitude.android.InteractionsOptions
import com.amplitude.android.RageClickOptions
import com.amplitude.android.DeadClickOptions

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = autocaptureOptions {
        +frustrationInteractions
    }
    interactionsOptions = InteractionsOptions(
        rageClick = RageClickOptions(enabled = true),
        deadClick = DeadClickOptions(enabled = false)
    )
}
```

```java Java
import com.amplitude.android.Amplitude;
import com.amplitude.android.InteractionsOptions;
import com.amplitude.android.RageClickOptions;
import com.amplitude.android.DeadClickOptions;

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().add(AutocaptureOption.FRUSTRATION_INTERACTIONS);
configuration.setInteractionsOptions(
    new InteractionsOptions(
        new RageClickOptions(true),
        new DeadClickOptions(false)
    )
);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

{% callout type="note" title="Dead clicks require Session Replay" %}
To track dead clicks, enable both Session Replay and frustration interactions.
{% /callout %}

### Ignore specific elements from frustration analytics

Some UI elements generate expected rapid clicks or don't provide meaningful frustration signals. Use the ignore APIs to exclude these elements from frustration analytics while still tracking regular interaction events.

Common use cases:

- Navigation elements: back buttons, close buttons, and drawer toggles.
- Multi-click elements: increment/decrement buttons and like/favorite buttons.
- Loading indicators: progress bars, spinners, and loading buttons.
- Decorative elements: non-functional UI components.

#### Android Views

Use `FrustrationAnalyticsUtils` to ignore frustration analytics for Android Views:

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.FrustrationAnalyticsUtils

// Ignore all frustration analytics for this view
val backButton = findViewById<Button>(R.id.back_button)
FrustrationAnalyticsUtils.ignoreFrustrationAnalytics(backButton)

// Ignore only rage clicks (allow dead click detection)
val incrementButton = findViewById<Button>(R.id.increment_button)
FrustrationAnalyticsUtils.ignoreFrustrationAnalytics(
    incrementButton,
    rageClick = true,
    deadClick = false
)

// Remove ignore marker from a view
FrustrationAnalyticsUtils.unignoreView(backButton)
```

```java Java
import com.amplitude.android.FrustrationAnalyticsUtils;

// Ignore all frustration analytics for this view
Button backButton = findViewById(R.id.back_button);
FrustrationAnalyticsUtils.INSTANCE.ignoreFrustrationAnalytics(backButton, true, true);

// Ignore only rage clicks (allow dead click detection)
Button incrementButton = findViewById(R.id.increment_button);
FrustrationAnalyticsUtils.INSTANCE.ignoreFrustrationAnalytics(incrementButton, true, false);

// Remove ignore marker from a view
FrustrationAnalyticsUtils.INSTANCE.unignoreView(backButton);
```
{% /code-group %}

#### Jetpack Compose

Use the `Modifier.ignoreFrustrationAnalytics()` extension to ignore frustration analytics for Compose elements:

```kotlin
import com.amplitude.android.ignoreFrustrationAnalytics

// Ignore all frustration analytics
Button(
    onClick = { finish() },
    modifier = Modifier.ignoreFrustrationAnalytics()
) { Text("Back") }

// Ignore only dead clicks (allow rage click detection)
Button(
    onClick = { submitForm() },
    modifier = Modifier.ignoreFrustrationAnalytics(
        rageClick = false,
        deadClick = true
    )
) { Text("Submit") }
```

#### Parameter combinations

| `rageClick`      | `deadClick`      | Behavior                             |
| ---------------- | ---------------- | ------------------------------------ |
| `true` (default) | `true` (default) | Ignore all frustration analytics     |
| `true`           | `false`          | Ignore only rage click detection     |
| `false`          | `true`           | Ignore only dead click detection     |
| `false`          | `false`          | Track both (doesn't ignore anything) |

{% callout type="note" heading="" %}
The SDK still tracks regular element interaction events (`[Amplitude] Element Interaction`) when you ignore frustration analytics. This affects only rage click and dead click events.
{% /callout %}

## User groups

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

For example, you want to group your users by organization using an `orgId`. Joe is in `orgId` `10`, and Sue is in `orgId` `15`. Both Sue and Joe perform a certain event. You can query their organizations in the Event Segmentation Chart.

When setting 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` is `sport`, with `groupName` values like `tennis` and `baseball`.

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

{% callout type="example" heading="" %}
If Joe is in `orgId` `15`, the `groupName` is `15`.

```kotlin
// set group with a single group name
amplitude.setGroup("orgId", "15");

```

If Joe is in `sport` `tennis` and `soccer`, the `groupName` is `["tennis", "soccer"]`.

```kotlin
// set group with multiple group names
amplitude.setGroup("sport", arrayOf("tennis", "soccer"))

```

{% /callout %}

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 the designation doesn't persist on the user unless you explicitly set it with `setGroup`.

```kotlin
val event = BaseEvent()
event.eventType = "event type"
event.eventProperties = mutableMapOf("event property" to "event property value")
event.groups = mutableMapOf("orgId" to "15")
amplitude.track(event)

```

## Group identify

Use the Group Identify API to set or update the properties of particular groups. Note these considerations:

- Updates affect only future events, and don't update historical events.
- You can track up to 5 unique group types and 10 total groups.

The `groupIdentify` method accepts a group type string parameter, a group name object parameter, and an Identify object that Amplitude applies to the group.

```kotlin
val groupType = "plan"
val groupName = "enterprise"

val identify = Identify().set("key", "value")
amplitude.groupIdentify(groupType, groupName, identify)

```

## Track revenue

Amplitude can track revenue generated by a user. Amplitude tracks revenue through distinct revenue objects, which have special fields that Amplitude's Event Segmentation and Revenue LTV charts use. Revenue objects automatically display data relevant to revenue in the platform. Revenue objects support the following special properties, as well as user-defined properties through the `eventProperties` field.

```kotlin
val revenue = Revenue()
revenue.productId = "com.company.productId"
revenue.price = 3.99
revenue.quantity = 3
amplitude.revenue(revenue)

```

| Name               | Description                                                                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `productId`        | Optional. String. An identifier for the product. Amplitude recommends something like the Google Play Store product ID. Defaults to `null`. |
| `quantity`         | Required. Integer. 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`.         |
| `revenueType`      | 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. For example, `123456`. Defaults to `null`.                                        |
| `receiptSignature` | Optional, but required for revenue verification. String. Defaults to `null`.                                                               |

## Custom user identifier

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

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

```

## Custom device identifier

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

```kotlin
import java.util.UUID

amplitude.setDeviceId(UUID.randomUUID().toString())

```

## Reset when a user logs out

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

- Setting `userId` to `null`.
- Setting `deviceId` to a new value based on current configuration.

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

```kotlin
amplitude.reset()

```

## SDK plugins

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

### Plugin.setup

This method contains logic for preparing the plugin for use and takes the `amplitude` instance as a parameter. The expected return value is `null`. A typical use for this method is to instantiate plugin dependencies. The SDK calls this method when the plugin is registered to the client through `amplitude.add()`.

### Plugin.execute

This method contains the logic for processing events and takes the `event` instance as a parameter. When used as an enrichment type plugin, the expected return value is the modified or enriched event. When used 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 using the client interface.

### Enrichment type plugin example

The following plugin modifies each instrumented event by adding an extra event property.

```java
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.amplitude.core.Amplitude;
import com.amplitude.core.events.BaseEvent;
import com.amplitude.core.platform.Plugin;

import java.util.HashMap;

public class EnrichmentPlugin implements Plugin {
  public Amplitude amplitude;
  @NonNull
  @Override
  public Amplitude getAmplitude() {
    return this.amplitude;
  }

  @Override
  public void setAmplitude(@NonNull Amplitude amplitude) {
    this.amplitude = amplitude;
  }

  @NonNull
  @Override
  public Type getType() {
    return Type.Enrichment;
  }

  @Nullable
  @Override
  public BaseEvent execute(@NonNull BaseEvent baseEvent) {
    if (baseEvent.getEventProperties() == null) {
      baseEvent.setEventProperties(new HashMap<String, Object>());
    }
    baseEvent.getEventProperties().put("custom android event property", "test");
    return baseEvent;
  }

  @Override
  public void setup(@NonNull Amplitude amplitude) {
    this.amplitude = amplitude;
  }
}

amplitude.add(new EnrichmentPlugin());

```

### Destination type plugin example

In a destination plugin, you can overwrite the `track()`, `identify()`, `groupIdentify()`, `revenue()`, and `flush()` functions.

```java
import com.amplitude.core.Amplitude;
import com.amplitude.core.events.BaseEvent;
import com.amplitude.core.platform.DestinationPlugin;
import com.segment.analytics.Analytics;
import com.segment.analytics.Properties;

public class SegmentDestinationPlugin extends DestinationPlugin {
  android.content.Context context;
  Analytics analytics;
  String writeKey;
  public SegmentDestinationPlugin(android.content.Context appContext, String writeKey) {
    this.context = appContext;
    this.writeKey = writeKey;
  }
  @Override
  public void setup(Amplitude amplitude) {
    super.setup(amplitude);
    analytics = new Analytics.Builder(this.context, this.writeKey)
    .build();

    Analytics.setSingletonInstance(analytics);
    }

  @Override
  public BaseEvent track(BaseEvent event) {
    Properties properties = new Properties();
    for (Map.Entry<String,Object> entry : event.getEventProperties().entrySet()) {
      properties.putValue(entry.getKey(),entry.getValue());
    }
    analytics.track(event.eventType, properties);
    return event;
    }
}

amplitude.add(
new SegmentDestinationPlugin(this, SEGMENT_WRITE_KEY)
)

```

### Network tracking plugin

The Network Tracking Plugin automatically tracks network requests and responses in your application. This plugin works with OkHttp and captures details about network calls including URLs, status codes, and timing information.

#### Installation

The Network Tracking Plugin requires the OkHttp dependency. To add it to your project:

{% code-group %}
```groovy Gradle
dependencies {
    // OkHttp is required for the NetworkTrackingPlugin
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}
```
{% /code-group %}

#### Configuration

Use the default configuration and add the plugin as an interceptor to integrate with OkHttp:

{% code-group %}
```kotlin Kotlin
import com.amplitude.core.network.NetworkTrackingPlugin

// Create the plugin with default configuration
val networkPlugin = NetworkTrackingPlugin()

// Add the plugin as an interceptor to your OkHttp client
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(networkPlugin)
    .build()

// Add the plugin to your Amplitude instance
amplitude.add(networkPlugin)
```

```java Java
import com.amplitude.core.network.NetworkTrackingPlugin;

// Create the plugin with default configuration
NetworkTrackingPlugin networkPlugin = new NetworkTrackingPlugin();

// Add the plugin as an interceptor to your OkHttp client
OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(networkPlugin)
    .build();

// Add the plugin to your Amplitude instance
amplitude.add(networkPlugin);
```
{% /code-group %}

The default configuration tracks all hosts except `*.amplitude.com` with status codes `500` to `599`.

{% accordion title="NetworkTrackingOptions.DEFAULT" %}
| Name | Description | Value |
| ------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `captureRules` | Captures all hosts (except `*.amplitude.com`) with status code `500` to `599`. | `NetworkTrackingOptions(captureRules = listOf(CaptureRule(hosts = listOf("*"), statusCodeRange = (500..599).toList())))` |
| `ignoreHosts` | Don't ignore any other hosts by default. | `[]` |
| `ignoreAmplitudeRequests` | Don't capture Amplitude requests by default. | `true` |

{% /accordion %}

Set `NetworkTrackingOptions` to customize tracking behavior and control which requests you track:

{% code-group %}
```kotlin Kotlin
import com.amplitude.android.Amplitude
import com.amplitude.core.network.NetworkTrackingOptions
import com.amplitude.core.network.NetworkTrackingPlugin
import com.amplitude.core.network.NetworkTrackingOptions.CaptureRule

// Create custom capture rules
val options = NetworkTrackingOptions(
    captureRules = listOf(
        // Track all responses from your API domain with status code from 400 to 599
        CaptureRule(
            hosts = listOf("*.example.com", "example.com"),
            statusCodeRange = (400..599).toList()
        )
    ),
    // Ignore specific domains
    ignoreHosts = listOf("analytics.example.com", "*.internal.com"),
    // Whether to ignore Amplitude API requests
    ignoreAmplitudeRequests = true
)

// Create the plugin with options
val networkPlugin = NetworkTrackingPlugin(options)

// Add the plugin to your Amplitude instance
amplitude.add(networkPlugin)
```

```java Java
import com.amplitude.android.Amplitude;
import com.amplitude.core.network.NetworkTrackingOptions;
import com.amplitude.core.network.NetworkTrackingPlugin;
import com.amplitude.core.network.NetworkTrackingOptions.CaptureRule;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

NetworkTrackingOptions options = new NetworkTrackingOptions(
    // Create custom capture rules
    Collections.singletonList(
        new NetworkTrackingOptions.CaptureRule(
            // Track all responses from your API domain with status code from 400 to 599
            Arrays.asList("*.example.com", "example.com"),
            new ArrayList<Integer>() {
              { for (int i = 400; i <= 599; i++) add(i); }
            }
        )
    ),
    // Ignore specific domains
    Arrays.asList("analytics.example.com", "*.internal.com"),
    // Whether to ignore Amplitude API requests
    true
);

// Create the plugin with options
NetworkTrackingPlugin networkPlugin = new NetworkTrackingPlugin(options);

// Add the plugin to your Amplitude instance
amplitude.add(networkPlugin);
```
{% /code-group %}

{% accordion title="NetworkTrackingOptions" %}
| Name | Description | Default Value |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
| `captureRules` | The rules for capturing network requests. You should always append rules with specific hosts to the bottom of the list. | `none` |
| `ignoreHosts` | The hosts to ignore. Supports wildcard characters `*`. For example, `["*"]` ignores all hosts, `["*.notmyapi.com", "notmyapi.com"]` ignores `notmyapi.com` and all subdomains. | `[]` |
| `ignoreAmplitudeRequests` | Whether to ignore Amplitude requests. | `true` |

{% /accordion %}

{% accordion title="NetworkTrackingOptions.CaptureRule" %}
| Name | Description | Default Value |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `hosts` | The hosts to capture. Supports wildcard characters `*`. For example, `["*"]` matches all hosts, `["*.example.com", "example.com"]` matches `example.com` and all subdomains. | `none` |
| `statusCodeRange` | The status code range to capture. For example, `(200..299) + 413 + (500..599)` | `"500-599"` |

{% /accordion %}

{% callout type="note" heading="" %}
The `captureRules` and `ignoreHosts` properties are mutually exclusive. If both are set, `ignoreHosts` takes precedence. Amplitude matches incoming requests against the `captureRules` from bottom to top. For example, with this configuration:

```kotlin
captureRules = listOf(
    CaptureRule(
        hosts = listOf("\*"),
        statusCodeRange = (400..599).toList()
    ),
    CaptureRule(
        hosts = listOf("\*.example.com", "example.com"),
        statusCodeRange = (500..599).toList()
    )
)
```

The SDK processes requests as follows:

- A request to `example.com` with status code 503: matches last rule's hosts → matches statusCodeRange → captured
- A request to `example.com` with status code 401: matches last rule's hosts → doesn't match statusCodeRange → ignored
- A request to `other.com` with status code 401: doesn't match last rule's hosts → matches first rule's hosts → matches statusCodeRange → captured
- A request to `other.com` with status code 200: doesn't match last rule's hosts → matches first rule's hosts → doesn't match statusCodeRange → ignored
{% /callout %}

#### Tracked event properties

When the plugin tracks a network request, it sends an event with the type `[Amplitude] Network Request` with the following properties:

| 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, etc.).                     |
| `[Amplitude] Status Code`        | The HTTP status code of the response.                                       |
| `[Amplitude] Error Message`      | The local error message if the request failed with out 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.                                     |

#### Privacy considerations

The Network Tracking Plugin masks the following sensitive information by default:

1. Authentication credentials in URLs (username:password@domain.com).
2. Common sensitive query parameters (for example, username, password, email, phone).

## Debugging

Confirm that the configuration and payload are accurate, and check for any unusual messages during debugging. If everything appears to be right, check the value of `flushQueueSize` or `flushIntervalMillis`. By default, the SDK queues and sends events in batches, so individual events don't dispatch to the server immediately. Wait for the SDK to send events to the server before checking for them in the charts.

### Log

- Set the [log level](#log-level) to debug to collect useful information during debugging.
- Customize the `loggerProvider` class from `LoggerProvider` and implement your own logic, such as logging error messages on a server in a production environment.

### Plugins

Use a destination plugin to print the configuration value and event payload before sending them to the server. Set `logLevel` to debug, copy the following `TroubleShootingPlugin` into your project, then add the plugin to the Amplitude instance.

- [Java TroubleShootingPlugin example](https://github.com/amplitude/Amplitude-Kotlin/blob/main/samples/java-android-app/src/main/java/com/amplitude/android/sample/TroubleShootingPlugin.java).
- [Kotlin TroubleShootingPlugin example](https://github.com/amplitude/Amplitude-Kotlin/blob/main/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/TroubleShootingPlugin.kt).

### Event callback

The event callback runs after the SDK sends the event, for both successful and failed events. Use this method to monitor the event status and message. For more information, refer to the Callback [configuration](#configure-the-sdk) setting.

## Advanced topics

### User sessions

Amplitude starts a session when the app moves into the foreground or when the SDK tracks an event in the background. A session ends when the app remains in the background for more than the time set by `setMinTimeBetweenSessionsMillis()` without any tracked event. A session continues for the entire time the app is in the foreground, regardless of whether you enable session tracking through `configuration.trackingSessionEvents`, `configuration.defaultTracking`, or `configuration.autocapture`.

When the app enters the foreground, Amplitude tracks a session start, and starts a countdown based on `setMinTimeBetweenSessionsMillis()`. Amplitude extends the session and restarts the countdown any time it tracks a new event. If the countdown expires, Amplitude waits until the next event to track a session end event.

Amplitude doesn't set user properties on session events by default. To add these properties, use `identify()` and `setUserId()`. Amplitude aggregates the user property state and associates the user with events based on `device_id` or `user_id`.

Because of how Amplitude manages sessions, the SDK can work as expected even when events appear to be missing or session tracking appears inaccurate:

- If a user doesn't return to the app, Amplitude doesn't track a session end event to correspond with a session start event.
- If you track an event in the background, it's possible that Amplitude perceives the session length to be longer than the user spends on the app in the foreground.
- If you modify user properties between the last event and the session end event, the session end event reflects the updated user properties, which may differ from other properties associated with events in the same session. To address this, use an enrichment plugin to set `event['$skip_user_properties_sync']` to `true` on the session end event, which prevents Amplitude from synchronizing properties for that specific event. Refer to [$skip_user_properties_sync](/docs/data/converter-configuration-reference#skipuserpropertiessync) in the Converter Configuration Reference article to learn more.

Amplitude groups events together by session. Events logged within the same session share the same `session_id`. Amplitude handles sessions automatically, so you don't have to manually call `startSession()` or `endSession()`.

Adjust the time window for session extension. The default session expiration time is 30 minutes.

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    minTimeBetweenSessionsMillis = 10000
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setMinTimeBetweenSessionsMillis(1000);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

By default, Amplitude automatically sends the `[Amplitude] Start Session` and `[Amplitude] End Session` events. Even when the SDK doesn't send these events, Amplitude still tracks sessions using `session_id`.
You can also disable those session events.

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    autocapture = setOf()
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.getAutocapture().remove(AutocaptureOption.SESSIONS);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

Use the helper method `getSessionId` to get the value of the current `sessionId`.

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    minTimeBetweenSessionsMillis = 10000
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setMinTimeBetweenSessionsMillis(10000);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

You can also track events as out-of-session. Out-of-session events have a `sessionId` of `-1` and behave as follows:

1. They aren't part of the current session.
2. They don't extend the current session.
3. They don't start a new session.
4. They don't change the `sessionId` for subsequent events.

A potential use case is events tracked from push notifications, which are usually external to the customer's app usage.

Set `sessionId` to `-1` in `EventOptions` to mark an event as out-of-session when you call `track(event, options)` or `identify(identify, options)`.

{% code-group %}
```kotlin Kotlin
val outOfSessionOptions = EventOptions().apply {
 sessionId = -1
}
amplitude.identify(
 Identify().set("user-prop", true),
 outOfSessionOptions
)
amplitude.track(
 BaseEvent().apply { eventType = "test event" },
 outOfSessionOptions
)

```

```java Java
EventOptions outOfSessionOptions = new EventOptions();
outOfSessionOptions.setSessionId(-1L);

amplitude.identify(
 new Identify().set("user-prop", true),
 outOfSessionOptions
);

BaseEvent event = new BaseEvent();
event.eventType = "test event";
amplitude.track(event, outOfSessionOptions);

```
{% /code-group %}

### Log level

Control the level of logs that print to the developer console.

- `INFO`: shows informative messages about events.
- `WARN`: shows error messages and warnings. This level logs issues that might cause problems or oddities in the data. For example, this level displays a warning for properties with null values.
- `ERROR`: shows error messages only.
- `DISABLE`: suppresses all log messages.
- `DEBUG`: shows error messages, warnings, and informative messages that may be useful for debugging.

Set the log level by calling `setLogLevel` with the level you want.

{% code-group %}
```kotlin Kotlin
amplitude.logger.logMode = Logger.LogMode.DEBUG

```

```java Java
amplitude.getLogger().setLogMode(Logger.LogMode.DEBUG);

```
{% /code-group %}

### Logged out and anonymous users

Amplitude [merges user data](/docs/data/sources/instrument-track-unique-users), so Amplitude links any events associated with a known `userId` or `deviceId` to the existing user.
If a user logs out, Amplitude can merge that user's logged-out events to the user's record. You can change this behavior and log those events to an anonymous user instead.

To log events to an anonymous user:

1. Set the `userId` to null.
2. Generate a new `deviceId`.

Events coming from the current user or device appear as a new user in Amplitude. Note: if you do this, you can't see that the two users used the same device.

```java
amplitude.reset()
```

### Disable tracking

By default, the Android SDK tracks several user properties such as `carrier`, `city`, `country`, `ip_address`, `language`, and `platform`.
Use the provided `TrackingOptions` interface to customize and toggle individual fields.

To use the `TrackingOptions` interface, import the class.

```java
import com.amplitude.android.TrackingOptions

```

Before you initialize the SDK with your `apiKey`, create a `TrackingOptions` instance with your configuration and set it on the SDK instance.

{% code-group %}
```kotlin Kotlin
val trackingOptions = TrackingOptions()
trackingOptions.disableCity().disableIpAddress().disableLatLng()

val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    this.trackingOptions = trackingOptions
}
```

```java Java
TrackingOptions trackingOptions = new TrackingOptions();
trackingOptions.disableCity().disableIpAddress().disableLatLng();

Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setTrackingOptions(trackingOptions);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

You can individually control tracking for each field. Each field has a corresponding method (for example, `disableCountry`, `disableLanguage`).

| Method                             | Description                                                           |
| ---------------------------------- | --------------------------------------------------------------------- |
| `disableAdid()`                    | Disable tracking of Google ADID                                       |
| `disableAppSetId()`                | Disable tracking of App Set Id                                        |
| `disableCarrier()`                 | Disable tracking of device's carrier                                  |
| `disableCity()`                    | Disable tracking of user's city                                       |
| `disableCountry()`                 | Disable tracking of user's country                                    |
| `disableDeviceBrand()`             | Disable tracking of device brand                                      |
| `disableDeviceModel()`             | Disable tracking of device model                                      |
| `disableTrackDeviceManufacturer()` | Disable tracking of device manufacturer                               |
| `disableDma()`                     | Disable tracking of user's designated market area (DMA).              |
| `disableIpAddress()`               | Disable tracking of user's IP address                                 |
| `disableLanguage()`                | Disable tracking of device's language                                 |
| `disableLatLng()`                  | Disable tracking of user's current latitude and longitude coordinates |
| `disableOsName()`                  | Disable tracking of device's OS Name                                  |
| `disableOsVersion()`               | Disable tracking of device's OS Version                               |
| `disablePlatform()`                | Disable tracking of device's platform                                 |
| `disableRegion()`                  | Disable tracking of user's region.                                    |
| `disableVersionName()`             | Disable tracking of your app's version name                           |
| `disableApiLevel`                  | Disable tracking of Android API level                                 |

{% callout type="note" heading="" %}
Using `TrackingOptions` only prevents the SDK from tracking default properties on newly created projects, where you haven't sent data yet. If you have a project with existing data and you want to stop collecting the default properties, get help in the [Amplitude Community](https://community.amplitude.com/). Disabling tracking doesn't delete any existing data in your project.
{% /callout %}

### Carrier

Amplitude determines the user's mobile carrier using [Android's TelephonyManager](https://developer.android.com/reference/kotlin/android/telephony/TelephonyManager#getnetworkoperatorname) `networkOperatorName`, which returns the current registered operator of the `tower`.

### COPPA control

You can enable or disable COPPA (Children's Online Privacy Protection Act) restrictions on IDFA, IDFV, city, IP address, and location tracking together. Apps that ask for information from children under 13 years of age must comply with COPPA.

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    enableCoppaControl = true // Disables ADID, city, IP, and location tracking
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
// Disables ADID, city, IP, and location tracking
configuration.setEnableCoppaControl(true);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

### Advertiser ID

The Android Advertising ID is a unique identifier provided by the Google Play store. Because it's unique to every person and not only to their devices, it's useful for mobile attribution. The Android Advertising ID is similar to the IDFA on iOS.
 [Mobile attribution](https://www.adjust.com/blog/mobile-ad-attribution-introduction-for-beginners/) attributes an installation of a mobile app to its original source (such as an ad campaign or app store search).
Users can choose to disable the Advertising ID, and apps targeted to children can't track at all.

Follow these steps to use Android Ad ID.

{% callout type="warning" heading="" %}
As of April 1, 2022, Google lets users opt out of Ad ID tracking. Ad ID may return null or error. You can use an alternative ID called [App Set ID](#app-set-id), which is unique to every app install on a device. For more information, refer to [Google's Advertising ID documentation](https://support.google.com/googleplay/android-developer/answer/6048248?hl=en).
{% /callout %}

1.  Add `play-services-ads-identifier` as a dependency.

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

2.  `AD_MANAGER_APP` Permission
    If you use Google Mobile Ads SDK version 17.0.0 or higher, you need to add `AD_MANAGER_APP` to `AndroidManifest.xml`.

        ```xml
        <manifest>
            <application>
                <meta-data
                    android:name="com.google.android.gms.ads.AD_MANAGER_APP"
                    android:value="true"/>
            </application>
        </manifest>
        ```

3.  Add ProGuard exception

    Amplitude Android SDK uses Java Reflection to use classes in Google Play Services. For Amplitude SDKs to work in your Android application, add these exceptions to `proguard.pro` for the classes from `play-services-ads`.
    `-keep class com.google.android.gms.ads.** { *; }`

4.  `AD_ID` Permission

    When you update apps to target Android 13 or above, you must declare a Google Play services normal permission in the manifest file, as follows, to use the ADID as a `deviceId`:

    ```xml
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
    ```

    For more information, refer to [Google's Advertising ID documentation](https://support.google.com/googleplay/android-developer/answer/6048248?hl=en).

#### Use the advertising ID as the device ID

After you set up the logic to fetch the advertising ID, enable `useAdvertisingIdForDeviceId` to use the advertising ID as the device ID.

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    useAdvertisingIdForDeviceId = true
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setUseAdvertisingIdForDeviceId(true);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

### 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 it resets automatically after 13 months of not opening the app.
Google designed app set ID 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. For versions earlier than 2.35.3, use `'com.google.android.gms:play-services-appset:16.0.0-alpha1'`

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

   ```

2. Enable to use app set ID as Device ID.

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    useAppSetIdForDeviceId = true
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setUseAppSetIdForDeviceId(true);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

### Device ID lifecycle

The SDK initializes the device ID in the following order, and sets the device ID to the first valid value it encounters:

1. Device ID of the instance.
2. ADID, if `useAdvertisingIdForDeviceId` is enabled and the required module is installed. For more information, refer to [Advertiser ID](#advertiser-id).
3. App Set ID with an `S` appended, if `useAppSetIdForDeviceId` is enabled and the required module is installed. For more information, refer to [App set ID](#app-set-id).
4. A randomly generated UUID with an `R` appended.

#### One user with multiple devices

A single user may have multiple devices, each with a different device ID. To ensure coherence, set the user ID consistently across all these devices. Even when the device IDs differ, Amplitude can still merge them into a single Amplitude ID and identify them as a unique user.

#### Transfer to a new device

Multiple devices can have the same device ID when a user switches to a new device. When users move to a new device, they often transfer their applications along with other relevant data. The specific transferred content varies by application. In general, it includes databases and file directories associated with the app. The exact items included depend on the app's design and the developer's choices. If databases or file directories transfer from one device to another, the device ID stored within them may still be present. If the SDK retrieves that device ID during initialization, different devices might end up using the same device ID.

#### Get device ID

Use the helper method `getDeviceId()` to get the value of the current `deviceId`.

{% code-group %}
```kotlin Kotlin
val deviceId = amplitude.getDeviceId();

```

```java Java
String deviceId = amplitude.getDeviceId();

```
{% /code-group %}

To set the device, refer to [custom device ID](#custom-device-identifier).

### Location tracking

Amplitude converts the IP of a user event into a location (GeoIP lookup) by default. An app's own tracking solution or user data can override this information.

{% callout type="note" heading="Location tracking in version 1.20.7+" %}
As of version 1.20.7, the SDK disables location tracking by default. Call `enableLocationListening()` to track location data. When enabled, Amplitude uses Android location services (if available) to add specific coordinates (longitude and latitude) to logged events. Call `disableLocationListening()` at any time to disable location tracking.
{% /callout %}

{% code-group %}
```kotlin Kotlin
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    locationListening = true
}
```

```java Java
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setLocationListening(true);

Amplitude amplitude = new Amplitude(configuration);
```
{% /code-group %}

{% callout type="note" heading="Proguard obfuscation" %}
If you use ProGuard obfuscation, add the following exception to the file:
`-keep class com.google.android.gms.common.** { *; }`
{% /callout %}

### Opt users out of tracking

Users may want to opt out of tracking entirely, which means Amplitude doesn't track any of their events or browsing history. `OptOut` provides a way to fulfill a user's privacy requests.

Amplitude doesn't save or send events while `optOut` is `true`.

{% code-group %}
```kotlin Kotlin
// At initialization
val amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    optOut = true
}

// At runtime
amplitude.optOut = true
amplitude.optOut = false // Re-enable tracking
```

```java Java
// At initialization
Configuration configuration = new Configuration(AMPLITUDE_API_KEY, getApplicationContext());
configuration.setOptOut(true);
Amplitude amplitude = new Amplitude(configuration);

// At runtime
amplitude.setOptOut(true);
amplitude.setOptOut(false); // Re-enable tracking
```
{% /code-group %}

### Push notification events

Don't send push notification events client-side with the Android SDK. Because a user must open the app to initialize the Amplitude SDK so the SDK can send the event, the SDK doesn't send events to the Amplitude servers until the next time the user opens the app. This can cause data delays.

{% code-group %}
```kotlin Kotlin
import com.amplitude.common.Logger
import com.amplitude.core.LoggerProvider

class sampleLogger : Logger {
override var logMode: Logger.LogMode
 get() = Logger.LogMode.DEBUG
 set(value) {}

 override fun debug(message: String) {
 TODO("Handle debug message here")
 }

 override fun error(message: String) {
 TODO("Handle error message here")
 }

 override fun info(message: String) {
 TODO("Handle info message here")
 }

 override fun warn(message: String) {
 TODO("Handle warn message here")
 }
}

class sampleLoggerProvider : LoggerProvider {
 override fun getLogger(amplitude: com.amplitude.core.Amplitude): Logger {
 return sampleLogger()
 }
}

amplitude = Amplitude(AMPLITUDE_API_KEY, applicationContext) {
    loggerProvider = sampleLoggerProvider()
}

```

```java Java
import com.amplitude.common.Logger;
import com.amplitude.core.LoggerProvider;

class sampleLogger implements Logger {
 @NonNull
 @Override
 public LogMode getLogMode() {
 return LogMode.DEBUG;
 }

 @Override
 public void setLogMode(@NonNull LogMode logMode) {
 // TODO("Handle debug message here")
 }

 @Override
 public void debug(@NonNull String message) {
 // TODO("Handle debug message here")
 }

 @Override
 public void error(@NonNull String message) {
 // TODO("Handle error message here")
 }

 @Override
 public void info(@NonNull String message) {
 // TODO("Handle info message here")
 }

 @Override
 public void warn(@NonNull String message) {
 // TODO("Handle warn message here")
 }
}

class sampleLoggerProvider implements LoggerProvider {
 @NonNull
 @Override
 public Logger getLogger(@NonNull com.amplitude.core.Amplitude amplitude) {
 return new sampleLogger();
 }
}

```
{% /code-group %}

### Multiple instances

You can create multiple instances of Amplitude. Instances with the same `instanceName` share storage and identity. For isolated storage and identity, use a unique `instanceName` for each instance. For more details, refer to [Configuration](#configuration).

```kotlin
val amplitude1 = Amplitude("api-key-1", applicationContext) {
    instanceName = "one"
}
val amplitude2 = Amplitude("api-key-2", applicationContext) {
    instanceName = "two"
}
```

### Offline mode

Starting from version 1.13.0, the Amplitude Android Kotlin SDK supports offline mode. The SDK checks network connectivity every time it tracks an event. If the device is connected to the network, the SDK schedules a flush. If not, it saves the event to storage. The SDK also listens for changes in network connectivity and flushes all stored events when the device reconnects.

To enable this feature, add the `ACCESS_NETWORK_STATE` permission to `AndroidManifest.xml`. Otherwise, the SDK flushes events based on `flushIntervalMillis` and `flushQueueSize`.

```xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
```

You can also implement your own offline logic:

1. Set `config.offline` to `AndroidNetworkConnectivityCheckerPlugin.Disabled` to disable the default offline logic.
2. Toggle `config.offline` by yourself.
