NimbleDroid User



Scenarios, or User Flows, are profiles of actions a real user might take. These can be things like loading a new page, clicking a control and waiting for the response, or scrolling a page. Cold Startup is one type of Scenario which NimbleDroid always measures. There are two ways to profile other Scenarios.

Cold Startup

Cold Startup is the first Scenario we profile, and the only one we profile for every app since it is a universal concept. Running your app directly after a device restart is a good example of real-world Cold Startup. We measure Cold Startup under the following conditions:

  • App has already been installed and run on a device
  • App is not currently loaded in the background
  • The time from app icon is clicked on Home until we determine Startup has finished.

How does NimbleDroid know that an app finishes startup?

We use a heuristic to tell when an app finishes startup by detecting when

  • the main Activity has been displayed
  • things like animated progress bars in the main Activity have stopped.

Before measurement starts, we run the app at least twice, wait for up to 30 seconds, and check the last Activity displayed. If this is consistent across multiple startups, it is designated the main Activity.

If this methodology doesn't match what you are trying to measure, you can customize the way Cold Startup is measured; see the Customization section.

Auto-discovered Scenarios

In order to provide maximum value with minimum effort, NimbleDroid will try by default to auto-discover Scenarios in your app using a crawler. The crawler will do simple actions like clicking buttons to discover navigation and actions in your app and build Scenarios from them. The crawler will run for a set amount of time and will add any Scenarios it finds.

Auto-discovered Scenarios always report measurements for the last action a user would take. There can be a variety of "setup" actions the user takes that would not get measured, followed by a final action that is measured. For example, a user might load the Home screen, click on a Product, Add To Cart, then click View Cart. In this case the loading of the Cart page is the last user action, and the one that would be measured.


Since many apps have important Scenarios accessible only after logging in, NimbleDroid provides an auto-login feature which will accept credentials from the user and attempt to use them to get the app into a logged-in state. For more on setting up auto-login, see the Using the Site section, and the Advanced Usage section for info about auto-login with the API and other integrations.

Crawled Scenario names

By default crawled Scenarios are named after the steps that are taken to produce them. You can rename these if you'd like to use a shorter or more meaningful name. This can be done on the App Info page, on the right-side dropdown for the relevant Scenario.


Steps to make the auto-crawler more effective

There are steps you can take to assist NimbleDroid's crawler in discovering Scenarios:

  • Add unique IDs and class names to clickable widgets.
  • Provide credentials if your app requires login. Check Scenario screenshots to confirm login has succeeded.
  • The crawler crawls widgets that are clickable or whose parents are clickable, make sure your important flows have a clear clicking structure

Limitations of the crawler:

  • The crawler does not do scroll and swipes at the moment.
  • The crawler does not support SMS or two-factor auth.

Disabling irrelevant Scenarios

The crawler may also identify Scenarios that you don't care to have measured, for example loading a Terms of Service page. You can disable Scenarios to prevent them from being profiled and from being shown in the interface. This will also reduce the overall time it takes to profile your app.


To disable a crawled Scenario, look for it on the App Info. The dropdown menu on the right side will allow you to disable it in future uploads. Disabling can always be undone via the App Setup page.


User-defined Scenarios

Usually customers have specific critical user flows that they want to profile that may not be covered by the auto-crawler.NimbleDroid supports custom user flows via the Espresso test framework. You can find more details in the Customization chapter.

NimbleDroid can also create and maintain custom Scenarios for you. When you begin your trial, let us know you are interested in this service.

Measurements and Profiling

NimbleDroid measures a number of important metrics for your app, as well as analyzing and diagnosing aspects of the underlying code.

