---
title: "Profiling"
description: "Learn how to enable profiling in your app using the Sentry Android SDK if it is not already set up."
url: https://docs.sentry.io/platforms/android/profiling/
---

# Set Up Android Profiling

With [profiling](https://docs.sentry.io/product/profiling.md), Sentry tracks your software's performance by sampling your program's call stack in a variety of environments. This feature collects function-level information about your code and enables you to fine-tune your program's performance. [Sentry's profiler](https://sentry.io/for/profiling/) captures function calls and their exact locations, aggregates them, and shows you the most common code paths of your program. This highlights areas you could optimize to help increase both the performance of your code and increase user satisfaction, as well as drive down costs.

Starting with SDK version `8.51.0`, Sentry's Android UI Profiling is built on top of the Android [ProfilingManager APIs](https://developer.android.com/reference/android/os/ProfilingManager), available on Android 15 (API level 35), which capture stack samples as [Perfetto](https://perfetto.dev/) traces. This is the recommended way to profile your Android app.

##### Looking for the old profiler?

On devices running below Android 15, the SDK automatically falls back to the legacy profiler, which samples threads using the Android runtime's `tracer`. That implementation, along with the transaction-based profiler, is now considered legacy. See [Legacy Profiling](https://docs.sentry.io/platforms/android/profiling/legacy.md) for details, including how to disable it.

## [Prerequisites](https://docs.sentry.io/platforms/android/profiling.md#prerequisites)

UI Profiling is available starting in SDK version `8.7.0`. On **Android 15 (API level 35) or higher**, it uses the ProfilingManager (Perfetto) backend, available starting in SDK version `8.51.0`.

On devices running below Android 15, the SDK automatically falls back to the [legacy profiler](https://docs.sentry.io/platforms/android/profiling/legacy.md). You can turn this fallback off, and disable profiling on those devices entirely, with the [`enableLegacyProfiling`](https://docs.sentry.io/platforms/android/configuration/options.md#enableLegacyProfiling) option.

## [Enabling UI Profiling](https://docs.sentry.io/platforms/android/profiling.md#enabling-ui-profiling)

To enable UI Profiling, set a `profileSessionSampleRate` and choose a profile lifecycle. The SDK automatically uses the ProfilingManager (Perfetto) backend on Android 15 (API level 35) and higher, and the legacy profiler on older devices.

UI Profiling supports two modes: `manual` and `trace`. These modes are mutually exclusive and cannot be used at the same time.

In `manual` mode, the profiling data collection can be managed via calls to `Sentry.profiler.startProfiler` and `Sentry.profiler.stopProfiler`. You are entirely in control of when the profiler runs.

In `trace` mode, the profiler manages its own start and stop calls, which are based on spans: the profiler continues to run while there is at least one active sampled span, and stops when there are no active sampled spans.

The Sentry SDK supports an additional `profileSessionSampleRate` that will enable or disable profiling for the entire [session](https://docs.sentry.io/platforms/android/configuration/releases.md#sessions). This sampling decision is evaluated only once per session.

### [Enabling Trace Lifecycle UI Profiling](https://docs.sentry.io/platforms/android/profiling.md#enabling-trace-lifecycle-ui-profiling)

To enable trace profiling, set the lifecycle to `trace`. Trace profiling requires tracing to be enabled.

Check out the [tracing setup documentation](https://docs.sentry.io/platforms/android/tracing.md) for more detailed information on how to configure sampling. Setting the sample rate to 1.0 means all transactions will be captured.

By default, some transactions will be created automatically for common operations like loading an activity and app startup.

```xml
<application>
  <meta-data
    android:name="io.sentry.dsn"
    android:value="https://<key>@o<orgId>.ingest.sentry.io/<projectId>"
  />
  <!-- Enable tracing, needed for profiling `trace` mode, adjust in production env -->
  <meta-data
    android:name="io.sentry.traces.sample-rate"
    android:value="1.0"
  />
  <!-- Enable UI profiling, adjust in production env. This is evaluated only once per session -->
  <meta-data
    android:name="io.sentry.traces.profiling.session-sample-rate"
    android:value="1.0"
  />
  <meta-data
    android:name="io.sentry.traces.profiling.lifecycle"
    android:value="trace"
  />
</application>
```

*Other available variations of the above snippet: java, kotlin*

### [Enabling Manual Lifecycle UI Profiling](https://docs.sentry.io/platforms/android/profiling.md#enabling-manual-lifecycle-ui-profiling)

To enable manual profiling, set the lifecycle to `manual`. Manual profiling does not require tracing to be enabled.

```xml
<application>
  <meta-data
    android:name="io.sentry.dsn"
    android:value="https://<key>@o<orgId>.ingest.sentry.io/<projectId>"
  />
  <!-- Enable UI profiling, adjust in production env. This is evaluated only once per session -->
  <meta-data
    android:name="io.sentry.traces.profiling.session-sample-rate"
    android:value="1.0"
  />
  <meta-data
    android:name="io.sentry.traces.profiling.lifecycle"
    android:value="manual"
  />
</application>
```

*Other available variations of the above snippet: java, kotlin*

## [Limitations](https://docs.sentry.io/platforms/android/profiling.md#limitations)

On Android 15 (API level 35) and higher, UI Profiling relies on the Android ProfilingManager, so the following limitations apply:

* **Older devices use the legacy profiler.** On devices below Android 15, the SDK automatically falls back to [Legacy Profiling](https://docs.sentry.io/platforms/android/profiling/legacy.md), which has different characteristics. You can disable this fallback with the [`enableLegacyProfiling`](https://docs.sentry.io/platforms/android/configuration/options.md#enableLegacyProfiling) option.
* **App start profiling is not supported.** The `startProfilerOnAppStart` option has no effect with the ProfilingManager (Perfetto) backend. App start profiling is only supported by the legacy profiler used on devices below Android 15. To learn more, see [Legacy Profiling](https://docs.sentry.io/platforms/android/profiling/legacy.md).
* **Profiling requests are rate limited and not guaranteed to be fulfilled.** Apart from the SDK sampling rate, the Android Framework also restricts profiling, so not every request results in a profile. These limits are outside the SDK's control. To learn more, see [When Android Rejects Profiling Requests](https://docs.sentry.io/platforms/android/profiling.md#when-android-rejects-profiling-requests).

## [When Android Rejects Profiling Requests](https://docs.sentry.io/platforms/android/profiling.md#when-android-rejects-profiling-requests)

Whether a session gets profiled works like a funnel. First, the SDK decides whether to request profiling for the session, based on your `profileSessionSampleRate`. Then, the ProfilingManager applies its own limits and decides whether to record each request the SDK sends. When Android rejects a request, no profile is recorded for that time window, and the transactions and spans running during that window aren't linked to a profile.

The SDK records profiles in chunks of up to 60 seconds, and each chunk is a separate ProfilingManager request. In `trace` mode, the profiler also sends a new request every time it restarts after all sampled spans have finished.

Android rejects a profiling request in the following cases:

* **The app reached its profiling limit.** Each app gets a limited profiling budget per hour, per day, and per week. Once the app uses up any of these, Android rejects further requests until that period resets (`ERROR_FAILED_RATE_LIMIT_PROCESS`).
* **The device reached its system-wide profiling limit.** All apps on a device share a global budget with the same hourly, daily, and weekly periods. Profiling by other apps can use up this budget, even if your app hasn't reached its own limit (`ERROR_FAILED_RATE_LIMIT_SYSTEM`).
* **Profiling is already in progress.** Android rejects a request while another profiling session is running (`ERROR_FAILED_PROFILING_IN_PROGRESS`).

Android doesn't publish the exact budgets, and they may change between Android versions. To learn more, see the Android [profiling limitations](https://developer.android.com/topic/performance/tracing/profiling-manager/will-my-profile-always-be-collected#how-rate-limiting-works) documentation. When [debug mode](https://docs.sentry.io/platforms/android/configuration/options.md#debug) is enabled, the SDK logs the error code of every rejected request.

##### Disabling Rate Limiting for Local Testing

When testing locally, you can disable the Android Framework restrictions with the following shell command:

```bash
adb shell device_config put profiling_testing rate_limiter.disabled true
```

### [Which Parts of Your App Get Profiled](https://docs.sentry.io/platforms/android/profiling.md#which-parts-of-your-app-get-profiled)

Requests sent early in a rate-limit period are the most likely to be recorded, while later ones are more likely to be rejected. As a result, the app start and first screens (right after `Sentry.init()`) are usually profiled more often than parts of your app that users reach later in a session. In long sessions, later parts of your app may not be profiled at all once the app has used up its budget.

### [Profiling Specific Parts of Your App](https://docs.sentry.io/platforms/android/profiling.md#profiling-specific-parts-of-your-app)

To get profiles for a specific flow, such as a checkout or a heavy screen, use the [`manual` lifecycle](https://docs.sentry.io/platforms/android/profiling.md#enabling-manual-lifecycle-ui-profiling). Call `Sentry.startProfiler()` when the flow starts and `Sentry.stopProfiler()` when it ends. This spends the limited budget on the code you want to investigate, instead of on everything that runs while a sampled span is active.

Keep manually profiled sections short, and always call `Sentry.stopProfiler()` when the flow is done. A profiler that keeps running sends a new request every 60 seconds, which uses up the app's budget quickly.

## Pages in this section

- [Legacy Profiling](https://docs.sentry.io/platforms/android/profiling/legacy.md)
- [Troubleshooting](https://docs.sentry.io/platforms/android/profiling/troubleshooting.md)
