> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userpilot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Auto Capture

> Configure auto capture for the Userpilot Android SDK

Configure automatic screen and interaction capture for Android View and Compose applications using the Userpilot Gradle Plugin and Userpilot SDK.

The Userpilot Android SDK can automatically capture Android View and Compose screens and interactions, enabling analytics and engagement without manual screen and event tracking. Use this guide for SDK-side configuration; build-time instrumentation is configured in the app module with the Userpilot Gradle Plugin.

***

## SDK Configuration

Auto capture behavior is configured through `UserpilotConfig` during SDK initialization.

```kotlin theme={null}
val userpilot = Userpilot(context, "<APP_TOKEN>") {
    enableScreenAutoCapture = true
    enableInteractionAutoCapture = true
    enableInteractionTextCapture = true
    enableInteractionAccessibilityLabelCapture = true
    enableInteractionValueCapture = false
    uiFramework = UiFramework.Compose // or UiFramework.View
}
```

| **Option**                                   | **Type**       | **Default** | **Description**                                                                                                                                                                                                                                                                                          |
| -------------------------------------------- | -------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enableScreenAutoCapture`                    | `Boolean`      | `false`     | Enables automatic screen tracking. View apps use Activity/Fragment lifecycle tracking. Compose apps should use `UserpilotComposeNavigationTracker(...)` for navigation-aware screen capture.                                                                                                             |
| `enableInteractionAutoCapture`               | `Boolean`      | `false`     | Enables automatic interaction capture. Requires Gradle plugin instrumentation for the UI framework being captured.                                                                                                                                                                                       |
| `enableInteractionTextCapture`               | `Boolean`      | `true`      | If `false`, user-visible text is redacted from captured interaction payloads.                                                                                                                                                                                                                            |
| `enableInteractionAccessibilityLabelCapture` | `Boolean`      | `true`      | If `false`, accessibility labels/content descriptions are not captured.                                                                                                                                                                                                                                  |
| `enableInteractionValueCapture`              | `Boolean`      | `false`     | Enables value payload capture: `is_checked`, selected date/time, slider/seekbar values, and on spinner / ListPopupWindow / Compose collections both `selected_index` and `selected_value`. `AdapterView` list item clicks always include `selected_index`; `selected_value` only when this flag is true. |
| `uiFramework`                                | `UiFramework?` | `null`      | Optional framework hint: `UiFramework.View` or `UiFramework.Compose`.                                                                                                                                                                                                                                    |

<Tip>
  **Note**

  Auto Capture automatically tracks screen views and ignores manually sent `screen` events while enabled.

  If you are migrating from manual screen tracking, please review the migration guide [here](https://docs.userpilot.com/data-events/mobile-screen-tracking/mobile-screen-auto-capture#important).
</Tip>

***

## Gradle Plugin Configuration

Auto capture also needs build-time instrumentation in the app module.

The plugin is distributed through Maven Central. Add the Userpilot Gradle plugin to your app module `build.gradle` and replace `<latest_version>` with the [latest release version](https://central.sonatype.com/artifact/com.userpilot.plugin/com.userpilot.plugin.gradle.plugin).

```kotlin theme={null}
plugins {
    id("com.userpilot.plugin") version "<latest_version>"
}

userpilot {
    enabled.set(true)
    viewEnabled.set(true)
    composeEnabled.set(true)
    composeHierarchy {
        row.set(true)
        column.set(false)
        box.set(false)
        card.set(true)
        surface.set(true)
    }
    logging.set(false)
}
```

| **Option**                 | **Default** | **Description**                                               |
| -------------------------- | ----------- | ------------------------------------------------------------- |
| `enabled`                  | `true`      | Master switch for plugin instrumentation.                     |
| `viewEnabled`              | `false`     | Instruments Android View call sites.                          |
| `composeEnabled`           | `false`     | Instruments Compose call sites.                               |
| `composeHierarchy.row`     | `true`      | Adds inline `Row` nodes to Compose hierarchy paths.           |
| `composeHierarchy.column`  | `false`     | Adds inline `Column` nodes to Compose hierarchy paths.        |
| `composeHierarchy.box`     | `false`     | Adds inline `Box` nodes to Compose hierarchy paths.           |
| `composeHierarchy.card`    | `true`      | Adds Material 3 card-family nodes to Compose hierarchy paths. |
| `composeHierarchy.surface` | `true`      | Adds Material 3 `Surface` nodes to Compose hierarchy paths.   |
| `logging`                  | `false`     | Enables plugin diagnostic logging during builds.              |

Enable `viewEnabled`, `composeEnabled`, or both depending on the UI frameworks used by the app.

***

## Android View Capture

View screen capture is handled by Activity and Fragment lifecycle callbacks. Internal Userpilot surfaces are excluded.

### View Screen Tracking

Activities are tracked from lifecycle resume events using the manifest label when available, otherwise the Activity class name. Fragments are tracked by class name, except dialog/bottom-sheet fragments and fragments marked with `userpilotIgnoreScreen`.

Use `userpilotIgnoreScreen` when a View `Activity` or `Fragment` is auxiliary content that should not emit its own automatic screen-view event. Typical cases: a host activity that delegates the visible screen to a child, or a fragment composed as one slot inside a split-pane / tabbed / nested-fragment layout where the parent already identifies the screen.

```kotlin theme={null}
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.userpilot.autoCapture.view.apis.userpilotIgnoreScreen

class DetailsHostActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        userpilotIgnoreScreen = true
    }
}

class DetailsPaneFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        userpilotIgnoreScreen = true
    }
}
```

Captured View interactions include:

* Clicks and long clicks
* Clickable spans
* Dialog and bottom-sheet presentation
* Dialog button clicks
* Adapter item clicks and selections
* Text changes
* CompoundButton, SeekBar, Slider, RangeSlider, date picker, and time picker changes

### Improving Android Autocapture

| **Interaction**              | **Supported Types**                                                                                  | **Required Listener**                                                                                               |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| View Click                   | All subclasses of `View`.                                                                            | `View.OnClickListener` must be set to the target view.                                                              |
| In-Text Link Click           | `TextView` and its subclasses.                                                                       | In-text link must be generated using a `ClickableSpan` that overrides the `onClick` method.                         |
| Dialog Button Click          | All dialog types that implement `DialogInterface` (e.g. `AlertDialog`).                              | `DialogInterface.OnClickListener` must be set to the target dialog button.                                          |
| Dialog List Item Click       | Platform native and AndroidX implementations of `AlertDialog`.                                       | Must attach a `DialogInterface.OnClickListener` to the target dialog's list using `AlertDialog.Builder.setItems()`. |
| List Item Click              | All subclasses of `AdapterView`.                                                                     | `AdapterView.OnItemClickListener` must be set to the target list.                                                   |
| Spinner Item Selected        | All subclasses of `AdapterView`, but works best with `Spinner` and its subclasses.                   | `AdapterView.OnItemSelectedListener` must be set to the target view.                                                |
| Toggle Control Value Changed | All subclasses of `CompoundButton` (e.g. `ToggleButton`, `CheckBox`, `Switch`) except `RadioButton`. | `CompoundButton.OnCheckedChangeListener` must be set to the target view.                                            |
| Radio Group Value Changed    | `RadioGroup` and its subclasses.                                                                     | `RadioGroup.OnCheckedChangeListener` must be set to the target view.                                                |
| Text Input Value Changed     | `EditText` and its subclasses.                                                                       | `TextWatcher` must be set to the input field using `TextView.addTextChangedListener()`.                             |
| Date Value Changed           | `DatePickerDialog`                                                                                   | `DatePickerDialog.OnDateSetListener` must be set to the target dialog.                                              |
| Time Value Changed           | `TimePickerDialog`                                                                                   | `TimePickerDialog.OnTimeSetListener` must be set to the target dialog.                                              |
| SeekBar Value Changed        | `SeekBar`                                                                                            | `SeekBar.OnSeekBarChangeListener` must be set to the target view.                                                   |
| Slider Value Changed         | Material component library implementations of `Slider` and `RangeSlider`.                            | No required listeners needed for value change capture. The SDK attaches its own listener.                           |

### View Privacy Helpers

Use these helpers for View-specific privacy and payload control:

* `Userpilot.redactText(view)`
* `Userpilot.ignoreInteractions(view)`
* `Userpilot.overrideTargetText(view, title)`
* `Userpilot.clearTargetTextOverride(view)`
* `Userpilot.enableCompoundButtonValueChangeCapture(compoundButton)`
* `Userpilot.disableCompoundButtonValueChangeCapture(compoundButton)`
* `Userpilot.setShouldCaptureValueOnInteractionChangeEvents(shouldCaptureValue)`

XML tags are also supported:

```xml theme={null}
android:tag="userpilotIgnoreInteractions"
android:tag="userpilotRedactText"
```

***

## Compose Capture

The following Compose interactions are supported:

* Clickable and combined-clickable taps
* Toggleable, checkbox, switch, radio button, and icon toggle changes
* Selectable items, tabs, navigation items, chips, and dropdown menu items
* Text field changes, debounced per field holder
* Slider, date picker, and time picker changes
* Dialog, alert dialog, modal bottom sheet, and exposed dropdown presentation

### Limitations

* **Material2 Compose components are intentionally not instrumented.** Use Material3 — the wrappers are tuned for Material3 **1.3.+** and are expected to work with Material3 **1.1.0+**. Apps pinned to Material3 below 1.1.0 may see missing or misbehaving Compose instrumentation. Plain foundation controls (`BasicTextField` via the `String` and `TextFieldValue` overloads) are covered regardless of Material version.
* **Compose screen tracking is opt-in.** Activities and Fragments are tracked automatically when `enableScreenAutoCapture = true` via the same Activity / Fragment lifecycle pipeline that View auto capture uses. Compose-driven screens require one of the explicit helpers: `UserpilotComposeNavigationTracker(navController)`, `UserpilotComposeNavigationTracker(backStack = ...)`, or `Modifier.userpilotScreen("title")` (see [Compose Screen Tracking](#compose-screen-tracking)). There is no automatic route-name detection — pick one of these wrappers per nav graph or per screen.
* **Custom-built Compose components are not auto-instrumented.** The Gradle plugin rewrites known foundation / Material3 call sites (`Modifier.clickable`, `Modifier.toggleable`, `Button`, `Checkbox`, `ModalBottomSheet`, etc.). A composable that implements its own interaction handling without going through those primitives won't be captured. Use the supported building blocks to inherit auto capture for free.

### Compose Screen Tracking

<CodeGroup>
  ```kotlin Navigation 2 theme={null}
  @Composable
  fun App() {
      val navController = rememberNavController()

      UserpilotComposeNavigationTracker(
          navController = navController,
          screenNameResolver = { route -> route.substringAfterLast(".") },
          screenFilter = { route -> !route.startsWith("debug") },
      )
  }
  ```

  ```kotlin Navigation 3 theme={null}
  sealed class Screen {
      data object Home : Screen()
      data class Product(val id: Int) : Screen()
      data object Debug : Screen()
  }

  @Composable
  fun App() {
      val backStack = remember { mutableStateListOf<Screen>(Screen.Home) }

      UserpilotComposeNavigationTracker(
          backStack = backStack,
          screenNameResolver = { key ->
              when (key) {
                  Screen.Home -> "Home"
                  is Screen.Product -> "Product ${key.id}"
                  Screen.Debug -> "Debug"
              }
          },
          screenFilter = { key -> key !is Screen.Debug },
      )
  }
  ```
</CodeGroup>

For a single Compose screen outside of a nav graph (for example, a one-off screen launched from XML, a settings overlay, or any Composable hosted directly in an Activity), attach `Modifier.userpilotScreen(...)` to the screen's root container. It fires a `screen(...)` event every time the host lifecycle reaches `RESUMED`, so the report is aligned with the user actually seeing the screen rather than with composition entry:

```kotlin theme={null}
@Composable
fun ProfileScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .userpilotScreen(screenTitle = "Profile"),
    ) {
        // screen content
    }
}
```

### Compose Privacy Helpers

Use subtree-scoped helpers for broad privacy rules. The default is to opt out / redact everything in the wrapped subtree:

```kotlin theme={null}
UserpilotIgnoreInteractions {
    SensitiveSettings()
}