Quantitative data

  • Speed

    Speed is defined as the clock time from when the user takes an action, like clicking or scrolling, until the app finishes responding to that action. For actions like Cold Startup, a speed of 2 seconds or less is recommended. The

  • Frames Per Second

  • Network bandwidth (up and down)

    The amount of network traffic observed

  • Max memory usage

    The maximum memory the app used at any point during the Scenario.

  • Disk bandwidth (read and write)

    The amount of data written and read to disk during the Scenario.

  • Method count

    Total method count for the app. This number is particularly critical in Android because of the 64K method threshold. We will also report method count breakdown by "library" (e.g. Crashlytics, OkHttp).

  • Download size

    Size of the APK file as if downloaded by a user from the Play store.

Other reported data

  • Memory leaks

    The presence of a memory leak, including the amount of memory leaked and the reference chain for the object in question.

    More information on memory leaks in Android can be found in our blog posts here and here

  • App crashes

    If an app crashed during a Scenario, NimbleDroid will report the crash along with the stack trace to assist with diagnosis.

  • Thread Timeline

  • Call stack

    This is a list of methods that are called during a Scenario, and the amount of time spent for each. The calling hierarchy of methods is also shown.

  • Network trace

    Performance and functional problems can often be attributed to network-related code. You can review network traffic requests, including the request URL and the timeline of the request. You can find this information for each Scenario in the left hand menu under Network Activity. networkTrace

Using the Site


Uploading using the site is done in one of two paths. The first is a wizard for uploading an app the first time. Once an app has been setup and run once, the user then sees a single page upload screen, which will allow them to quickly upload, or customize settings if needed.

Adding credentials for Auto-Login

If supplied with app credentials, NimbleDroid will attempt to use them to login before measuring Cold Startup and other Scenarios. NimbleDroid runs the app for auto-login before other measurements take place, and will quit the app once login is successful in order to not interfere. Apps that remain logged in after exiting will work with auto-login.

You will be prompted for credentials at upload time. You can also change or add persistent credentials on the App Setup/App Data page.

The interface provides fields for the two most common login fields, username and password. NimbleDroid will attempt a variety of algorithms to identify the relevant controls in the app.

Some apps require other fields for login, so it is possible to add arbitrary login fields and values, in the form of resource-id and value.


Ensuring your backend supports multiple logged-in devices

Sometimes apps have backend server restrictions that prevent a set of credentials from being used in more than one device at the same time. In this case auto-login will not work since NimbleDroid runs an app in parallel on multiple devices to provide quick results. You can update the restriction on your backend, or NimbleDroid provides a setting to force profiling to take place serially to ensure no simultaneous credential usage. This can be enabled on the App Setup/App Data page. Using this feature will greatly raise the latency for receiving results.

Choosing profiling environment options

You can choose to run your app profiles in one or more environments. At the time of this writing, the available environments are Android 4.4 and Android 5. Choosing two environments will generate two different profiles for each Scenario.

Choosing files to upload



This is your app APK, signed and ready to run.

Mapping file (optional)

For apps obfuscated with ProGuard, you will want to also upload the mapping file in order to get meaningful issue diagnosis. Otherwise a ProGuarded app will show methods like a.b in the diagnosis sections, making it difficult or impossible to match with real method names.

Instrumentation Test APK (optional)

This field is for an Espresso test APK, for the purpose of running profiles on user-created custom Scenarios. See the section below on custom Scenarios for more details.

Set up alerts


One of the key advantages to using NimbleDroid is the ability to receive a notification when something significant happens with a new build of your app. This can be a performance regression, a memory leak, or other significant changes.

You will first choose one or more channels for alerts (email or Slack), and then choose which conditions you wish to receive alerts for.



In addition to viewing results yourself, you may want to share results with other individuals. The sharing dialog will allow you to email others with a link that will give them access to all your uploads of the current app.

For Enterprise teams, contact us to find out about enhanced team management features.

Setting up Continuous Integration uploads

The most powerful way to use NimbleDroid is to add uploading to your CI build process. In this way NimbleDroid can look out for regressions and alert you immediately when they occur.

There are instructions on the last step for integrating with CI. Also see the section below, Continuous Integration

Reviewing results

App Overview Navigation

When you upload, you will be able to review your results at a high level and in detail. The navigation is broken into three primary sections:


  • App Info
  • Scenario Details
  • App Setup

