---
updatedAt: 2026-02-12T13:51:17.000Z
agentTools:
  projectIndex: https://docs.emergetools.com/llms.txt
---

# Setup (Android)

Get started using Reaper in Android in under 10 minutes

<br />

<Callout icon="📘" theme="info">
  Reaper is now fully open-sourced and not available as a managed service. Learn more here:

  * [Open Source Blog](https://blog.sentry.io/an-open-source-sdk-for-finding-dead-code/)
  * [iOS Repo](https://github.com/getsentry/Reaper-iOS)
  * [Android Repo](https://github.com/EmergeTools/emerge-android/tree/main/reaper) 
</Callout>

Reaper is a library that uses production data to detect dead code. See the [emerge-android](https://github.com/EmergeTools/emerge-android/blob/main/reaper/README.md) repo for source code.

# Quick setup (\~10 minutes)

## Install the library

First, if you haven't already, you must install our Gradle plugin by following our [setup guide](https://docs.emergetools.com/docs/gradle-plugin#quick-setup-10-minutes). The Gradle plugin is used to instrument your application code.

Second, add an implementation dependency for the Reaper library:

Latest versions:

* Gradle plugin: [![Gradle Plugin Portal Version](https://img.shields.io/gradle-plugin-portal/v/com.emergetools.android.svg)](https://plugins.gradle.org/plugin/com.emergetools.android)
* Reaper library [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.emergetools.reaper/reaper/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.emergetools.reaper/reaper)

```kotlin build.gradle.kts (app)
// app-module build.gradle.kts
dependencies {
  implementation("com.emergetools.reaper:reaper:<latest_version>")
}
```

## Configure the Reaper extension in Gradle

The library automatically sends user sessions to Emerge's backend, allowing Emerge to determine used & unused code.

To send sessions we need to configure two settings within the `reaper` extension: `enabledVariants` and `publishableApiKey`.

* `enabledVariants` is a `ListProperty<String>` property that controls whether the plugin instruments the bytecode during compilation. for the specified variants
* `publishableApiKey` is a token included with Reaper reports uploaded from the field to Emerge. The key can be found in [Emerge's settings](https://www.emergetools.com/settings?tab=feature-configuration\&cards=reaper_enabled). This key is safe to commit to your repository.

> ❗ Reaper's Publishable API key is different from the Emerge API Token
>
> The Reaper API key (`publishableApiKey`) is a standalone key that is used with the library to associate requests with your Emerge account. This is different from the Emerge API token (`apiToken/EMERGE_API_TOKEN`) used to upload builds.
> You can find your Reaper API key on a Reaper build page or in [Emerge's settings](https://www.emergetools.com/settings?tab=feature-configuration\&cards=reaper_enabled).

```kotlin build.gradle.kts
// app-module build.gradle.kts
plugins {
  id("com.emergetools.android")
}

emerge {
  reaper {
    enabledVariants.set(listOf("release"))
    publishableApiKey = "<PUBLISHABLE API KEY>"
  }
}
```
```groovy build.gradle
// app-module build.gradle
plugins {
  id("com.emergetools.android")
}

emerge {
  reaper {
    enabledVariants = ["release"]
    publishableApiKey = "<PUBLISHABLE API KEY>"
  }
}
```

## Setup verification

Emerge offers a task, `./gradlew :<app>:emergeReaperPreflight<variant>` to verify Reaper is set up properly for each release variant of your application.

```shell shell
› ./gradlew :app:emergeReaperPreflightRelease

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

> Task :app:emergeReaperPreflightRelease

╔═════════════════════════════════════════════╗
║ Reaper preflight check was successful (4/4) ║
╠═════════════════════════════════════════════╝
╠═ ✅ Emerge API token set
╠═ ✅ enabled for variant: release
╠═ ✅ publishableApiKey set
╚═ ✅ Runtime library added
```

Any errors in the Reaper configuration will be raised here with instructions for how to address them.

## Build and upload the release AAB

> 🚧 Reaper is intended to run on Release builds
>
> Emerge recommends only enabling Reaper on non-debug variants.
>
> Even if just for testing, Emerge does not recommend leveraging debug builds with reaper, as it can lead to inaccurate results due to lack of minification and other optimizations that occur only in release builds.

Emerge requires a release AAB with Reaper to be uploaded, as Emerge analyzes the app to determine all classes available.

This is done automatically by the default AGP `./gradlew :<app>:bundle<variant>` Gradle task. Emerge hooks the `bundle` tasks for any variants specified with `enabledVariants` and uploads the AAB automatically to Emerge.

Emerge will then parse the uploaded AAB and find all possible classes in the app, which will later be marked as used/unused when user reports are uploaded.

### Viewing Reaper data

All versions of your app with Reaper included can be viewed in the uploads page, under the "Reaper" tab: <https://www.emergetools.com/uploads?tab=reaper>.

<Image align="center" alt="The Reaper versions tab contains all app versions with valid Reaper data, viewable from the &#x22;Uploads&#x22; page." caption="The Reaper versions tab contains all app versions with valid Reaper data, viewable from the &#x22;Uploads&#x22; page." src="https://files.readme.io/bb27dec-Screenshot_2024-08-08_at_10.46.06_AM.png" />

Clicking on a version will take you to a detailed breakdown of class usage information for that app version.

<Image align="center" alt="Reaper class usage information can be viewed in the Reaper tab." border={true} caption="Reaper class usage information can be viewed in the Reaper sidebar tab." src="https://files.readme.io/b04f0e1-Screenshot_2024-07-24_at_10.59.06_AM.png" />

Once Reaper is in your app, as your users use the application, reports will be sent and analyzed by Emerge to aggregate class usage information.

*Note: After setting up/uploading for the first time, it's expected for an app to have all classes marked as unused and no session counts. Once you release your app with Reaper integrated and sessions begin to be uploaded, Emerge will reflect unused classes and session counts in the UI.*

## Publish the built AAB

The `./gradlew :<app>:bundle<variant>` will generate the AAB for the specific variant specified in the standard output directory (`<app>/build/outputs/bundle/<variant>/app-<variant>.aab`) with Reaper set up.

Emerge recommends publishing the built AAB to Google Play and any other publications as the final release build artifact.

> 👍 That's it!
>
> Once published, the Emerge Reaper library. will begin uploading real code usage reports to Emerge.
>
> Read on for more information on how Reaper works and how to interpret results.

# How does it work?

Reaper works by instrumenting your app's code using Emerge's gradle plugin. The plugin adds "breadcrumb" logging, which records hashed information about code as it's used.

The Reaper library will aggregate this information into a background report. Once users leave your app, the Reaper library will upload the report to Emerge. Emerge will then connect the hashed class usage information on our backend with the detected classes in your app, which is then used to determine which code is used and unused.

Emerge will then reflect which code is unused in the Reaper UI. Emerge recommends waiting some time for a critical amount of sessions to be received before taking action on deleting unused code.

## Performance impact

Emerge has heavily tested Reaper on apps like [Hacker News](https://github.com/EmergeTools/hackernews) and [Now in Android](https://github.com/android/nowinandroid). The overall performance impact of adding/using reaper is negligible. Reaper adds \~2 instructions to the init method of a class.

Nonetheless, Emerge would encourage adding Reaper into a beta/internal release track before rolling out to production and validating using Emerge performance testing or any other performance metrics your team currently leverages.

> ❗ `Reaper.fuseOff` in the control arm of experiments
>
> If you are manually initializing Reaper in the treatment arm of an experiment
> you should call `Reaper.fuseOff(context)` in the *control* arm in order to minimize the impact of the instrumentation on the control arm.

## Size impact

The overall size impact of Reaper is a function of the number of classes in the app. The library itself adds \~12kb of download size to an app. Additionally, Reaper relies on class instrumentation, which will add a few instructions and an 8-byte hash string to each class.

For apps like apps like [Hacker News](https://github.com/EmergeTools/hackernews) and [Now in Android](https://github.com/android/nowinandroid), we've seen a \~5% increase in download size from adding Reaper.

# Library initialization

## Setting `baseUrl`

To send Reaper data to a custom URL set `com.emergetools.OVERRIDE_BASE_URL` in `AndroidManifest.xml`.

The Reaper library sends data to two endpoints:

* `$baseUrl/report`
* `$baseUrl/reaper/error`

So if baseUrl is set to `https://example.com/foo` as below Reaper reports will be sent to:

* `https://example.com/foo/report`
  and errors will be sent to:
* `https://example.com/foo/reaper/error`

```xml AndroidManifest.xml
  <meta-data
    android:name="com.emergetools.OVERRIDE_BASE_URL"
    android:value="https://example.com/foo" />
```

In both cases we `POST` json data.
The data format is defined [here](https://github.com/EmergeTools/emerge-android/blob/reaper-v1.0.1/reaper/reaper/src/main/kotlin/com/emergetools/reaper/ReaperReport.kt).

## Automatic initialization

Reaper relies on the [Androidx startup library](https://developer.android.com/topic/libraries/app-startup) to auto-initialize the Reaper library as part of your app's startup.

## Disable automatic initialization

To disable automatic initialization add the following snippet to your app's `AndroidManifest.xml`:

```xml AndroidManifest.xml
<provider
  android:name="androidx.startup.InitializationProvider"
  android:authorities="${applicationId}.androidx-startup"
  android:exported="false"
  tools:node="merge">
  <meta-data android:name="com.emergetools.reaper.ReaperInitializer"
    tools:node="remove" />
</provider>
```

You may need to add a direct dependency on the`androidx.startup:startup-runtime` library if the app does not already have such a dependency.

```kotlin build.gradle.kts (app)
// app-module build.gradle.kts
dependencies {
  implementation("androidx.startup:startup-runtime:<latest_version>")
}
```

Follow the [Manual initialization](#manual-initialization) steps below to ensure that Reaper is initialized.

## Manual initialization

To manually initialize Reaper call `Reaper.init(context)`. For example:

```kotlin MyApp.kt
import com.emergetools.reaper.Reaper

class MyApp : Application() {
  override fun onCreate() {
    Reaper.init(this)
  }
}
```
```java MyApp.java
import com.emergetools.reaper.Reaper;

public class MyApp extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    Reaper.init(this);
  }
}
```

If you know Reaper will never be initialized in a given processes lifetime but the code is instrumented with Reaper
you should call `Reaper.fuseOff(context)` to minimize the overhead of the instrumentation.

A common case when manual initialization is required is when `androidx.startup.InitializationProvider` has been [globally disabled](https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration?_gl=1*zaner1*_up*MQ..*_ga*Mzg1MDcwNDgwLjE3MjA3MDc2MDI.*_ga_6HH9YJMN9M*MTcyMDcwNzYwMi4xLjAuMTcyMDcwNzYwMi4wLjAuMA..#remove-default) by the following snippet being included in the `AndroidManifest.xml`:

```xml AndroidManifest.xml
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="remove">
  <meta-data
    	android:name="androidx.work.WorkManagerInitializer"
    	android:value="androidx.startup"
    	tools:node="remove" />
</provider>
```

# Common Errors

## `Missing classes detected while running R8`

*Example error message*

```
ERROR: Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in missing_rules.txt.
ERROR: R8: Missing class com.emergetools.reaper.ReaperInternal (referenced from: void \_COROUTINE.ArtificialStackFrames.<init>() and 5715 other contexts)
```

*Cause* This occurs when the Gradle plugin instruments the code but the library is not added as a implementation dependency.

*Fix* Add the following code to the application `build.gradle.kts` file:

```kotlin build.gradle.kts (app)
// app-module build.gradle.kts
dependencies {
  implementation("com.emergetools.reaper:reaper:<latest_version>")
}
```