UserpilotRedactText {
    ProfileForm()
}
```

Both helpers also accept an explicit boolean so you can carve out an exception inside a larger opt-out — for example, re-enable a specific section while everything around it is ignored:

```kotlin theme={null}
UserpilotIgnoreInteractions {
    SensitiveSettings()

    UserpilotIgnoreInteractions(ignore = false) {
        // captured normally, even though the outer scope opts out
        FeedbackPrompt()
    }
}
```

Use modifier-level helpers for one element. Unlike the subtree composables, the effect does **not** propagate into the element's `content` slot, and an explicit modifier value wins over any inherited scope:

```kotlin theme={null}
Button(
    modifier = Modifier.userpilotIgnoreInteractions(),
    onClick = onClick,
) {
    Text("Internal action")
}

TextField(
    modifier = Modifier.userpilotRedactText(),
    value = value,
    onValueChange = onValueChange,
)
```

Both modifier helpers accept the same `ignore: Boolean = true` / `redact: Boolean = true` parameter, so you can use them to undo an inherited scope at the element level:

```kotlin theme={null}
UserpilotRedactText {
    ProfileForm()
    // The job title is product copy, not PII — keep it captured.
    Text(
        text = "Senior Engineer",
        modifier = Modifier.userpilotRedactText(redact = false),
    )
}
```

***

## Runtime Controls

These APIs stop or resume auto capture:

```kotlin theme={null}
Userpilot.stopAutoCapture()

// ... sensitive flow ...

Userpilot.resumeAutoCapture()
```

While stopped, no screen or interaction events are recorded regardless of other configuration. This is a global toggle that overrides per-view settings.

<Frame>
  [**For any questions or concerns please reach out to support@userpilot.com**](mailto:support@userpilot.com)
</Frame>