The App Info page

The App Info page is the overview of an upload. It has metadata like time of upload, uploader, file name. It also lists Cold Startup, crawled Scenarios, and custom Espresso Scenarios. The list is updated as new Scenarios are discovered and profiled.

For each Scenario, measurements are listed, along with a small spark line to indicate provide an idea of trending. You can get more details on a Scenario by clicking its name, screenshots, or data.


Scenario Details page


scenarioDetailsNav Top nav for a Scenario lets you toggle between different uploads you've made, as well as between different run environments (e.g. Android 5) as well as change the current Scenario being viewed.


Side navigation will let you view the different aspects of the Scenario profile.


This will show you screenshots from the Scenario steps, top level stats about the Scenarios, as well as a list of slow methods.

Scenario Definition

This will show in detail each step that was taken in the app during the course of app state setup (getting to the final action) and the last screenshot of the profiled final action.

Speed Overview

Lists the slow methods detected, and shows a trending graph for the Scenario speed measured for different uploads. You can choose different number of points to display on the graph. Hovering on a graph point will reveal details about upload time, measurement value, upload information, and git hash if available. You can view trending graphs full screen by clicking the full screen control.


Method Details



This is similar to the Full Call Stack (see below), but restricted to a particular method that has been identified as a performance issue. You can tell what constituent code in the method may be adding to the issue.

CPU Time by SDK


This graph groups CPU time spent in methods that belong to different SDKS and libraries. You can use this to identify if certain third-party SDKs are disproportionally responsible for performance issues in your app.

Full Call Stack


The call stack gives visibility into which methods in your app are taking time to execute. The design lists calling methods higher than called methods in the stack. By navigating down the stack you can see subsequent calls, and navigating up you can see callers. There are some important notes about this display:

  • The call stack diagram does not represent a timeline, there is no chronology. Methods on the left do not get executed before methods on the right.
  • The ms figure you seeing next to a method may be for a single invocation of a method, but can also be a sum of all instances of invocations for that method. For example 100ms can mean 1 call that took 100ms, or 100 calls that took 1ms each. If you hover your mouse on a method you can get the exact invocation count.



The Timeline displays real time method trace over time per each thread. Unlike the Full Call Stack, which shows aggregated CPU time of methods, the Timeline shows when an individual method begins and ends in real time. the Timeline also displays thread information such as thread id, thread name, thread start time. and thread events.

A light gray line, the thread bar, in the Timeline indicates a running thread. A running thread can be paused and resumed by thread events such as wait and sleep, and this "paused" status is displayed as a dark gray section inside a running thread.

Each thread in the Timeline can be expanded by clicking the arrow button on the left side to display the call stack in real time.

Other options:

  • The timeline by default doesn't display minor threads which don't spend much time, and you can see minor threads by unchecking "Hide minor threads".
  • "Show methods" option enables displaying the method occupying the thread at each moment on the thread bar.
  • "Show events" displays more detailed information about thread events; when a thread creates another thread and when a tread wakes up another thread.

Vs Other Apps


This allows you to monitor how your Cold Startup time compares to other popular apps. To customize which apps are shown, go to , search for an app, and follow it to see it in the comparison.

Method Count

In addition to total APK method count, NimbleDroid will also break down the method count into individual libraries, so you can better understand which libraries and SDKs are contributing to your overall method count.


Managing Uploads

You can see a list of all Uploads for an up on the App Info/Uploads page. Uploads are listed reverse chronologically.

Archiving Uploads

If you have uploaded a version of the app that you have decided should not be included in trending and other results, you can archive that upload. This is done from the Uploads page, in the dropdown next to each version. Archiving an upload will make it seem to the rest of the site UI as if the version was never uploaded. Archiving can also be undone from the Uploads page.

Continuous Integration

To get the full power of NimbleDroid, we recommend automatically uploading apks as part of your build process.

  • Generate performance history for your development process
  • Save time manually uploading builds
  • Catch issues earlier in the release process

Getting an API key

You can get an API key on your account page at . The API key can also be reset on this page. After resetting, the old API key will no longer work.

Using the Gradle plugin

NimbleDroid provides a Gradle plugin to make it easy to integrate our service with CI builds. The full documentation for the Gradle plugin is located here .

Failing a build with the Gradle plugin

In addition to getting notified of issues by Alerts, you can fail a CI build that is using the Gradle plug-in under specific conditions like a Scenario getting slower, a new memory leak, or an app crash. Failing can be enabled in the App Setup section under Alerts. gradleFail

Uploading with the REST API

See the Advanced Usage section for information on uploading directly to the REST API.


If you have NimbleDroid integrated with your Continuous Integration server, we support email and Slack alerts that can inform you about slowdowns, memory leaks, or app crashes. You can configure Alerts for your app in the App Setup/Channels and App Setup/Alerts tabs.


An example Slack alert slackAlert


Cold Startup measurement exit point

Our profiler is capable of automatically analyzing your app’s cold startup to determine where startup completes. Although this handles many users’ needs, you might be interested in ending profiling before or after our default endpoint. We have provided a specialized API method to do just that. By placing the following statement somewhere in your app’s Cold Startup code path, you can explicitly define where the profiler should end profiling for the Cold Startup scenario:

Log.i(“NimbleDroidV1”, “ColdStartup.end”);


// Activity onCreate method in the app code
protected void onCreate(Bundle savedInstanceState ) {
    // ...misc app code
    // ...misc app code

    Log.i("NimbleDroidV1", "ColdStartup.end"); //stop profiling Cold Startup here

    // ...misc app code
    // ...misc app code


Custom Scenarios

NimbleDroid’s Espresso Scenarios feature allows you to specify custom user flows for profiling. You use standard Espresso instructions to control user actions in the app, and annotate your code with a few log statements to specify which parts of code should be profiled.

To use this feature NimbleDroid you will need the following:

  1. The compiled App APK “begin” and/or “end” Log statements in any relevant code to be profiled (optional)
  2. The compiled Espresso APK
  3. At least one log statement to indicate which test cases to run Log.i("NimbleDroidV1", "Scenario.profile");
  4. “begin” and/or “end” Log statements in any relevant code to be profiled (optional)

Additional Requirements:

  • A test case should not make an assumptions whether app is freshly installed as we run your app in a variety of different conditions
  • Scenarios should generally be 5s or less, with a max of 30s
  • Test classes should be written using the Android Testing Support Library and ActivityTestRule. ActivityInstrumentationTestCase2 is deprecated and is therefore not supported.
  • Your app’s build.gradle should be using the latest versions of the Espresso dependencies.

Our code relies on the app developer using a logcat message to register an Espresso test case for profiling and then subsequently using logcat messages to place at least one pair of bookends with IDs around relevant test or app code.

Registering a test case

It is mandatory to register each Espresso test case you intend to profile by placing the following logcat message inline exactly as seen here:

Log.i("NimbleDroidV1", "Scenario.profile");

Since customer Espresso APKs often have functional tests not intended for profiling by NimbleDroid, this is how we identify which test cases are intended for profiling. We will ignore any test case method that does not use the above statement as shown. It cannot be included via method call, only inline.

Bookending code

To generate a new Scenario the app developer needs to place a pair of logcat messages known as bookends with a matching bookend-id parameter anywhere along the code path of a registered test case. The pair of bookends must look like the following:

Log.i("NimbleDroidV1", "Scenario.begin bookend-id");
Log.i("NimbleDroidV1", "Scenario.end bookend-id");

Here, bookend-id is a string with length at most 127 characters. These logcat messages do not need to be placed inline and each one can be in either your app code or your test code as long as they will be executed along the code path of your registered test cases. The bookend-id for a matching pair of bookends must be identical or the Scenario will not be recognized.

Choosing where to add bookends

In order to get the most precise and relevant results, you should ideally define your Scenario bookends to encompass the smallest section of code as possible. This would be about 5 seconds of action or smaller. In general it is better to create two discrete bookend sets than to wrap a large amount of action inside a single bookend set.

For example, rather than creating one Scenario that encompasses entering text on a screen, clicking a submit button to a new screen, then clicking a checkbox and another submit button, you’re better off bookending each form submit separately. If you do choose to create large Scenarios, it must run within 30 seconds to avoid a timeout. This is necessary because of the enormous amount of data profiling generates and increased result variability with long Scenarios.


The source code for the example app APK and test APKs can be found here:

Example 1: begin and end in app code

The most precise profiling can be achieved by placing both ends of the Scenario log statements directly in the app code. We will create a Scenario with bookend-id clickActivity.


// Espresso test case method
public void appCodeTest() {
    Log.i("NimbleDroidV1", "Scenario.profile"); //this registration logcat must be placed inline exactly as seen here
    // ...



// MainActivity onClick method in the app code
public void onClick(View view ) {
    Log.i("NimbleDroidV1", "Scenario.begin clickActivity"); //start profiling clickActivity here
    // ...misc app code



// ShowTextActivity onCreate method in the app code
protected void onCreate(Bundle savedInstanceState ) {
    // ...misc app code

    Log.i("NimbleDroidV1", "Scenario.end clickActivity"); //stop profiling clickActivity here


Note: Although the bookend-id clickActivity was created for this example, it will actually generate a unique Scenario for every test case whose code path flows through this pair of bookends. In essence, multiple test cases can share a single bookend-id. This means you should expect to generate Scenarios with name appCodeTest (clickActivity) in addition to hybridTest (clickActivity) and espressoCodeTest (clickActivity).

Example 2: Bookends in test case

The easiest use case involves placing the logcat messages directly in your Espresso test case method. We will create a Scenario with bookend-id clickTest.


// Espresso test case method 
 public void espressoCodeTest() {
    Log.i("NimbleDroidV1", "Scenario.profile"); //this registration logcat must be placed inline exactly as seen here

    onView(withId(, closeSoftKeyboard());

    Log.i("NimbleDroidV1", "Scenario.begin clickTest"); //start profiling clickTest here


    Log.i("NimbleDroidV1", "Scenario.end clickTest"); //stop profiling clickTest here


Example 3: begin profile in test case, end in app code

The next use case is to place the begin log in your Espresso APK test case method and the corresponding end log in your app APK’s code. As long as the test case follows a flow that causes both log statements to be executed, the Scenario will be identified and profiled.

We can create a Scenario with bookend-id testToAppClick where the Scenario starts profiling in the Espresso test code and finishes profiling in the app code:


// Espresso test case method
public void hybridTest() {
    Log.i("NimbleDroidV1", "Scenario.profile"); //this registration logcat must be placed inline exactly as seen here

    onView(withId(, closeSoftKeyboard());

    Log.i("NimbleDroidV1", "Scenario.begin testToAppClick"); //start profiling testToAppClick here




// Activity onCreate method in the app code
protected void onCreate(Bundle savedInstanceState ) {
    // …misc app code

    Log.i("NimbleDroidV1", "Scenario.end testToAppClick"); //stop profiling testToAppClick here


Example 4: begin profile in app code, end in Espresso test code

The reverse is also possible. We will create a Scenario with bookend-id appToTestClick that starts profiling in the app code and stops profiling in the test code:


// Activity onClick method in the app code
public void onClick(View view ) {
    Log.i("NimbleDroidV1", "Scenario.begin appToTestClick"); //start profiling appToTestClick here
    // …misc app code


// Espresso test case method
public void hybridTest() {
    Log.i("NimbleDroidV1", "Scenario.profile"); //this registration logcat must be placed inline exactly as seen here


    Log.i("NimbleDroidV1", "Scenario.end appToTestClick"); //stop profiling appToTestClick here


Example 5: multiple bookend pairs per test case

Keep in mind that nesting and interleaving bookends is supported so use them however you’d like as long as the bookend-id’s are unique per test case. We will create three Scenarios with bookend-ids interleaveClick, clickActivity, and startActivity. This will generate three scenarios named nestedInterleaveTest (interleaveClick), nestedInterleaveTest (clickActivity), and nestedInterleaveTest (startActivity) respectively.


// Espresso test case method 
 public void nestedInterleaveTest() {
    Log.i("NimbleDroidV1", "Scenario.profile"); //this registration logcat must be placed inline exactly as seen here

    onView(withId(, closeSoftKeyboard());

    Log.i("NimbleDroidV1", "Scenario.begin interleaveClick"); //start profiling interleaveClick here




// MainActivity onClick method in the app code
public void onClick(View view ) {
    Log.i("NimbleDroidV1", "Scenario.begin clickActivity"); //start profiling clickActivity here
    // ...misc app code
    Log.i("NimbleDroidV1", "Scenario.end interleaveClick"); //stop profiling interleaveClick here
    final String text = mEditText.getText().toString();
    switch (view.getId()) {
        Intent intent = ShowTextActivity.newStartIntent(this, text);
        Log.i("NimbleDroidV1", "Scenario.begin startActivity"); //start profiling startActivity here


// ShowTextActivity onCreate method in the app code
protected void onCreate(Bundle savedInstanceState ) {

    Log.i("NimbleDroidV1", "Scenario.end startActivity"); //stop profiling startActivity here
    // ...misc app code

    Log.i("NimbleDroidV1", "Scenario.end clickActivity"); //stop profiling clickActivity here


Advanced Usage

Using the REST API


The base endpoint for the latest API version is


All authentication is done using HTTP Basic auth. Each NimbleDroid user has an API key (example format: bfca920e348a0c88af00b60e90ae7d4e) available on their Account page for use with API requests. The API key can be used in either the user or password fields for basic auth, authentication will work so as long as the key is in at least one of those fields.


You may want to upload using the REST API instead of the Gradle plugin or the web site for a variety of reasons, for example if you are not using Gradle in your CI process, or have a non-standard setup.

At its simplest, you can use a single HTTP POST to upload your APK for profiling.

Simple example (curl)

curl -F username="myappuser" -F password='123456' -F apk=@com.myapp.apk -v -u bfca920e348a0c88af00b60e90ae7d4e:

Advanced example (curl)

curl -F apk=@com.myapp.apk -F username="myappuser" -F password='123456' -F device_config="android5" -F commit="e912f09e819f0e81209e8fh2" -v -u bfca920e348a0c88af00b60e90ae7d4e:


Parameter Values Default Notes
username String A valid user account for using a customer's uploaded app. This is not a NimbleDroid credential but a customer's user account for testing with their backend.
password String A valid user account password for using a customer's uploaded app. This is not a NimbleDroid credential but a customer's user account for testing with their backend.
auto_login true false true (if username and password present OR app has saved credentials Allows explicit enabling/disabling of the auto login feature for Cold Startup and crawled Sceanarios. Auto login is not available for custom Espresso Scenarios.
auto_scenarios true false true Run the crawler to auto-discover Scenarios
test_apk File Espresso test apk for running custom Scenarios
mapping File ProGuard mapping file for translating obfuscated method names
commit String Git commit hash of uploaded APK, for labeling and reference
upload_label String Replaces default upload labeling algorithm with user-provided string
device_config Comma String android4 android5 android4 Comma list of one or more device configurations under which to run profiles. Listing more than one value will cause profiles to be run for each listed value e.g. "android4,android5"
serial_profiling true false false All profiles will be run serially and not in parallel, in order to prevent "simultaneous credential device use" security locks in customer's backend. Enabling this setting will greatly increase latency of results.
measurement_cap positive Int Allows a user to run profiling on an upload while lowering the number of measurement iterations. This can be used in the case where the uploader wants to just do a sanity check to make sure an app will profile successfully, without the need for a stable speed measurement. Fastest results will be available by setting this to 1.